/******/ (() => { // webpackBootstrap
/******/ 	var __webpack_modules__ = ({

/***/ 352:
/***/ ((module) => {

"use strict";
/**
 * DON'T EDIT THIS FILE
 * Module was generated automatically by ajv precompiler 
 * See '/tools/bundle/genValidators.js'
 */


module.exports = validate10;
module.exports["default"] = validate10;
const schema11 = {
  "$id": "settings.json",
  "type": "object",
  "properties": {
    "protocol-version": {
      "type": "string"
    },
    "general-settings": {
      "type": "object",
      "properties": {
        "app-language": {
          "type": "string"
        },
        "allow-acceptable-ads": {
          "type": "boolean"
        },
        "show-blocked-ads-count": {
          "type": "boolean"
        },
        "autodetect-filters": {
          "type": "boolean"
        },
        "safebrowsing-enabled": {
          "type": "boolean"
        },
        "filters-update-period": {
          "type": "integer"
        },
        "appearance-theme": {
          "type": "string"
        }
      },
      "required": ["allow-acceptable-ads", "show-blocked-ads-count", "autodetect-filters", "safebrowsing-enabled", "filters-update-period"]
    },
    "extension-specific-settings": {
      "type": "object",
      "properties": {
        "use-optimized-filters": {
          "type": "boolean"
        },
        "collect-hits-count": {
          "type": "boolean"
        },
        "show-context-menu": {
          "type": "boolean"
        },
        "show-info-about-adguard": {
          "type": "boolean"
        },
        "show-app-updated-info": {
          "type": "boolean"
        }
      },
      "required": ["use-optimized-filters", "collect-hits-count", "show-context-menu", "show-info-about-adguard", "show-app-updated-info"]
    },
    "filters": {
      "type": "object",
      "properties": {
        "enabled-groups": {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        "enabled-filters": {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        "custom-filters": {
          "type": "array",
          "items": {}
        },
        "user-filter": {
          "type": "object",
          "properties": {
            "rules": {
              "type": "string"
            },
            "disabled-rules": {
              "type": "string"
            },
            "enabled": {
              "type": "boolean"
            }
          },
          "required": ["rules", "disabled-rules"]
        },
        "whitelist": {
          "type": "object",
          "properties": {
            "inverted": {
              "type": "boolean"
            },
            "domains": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "inverted-domains": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "enabled": {
              "type": "boolean"
            }
          },
          "required": ["inverted", "domains", "inverted-domains"]
        }
      },
      "required": ["enabled-groups", "enabled-filters", "custom-filters", "user-filter", "whitelist"]
    },
    "stealth": {
      "type": "object",
      "properties": {
        "stealth_disable_stealth_mode": {
          "type": "boolean"
        },
        "stealth-hide-referrer": {
          "type": "boolean"
        },
        "stealth-hide-search-queries": {
          "type": "boolean"
        },
        "stealth-send-do-not-track": {
          "type": "boolean"
        },
        "stealth-block-webrtc": {
          "type": "boolean"
        },
        "stealth-block-third-party-cookies": {
          "type": "boolean"
        },
        "stealth-block-first-party-cookies": {
          "type": "boolean"
        },
        "block-known-trackers": {
          "type": "boolean"
        },
        "strip-tracking-parameters": {
          "type": "boolean"
        }
      },
      "required": ["stealth_disable_stealth_mode", "stealth-hide-referrer", "stealth-hide-search-queries", "stealth-send-do-not-track", "stealth-block-webrtc", "stealth-block-third-party-cookies", "stealth-block-first-party-cookies", "strip-tracking-parameters"]
    }
  },
  "required": ["protocol-version", "general-settings", "extension-specific-settings", "filters"]
};

function validate10(data, {
  instancePath = "",
  parentData,
  parentDataProperty,
  rootData = data
} = {}) {
  /*# sourceURL="settings.json" */
  ;
  let vErrors = null;
  let errors = 0;

  if (errors === 0) {
    if (data && typeof data == "object" && !Array.isArray(data)) {
      let missing0;

      if (data["protocol-version"] === undefined && (missing0 = "protocol-version") || data["general-settings"] === undefined && (missing0 = "general-settings") || data["extension-specific-settings"] === undefined && (missing0 = "extension-specific-settings") || data.filters === undefined && (missing0 = "filters")) {
        validate10.errors = [{
          instancePath,
          schemaPath: "#/required",
          keyword: "required",
          params: {
            missingProperty: missing0
          },
          message: "must have required property '" + missing0 + "'"
        }];
        return false;
      } else {
        if (data["protocol-version"] !== undefined) {
          const _errs1 = errors;

          if (typeof data["protocol-version"] !== "string") {
            validate10.errors = [{
              instancePath: instancePath + "/protocol-version",
              schemaPath: "#/properties/protocol-version/type",
              keyword: "type",
              params: {
                type: "string"
              },
              message: "must be string"
            }];
            return false;
          }

          var valid0 = _errs1 === errors;
        } else {
          var valid0 = true;
        }

        if (valid0) {
          if (data["general-settings"] !== undefined) {
            let data1 = data["general-settings"];
            const _errs3 = errors;

            if (errors === _errs3) {
              if (data1 && typeof data1 == "object" && !Array.isArray(data1)) {
                let missing1;

                if (data1["allow-acceptable-ads"] === undefined && (missing1 = "allow-acceptable-ads") || data1["show-blocked-ads-count"] === undefined && (missing1 = "show-blocked-ads-count") || data1["autodetect-filters"] === undefined && (missing1 = "autodetect-filters") || data1["safebrowsing-enabled"] === undefined && (missing1 = "safebrowsing-enabled") || data1["filters-update-period"] === undefined && (missing1 = "filters-update-period")) {
                  validate10.errors = [{
                    instancePath: instancePath + "/general-settings",
                    schemaPath: "#/properties/general-settings/required",
                    keyword: "required",
                    params: {
                      missingProperty: missing1
                    },
                    message: "must have required property '" + missing1 + "'"
                  }];
                  return false;
                } else {
                  if (data1["app-language"] !== undefined) {
                    const _errs5 = errors;

                    if (typeof data1["app-language"] !== "string") {
                      validate10.errors = [{
                        instancePath: instancePath + "/general-settings/app-language",
                        schemaPath: "#/properties/general-settings/properties/app-language/type",
                        keyword: "type",
                        params: {
                          type: "string"
                        },
                        message: "must be string"
                      }];
                      return false;
                    }

                    var valid1 = _errs5 === errors;
                  } else {
                    var valid1 = true;
                  }

                  if (valid1) {
                    if (data1["allow-acceptable-ads"] !== undefined) {
                      const _errs7 = errors;

                      if (typeof data1["allow-acceptable-ads"] !== "boolean") {
                        validate10.errors = [{
                          instancePath: instancePath + "/general-settings/allow-acceptable-ads",
                          schemaPath: "#/properties/general-settings/properties/allow-acceptable-ads/type",
                          keyword: "type",
                          params: {
                            type: "boolean"
                          },
                          message: "must be boolean"
                        }];
                        return false;
                      }

                      var valid1 = _errs7 === errors;
                    } else {
                      var valid1 = true;
                    }

                    if (valid1) {
                      if (data1["show-blocked-ads-count"] !== undefined) {
                        const _errs9 = errors;

                        if (typeof data1["show-blocked-ads-count"] !== "boolean") {
                          validate10.errors = [{
                            instancePath: instancePath + "/general-settings/show-blocked-ads-count",
                            schemaPath: "#/properties/general-settings/properties/show-blocked-ads-count/type",
                            keyword: "type",
                            params: {
                              type: "boolean"
                            },
                            message: "must be boolean"
                          }];
                          return false;
                        }

                        var valid1 = _errs9 === errors;
                      } else {
                        var valid1 = true;
                      }

                      if (valid1) {
                        if (data1["autodetect-filters"] !== undefined) {
                          const _errs11 = errors;

                          if (typeof data1["autodetect-filters"] !== "boolean") {
                            validate10.errors = [{
                              instancePath: instancePath + "/general-settings/autodetect-filters",
                              schemaPath: "#/properties/general-settings/properties/autodetect-filters/type",
                              keyword: "type",
                              params: {
                                type: "boolean"
                              },
                              message: "must be boolean"
                            }];
                            return false;
                          }

                          var valid1 = _errs11 === errors;
                        } else {
                          var valid1 = true;
                        }

                        if (valid1) {
                          if (data1["safebrowsing-enabled"] !== undefined) {
                            const _errs13 = errors;

                            if (typeof data1["safebrowsing-enabled"] !== "boolean") {
                              validate10.errors = [{
                                instancePath: instancePath + "/general-settings/safebrowsing-enabled",
                                schemaPath: "#/properties/general-settings/properties/safebrowsing-enabled/type",
                                keyword: "type",
                                params: {
                                  type: "boolean"
                                },
                                message: "must be boolean"
                              }];
                              return false;
                            }

                            var valid1 = _errs13 === errors;
                          } else {
                            var valid1 = true;
                          }

                          if (valid1) {
                            if (data1["filters-update-period"] !== undefined) {
                              let data7 = data1["filters-update-period"];
                              const _errs15 = errors;

                              if (!(typeof data7 == "number" && !(data7 % 1) && !isNaN(data7) && isFinite(data7))) {
                                validate10.errors = [{
                                  instancePath: instancePath + "/general-settings/filters-update-period",
                                  schemaPath: "#/properties/general-settings/properties/filters-update-period/type",
                                  keyword: "type",
                                  params: {
                                    type: "integer"
                                  },
                                  message: "must be integer"
                                }];
                                return false;
                              }

                              var valid1 = _errs15 === errors;
                            } else {
                              var valid1 = true;
                            }

                            if (valid1) {
                              if (data1["appearance-theme"] !== undefined) {
                                const _errs17 = errors;

                                if (typeof data1["appearance-theme"] !== "string") {
                                  validate10.errors = [{
                                    instancePath: instancePath + "/general-settings/appearance-theme",
                                    schemaPath: "#/properties/general-settings/properties/appearance-theme/type",
                                    keyword: "type",
                                    params: {
                                      type: "string"
                                    },
                                    message: "must be string"
                                  }];
                                  return false;
                                }

                                var valid1 = _errs17 === errors;
                              } else {
                                var valid1 = true;
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              } else {
                validate10.errors = [{
                  instancePath: instancePath + "/general-settings",
                  schemaPath: "#/properties/general-settings/type",
                  keyword: "type",
                  params: {
                    type: "object"
                  },
                  message: "must be object"
                }];
                return false;
              }
            }

            var valid0 = _errs3 === errors;
          } else {
            var valid0 = true;
          }

          if (valid0) {
            if (data["extension-specific-settings"] !== undefined) {
              let data9 = data["extension-specific-settings"];
              const _errs19 = errors;

              if (errors === _errs19) {
                if (data9 && typeof data9 == "object" && !Array.isArray(data9)) {
                  let missing2;

                  if (data9["use-optimized-filters"] === undefined && (missing2 = "use-optimized-filters") || data9["collect-hits-count"] === undefined && (missing2 = "collect-hits-count") || data9["show-context-menu"] === undefined && (missing2 = "show-context-menu") || data9["show-info-about-adguard"] === undefined && (missing2 = "show-info-about-adguard") || data9["show-app-updated-info"] === undefined && (missing2 = "show-app-updated-info")) {
                    validate10.errors = [{
                      instancePath: instancePath + "/extension-specific-settings",
                      schemaPath: "#/properties/extension-specific-settings/required",
                      keyword: "required",
                      params: {
                        missingProperty: missing2
                      },
                      message: "must have required property '" + missing2 + "'"
                    }];
                    return false;
                  } else {
                    if (data9["use-optimized-filters"] !== undefined) {
                      const _errs21 = errors;

                      if (typeof data9["use-optimized-filters"] !== "boolean") {
                        validate10.errors = [{
                          instancePath: instancePath + "/extension-specific-settings/use-optimized-filters",
                          schemaPath: "#/properties/extension-specific-settings/properties/use-optimized-filters/type",
                          keyword: "type",
                          params: {
                            type: "boolean"
                          },
                          message: "must be boolean"
                        }];
                        return false;
                      }

                      var valid2 = _errs21 === errors;
                    } else {
                      var valid2 = true;
                    }

                    if (valid2) {
                      if (data9["collect-hits-count"] !== undefined) {
                        const _errs23 = errors;

                        if (typeof data9["collect-hits-count"] !== "boolean") {
                          validate10.errors = [{
                            instancePath: instancePath + "/extension-specific-settings/collect-hits-count",
                            schemaPath: "#/properties/extension-specific-settings/properties/collect-hits-count/type",
                            keyword: "type",
                            params: {
                              type: "boolean"
                            },
                            message: "must be boolean"
                          }];
                          return false;
                        }

                        var valid2 = _errs23 === errors;
                      } else {
                        var valid2 = true;
                      }

                      if (valid2) {
                        if (data9["show-context-menu"] !== undefined) {
                          const _errs25 = errors;

                          if (typeof data9["show-context-menu"] !== "boolean") {
                            validate10.errors = [{
                              instancePath: instancePath + "/extension-specific-settings/show-context-menu",
                              schemaPath: "#/properties/extension-specific-settings/properties/show-context-menu/type",
                              keyword: "type",
                              params: {
                                type: "boolean"
                              },
                              message: "must be boolean"
                            }];
                            return false;
                          }

                          var valid2 = _errs25 === errors;
                        } else {
                          var valid2 = true;
                        }

                        if (valid2) {
                          if (data9["show-info-about-adguard"] !== undefined) {
                            const _errs27 = errors;

                            if (typeof data9["show-info-about-adguard"] !== "boolean") {
                              validate10.errors = [{
                                instancePath: instancePath + "/extension-specific-settings/show-info-about-adguard",
                                schemaPath: "#/properties/extension-specific-settings/properties/show-info-about-adguard/type",
                                keyword: "type",
                                params: {
                                  type: "boolean"
                                },
                                message: "must be boolean"
                              }];
                              return false;
                            }

                            var valid2 = _errs27 === errors;
                          } else {
                            var valid2 = true;
                          }

                          if (valid2) {
                            if (data9["show-app-updated-info"] !== undefined) {
                              const _errs29 = errors;

                              if (typeof data9["show-app-updated-info"] !== "boolean") {
                                validate10.errors = [{
                                  instancePath: instancePath + "/extension-specific-settings/show-app-updated-info",
                                  schemaPath: "#/properties/extension-specific-settings/properties/show-app-updated-info/type",
                                  keyword: "type",
                                  params: {
                                    type: "boolean"
                                  },
                                  message: "must be boolean"
                                }];
                                return false;
                              }

                              var valid2 = _errs29 === errors;
                            } else {
                              var valid2 = true;
                            }
                          }
                        }
                      }
                    }
                  }
                } else {
                  validate10.errors = [{
                    instancePath: instancePath + "/extension-specific-settings",
                    schemaPath: "#/properties/extension-specific-settings/type",
                    keyword: "type",
                    params: {
                      type: "object"
                    },
                    message: "must be object"
                  }];
                  return false;
                }
              }

              var valid0 = _errs19 === errors;
            } else {
              var valid0 = true;
            }

            if (valid0) {
              if (data.filters !== undefined) {
                let data15 = data.filters;
                const _errs31 = errors;

                if (errors === _errs31) {
                  if (data15 && typeof data15 == "object" && !Array.isArray(data15)) {
                    let missing3;

                    if (data15["enabled-groups"] === undefined && (missing3 = "enabled-groups") || data15["enabled-filters"] === undefined && (missing3 = "enabled-filters") || data15["custom-filters"] === undefined && (missing3 = "custom-filters") || data15["user-filter"] === undefined && (missing3 = "user-filter") || data15.whitelist === undefined && (missing3 = "whitelist")) {
                      validate10.errors = [{
                        instancePath: instancePath + "/filters",
                        schemaPath: "#/properties/filters/required",
                        keyword: "required",
                        params: {
                          missingProperty: missing3
                        },
                        message: "must have required property '" + missing3 + "'"
                      }];
                      return false;
                    } else {
                      if (data15["enabled-groups"] !== undefined) {
                        let data16 = data15["enabled-groups"];
                        const _errs33 = errors;

                        if (errors === _errs33) {
                          if (Array.isArray(data16)) {
                            var valid4 = true;
                            const len0 = data16.length;

                            for (let i0 = 0; i0 < len0; i0++) {
                              let data17 = data16[i0];
                              const _errs35 = errors;

                              if (!(typeof data17 == "number" && !(data17 % 1) && !isNaN(data17) && isFinite(data17))) {
                                validate10.errors = [{
                                  instancePath: instancePath + "/filters/enabled-groups/" + i0,
                                  schemaPath: "#/properties/filters/properties/enabled-groups/items/type",
                                  keyword: "type",
                                  params: {
                                    type: "integer"
                                  },
                                  message: "must be integer"
                                }];
                                return false;
                              }

                              var valid4 = _errs35 === errors;

                              if (!valid4) {
                                break;
                              }
                            }
                          } else {
                            validate10.errors = [{
                              instancePath: instancePath + "/filters/enabled-groups",
                              schemaPath: "#/properties/filters/properties/enabled-groups/type",
                              keyword: "type",
                              params: {
                                type: "array"
                              },
                              message: "must be array"
                            }];
                            return false;
                          }
                        }

                        var valid3 = _errs33 === errors;
                      } else {
                        var valid3 = true;
                      }

                      if (valid3) {
                        if (data15["enabled-filters"] !== undefined) {
                          let data18 = data15["enabled-filters"];
                          const _errs37 = errors;

                          if (errors === _errs37) {
                            if (Array.isArray(data18)) {
                              var valid5 = true;
                              const len1 = data18.length;

                              for (let i1 = 0; i1 < len1; i1++) {
                                let data19 = data18[i1];
                                const _errs39 = errors;

                                if (!(typeof data19 == "number" && !(data19 % 1) && !isNaN(data19) && isFinite(data19))) {
                                  validate10.errors = [{
                                    instancePath: instancePath + "/filters/enabled-filters/" + i1,
                                    schemaPath: "#/properties/filters/properties/enabled-filters/items/type",
                                    keyword: "type",
                                    params: {
                                      type: "integer"
                                    },
                                    message: "must be integer"
                                  }];
                                  return false;
                                }

                                var valid5 = _errs39 === errors;

                                if (!valid5) {
                                  break;
                                }
                              }
                            } else {
                              validate10.errors = [{
                                instancePath: instancePath + "/filters/enabled-filters",
                                schemaPath: "#/properties/filters/properties/enabled-filters/type",
                                keyword: "type",
                                params: {
                                  type: "array"
                                },
                                message: "must be array"
                              }];
                              return false;
                            }
                          }

                          var valid3 = _errs37 === errors;
                        } else {
                          var valid3 = true;
                        }

                        if (valid3) {
                          if (data15["custom-filters"] !== undefined) {
                            const _errs41 = errors;

                            if (errors === _errs41) {
                              if (!Array.isArray(data15["custom-filters"])) {
                                validate10.errors = [{
                                  instancePath: instancePath + "/filters/custom-filters",
                                  schemaPath: "#/properties/filters/properties/custom-filters/type",
                                  keyword: "type",
                                  params: {
                                    type: "array"
                                  },
                                  message: "must be array"
                                }];
                                return false;
                              }
                            }

                            var valid3 = _errs41 === errors;
                          } else {
                            var valid3 = true;
                          }

                          if (valid3) {
                            if (data15["user-filter"] !== undefined) {
                              let data21 = data15["user-filter"];
                              const _errs43 = errors;

                              if (errors === _errs43) {
                                if (data21 && typeof data21 == "object" && !Array.isArray(data21)) {
                                  let missing4;

                                  if (data21.rules === undefined && (missing4 = "rules") || data21["disabled-rules"] === undefined && (missing4 = "disabled-rules")) {
                                    validate10.errors = [{
                                      instancePath: instancePath + "/filters/user-filter",
                                      schemaPath: "#/properties/filters/properties/user-filter/required",
                                      keyword: "required",
                                      params: {
                                        missingProperty: missing4
                                      },
                                      message: "must have required property '" + missing4 + "'"
                                    }];
                                    return false;
                                  } else {
                                    if (data21.rules !== undefined) {
                                      const _errs45 = errors;

                                      if (typeof data21.rules !== "string") {
                                        validate10.errors = [{
                                          instancePath: instancePath + "/filters/user-filter/rules",
                                          schemaPath: "#/properties/filters/properties/user-filter/properties/rules/type",
                                          keyword: "type",
                                          params: {
                                            type: "string"
                                          },
                                          message: "must be string"
                                        }];
                                        return false;
                                      }

                                      var valid6 = _errs45 === errors;
                                    } else {
                                      var valid6 = true;
                                    }

                                    if (valid6) {
                                      if (data21["disabled-rules"] !== undefined) {
                                        const _errs47 = errors;

                                        if (typeof data21["disabled-rules"] !== "string") {
                                          validate10.errors = [{
                                            instancePath: instancePath + "/filters/user-filter/disabled-rules",
                                            schemaPath: "#/properties/filters/properties/user-filter/properties/disabled-rules/type",
                                            keyword: "type",
                                            params: {
                                              type: "string"
                                            },
                                            message: "must be string"
                                          }];
                                          return false;
                                        }

                                        var valid6 = _errs47 === errors;
                                      } else {
                                        var valid6 = true;
                                      }

                                      if (valid6) {
                                        if (data21.enabled !== undefined) {
                                          const _errs49 = errors;

                                          if (typeof data21.enabled !== "boolean") {
                                            validate10.errors = [{
                                              instancePath: instancePath + "/filters/user-filter/enabled",
                                              schemaPath: "#/properties/filters/properties/user-filter/properties/enabled/type",
                                              keyword: "type",
                                              params: {
                                                type: "boolean"
                                              },
                                              message: "must be boolean"
                                            }];
                                            return false;
                                          }

                                          var valid6 = _errs49 === errors;
                                        } else {
                                          var valid6 = true;
                                        }
                                      }
                                    }
                                  }
                                } else {
                                  validate10.errors = [{
                                    instancePath: instancePath + "/filters/user-filter",
                                    schemaPath: "#/properties/filters/properties/user-filter/type",
                                    keyword: "type",
                                    params: {
                                      type: "object"
                                    },
                                    message: "must be object"
                                  }];
                                  return false;
                                }
                              }

                              var valid3 = _errs43 === errors;
                            } else {
                              var valid3 = true;
                            }

                            if (valid3) {
                              if (data15.whitelist !== undefined) {
                                let data25 = data15.whitelist;
                                const _errs51 = errors;

                                if (errors === _errs51) {
                                  if (data25 && typeof data25 == "object" && !Array.isArray(data25)) {
                                    let missing5;

                                    if (data25.inverted === undefined && (missing5 = "inverted") || data25.domains === undefined && (missing5 = "domains") || data25["inverted-domains"] === undefined && (missing5 = "inverted-domains")) {
                                      validate10.errors = [{
                                        instancePath: instancePath + "/filters/whitelist",
                                        schemaPath: "#/properties/filters/properties/whitelist/required",
                                        keyword: "required",
                                        params: {
                                          missingProperty: missing5
                                        },
                                        message: "must have required property '" + missing5 + "'"
                                      }];
                                      return false;
                                    } else {
                                      if (data25.inverted !== undefined) {
                                        const _errs53 = errors;

                                        if (typeof data25.inverted !== "boolean") {
                                          validate10.errors = [{
                                            instancePath: instancePath + "/filters/whitelist/inverted",
                                            schemaPath: "#/properties/filters/properties/whitelist/properties/inverted/type",
                                            keyword: "type",
                                            params: {
                                              type: "boolean"
                                            },
                                            message: "must be boolean"
                                          }];
                                          return false;
                                        }

                                        var valid7 = _errs53 === errors;
                                      } else {
                                        var valid7 = true;
                                      }

                                      if (valid7) {
                                        if (data25.domains !== undefined) {
                                          let data27 = data25.domains;
                                          const _errs55 = errors;

                                          if (errors === _errs55) {
                                            if (Array.isArray(data27)) {
                                              var valid8 = true;
                                              const len2 = data27.length;

                                              for (let i2 = 0; i2 < len2; i2++) {
                                                const _errs57 = errors;

                                                if (typeof data27[i2] !== "string") {
                                                  validate10.errors = [{
                                                    instancePath: instancePath + "/filters/whitelist/domains/" + i2,
                                                    schemaPath: "#/properties/filters/properties/whitelist/properties/domains/items/type",
                                                    keyword: "type",
                                                    params: {
                                                      type: "string"
                                                    },
                                                    message: "must be string"
                                                  }];
                                                  return false;
                                                }

                                                var valid8 = _errs57 === errors;

                                                if (!valid8) {
                                                  break;
                                                }
                                              }
                                            } else {
                                              validate10.errors = [{
                                                instancePath: instancePath + "/filters/whitelist/domains",
                                                schemaPath: "#/properties/filters/properties/whitelist/properties/domains/type",
                                                keyword: "type",
                                                params: {
                                                  type: "array"
                                                },
                                                message: "must be array"
                                              }];
                                              return false;
                                            }
                                          }

                                          var valid7 = _errs55 === errors;
                                        } else {
                                          var valid7 = true;
                                        }

                                        if (valid7) {
                                          if (data25["inverted-domains"] !== undefined) {
                                            let data29 = data25["inverted-domains"];
                                            const _errs59 = errors;

                                            if (errors === _errs59) {
                                              if (Array.isArray(data29)) {
                                                var valid9 = true;
                                                const len3 = data29.length;

                                                for (let i3 = 0; i3 < len3; i3++) {
                                                  const _errs61 = errors;

                                                  if (typeof data29[i3] !== "string") {
                                                    validate10.errors = [{
                                                      instancePath: instancePath + "/filters/whitelist/inverted-domains/" + i3,
                                                      schemaPath: "#/properties/filters/properties/whitelist/properties/inverted-domains/items/type",
                                                      keyword: "type",
                                                      params: {
                                                        type: "string"
                                                      },
                                                      message: "must be string"
                                                    }];
                                                    return false;
                                                  }

                                                  var valid9 = _errs61 === errors;

                                                  if (!valid9) {
                                                    break;
                                                  }
                                                }
                                              } else {
                                                validate10.errors = [{
                                                  instancePath: instancePath + "/filters/whitelist/inverted-domains",
                                                  schemaPath: "#/properties/filters/properties/whitelist/properties/inverted-domains/type",
                                                  keyword: "type",
                                                  params: {
                                                    type: "array"
                                                  },
                                                  message: "must be array"
                                                }];
                                                return false;
                                              }
                                            }

                                            var valid7 = _errs59 === errors;
                                          } else {
                                            var valid7 = true;
                                          }

                                          if (valid7) {
                                            if (data25.enabled !== undefined) {
                                              const _errs63 = errors;

                                              if (typeof data25.enabled !== "boolean") {
                                                validate10.errors = [{
                                                  instancePath: instancePath + "/filters/whitelist/enabled",
                                                  schemaPath: "#/properties/filters/properties/whitelist/properties/enabled/type",
                                                  keyword: "type",
                                                  params: {
                                                    type: "boolean"
                                                  },
                                                  message: "must be boolean"
                                                }];
                                                return false;
                                              }

                                              var valid7 = _errs63 === errors;
                                            } else {
                                              var valid7 = true;
                                            }
                                          }
                                        }
                                      }
                                    }
                                  } else {
                                    validate10.errors = [{
                                      instancePath: instancePath + "/filters/whitelist",
                                      schemaPath: "#/properties/filters/properties/whitelist/type",
                                      keyword: "type",
                                      params: {
                                        type: "object"
                                      },
                                      message: "must be object"
                                    }];
                                    return false;
                                  }
                                }

                                var valid3 = _errs51 === errors;
                              } else {
                                var valid3 = true;
                              }
                            }
                          }
                        }
                      }
                    }
                  } else {
                    validate10.errors = [{
                      instancePath: instancePath + "/filters",
                      schemaPath: "#/properties/filters/type",
                      keyword: "type",
                      params: {
                        type: "object"
                      },
                      message: "must be object"
                    }];
                    return false;
                  }
                }

                var valid0 = _errs31 === errors;
              } else {
                var valid0 = true;
              }

              if (valid0) {
                if (data.stealth !== undefined) {
                  let data32 = data.stealth;
                  const _errs65 = errors;

                  if (errors === _errs65) {
                    if (data32 && typeof data32 == "object" && !Array.isArray(data32)) {
                      let missing6;

                      if (data32.stealth_disable_stealth_mode === undefined && (missing6 = "stealth_disable_stealth_mode") || data32["stealth-hide-referrer"] === undefined && (missing6 = "stealth-hide-referrer") || data32["stealth-hide-search-queries"] === undefined && (missing6 = "stealth-hide-search-queries") || data32["stealth-send-do-not-track"] === undefined && (missing6 = "stealth-send-do-not-track") || data32["stealth-block-webrtc"] === undefined && (missing6 = "stealth-block-webrtc") || data32["stealth-block-third-party-cookies"] === undefined && (missing6 = "stealth-block-third-party-cookies") || data32["stealth-block-first-party-cookies"] === undefined && (missing6 = "stealth-block-first-party-cookies") || data32["strip-tracking-parameters"] === undefined && (missing6 = "strip-tracking-parameters")) {
                        validate10.errors = [{
                          instancePath: instancePath + "/stealth",
                          schemaPath: "#/properties/stealth/required",
                          keyword: "required",
                          params: {
                            missingProperty: missing6
                          },
                          message: "must have required property '" + missing6 + "'"
                        }];
                        return false;
                      } else {
                        if (data32.stealth_disable_stealth_mode !== undefined) {
                          const _errs67 = errors;

                          if (typeof data32.stealth_disable_stealth_mode !== "boolean") {
                            validate10.errors = [{
                              instancePath: instancePath + "/stealth/stealth_disable_stealth_mode",
                              schemaPath: "#/properties/stealth/properties/stealth_disable_stealth_mode/type",
                              keyword: "type",
                              params: {
                                type: "boolean"
                              },
                              message: "must be boolean"
                            }];
                            return false;
                          }

                          var valid10 = _errs67 === errors;
                        } else {
                          var valid10 = true;
                        }

                        if (valid10) {
                          if (data32["stealth-hide-referrer"] !== undefined) {
                            const _errs69 = errors;

                            if (typeof data32["stealth-hide-referrer"] !== "boolean") {
                              validate10.errors = [{
                                instancePath: instancePath + "/stealth/stealth-hide-referrer",
                                schemaPath: "#/properties/stealth/properties/stealth-hide-referrer/type",
                                keyword: "type",
                                params: {
                                  type: "boolean"
                                },
                                message: "must be boolean"
                              }];
                              return false;
                            }

                            var valid10 = _errs69 === errors;
                          } else {
                            var valid10 = true;
                          }

                          if (valid10) {
                            if (data32["stealth-hide-search-queries"] !== undefined) {
                              const _errs71 = errors;

                              if (typeof data32["stealth-hide-search-queries"] !== "boolean") {
                                validate10.errors = [{
                                  instancePath: instancePath + "/stealth/stealth-hide-search-queries",
                                  schemaPath: "#/properties/stealth/properties/stealth-hide-search-queries/type",
                                  keyword: "type",
                                  params: {
                                    type: "boolean"
                                  },
                                  message: "must be boolean"
                                }];
                                return false;
                              }

                              var valid10 = _errs71 === errors;
                            } else {
                              var valid10 = true;
                            }

                            if (valid10) {
                              if (data32["stealth-send-do-not-track"] !== undefined) {
                                const _errs73 = errors;

                                if (typeof data32["stealth-send-do-not-track"] !== "boolean") {
                                  validate10.errors = [{
                                    instancePath: instancePath + "/stealth/stealth-send-do-not-track",
                                    schemaPath: "#/properties/stealth/properties/stealth-send-do-not-track/type",
                                    keyword: "type",
                                    params: {
                                      type: "boolean"
                                    },
                                    message: "must be boolean"
                                  }];
                                  return false;
                                }

                                var valid10 = _errs73 === errors;
                              } else {
                                var valid10 = true;
                              }

                              if (valid10) {
                                if (data32["stealth-block-webrtc"] !== undefined) {
                                  const _errs75 = errors;

                                  if (typeof data32["stealth-block-webrtc"] !== "boolean") {
                                    validate10.errors = [{
                                      instancePath: instancePath + "/stealth/stealth-block-webrtc",
                                      schemaPath: "#/properties/stealth/properties/stealth-block-webrtc/type",
                                      keyword: "type",
                                      params: {
                                        type: "boolean"
                                      },
                                      message: "must be boolean"
                                    }];
                                    return false;
                                  }

                                  var valid10 = _errs75 === errors;
                                } else {
                                  var valid10 = true;
                                }

                                if (valid10) {
                                  if (data32["stealth-block-third-party-cookies"] !== undefined) {
                                    const _errs77 = errors;

                                    if (typeof data32["stealth-block-third-party-cookies"] !== "boolean") {
                                      validate10.errors = [{
                                        instancePath: instancePath + "/stealth/stealth-block-third-party-cookies",
                                        schemaPath: "#/properties/stealth/properties/stealth-block-third-party-cookies/type",
                                        keyword: "type",
                                        params: {
                                          type: "boolean"
                                        },
                                        message: "must be boolean"
                                      }];
                                      return false;
                                    }

                                    var valid10 = _errs77 === errors;
                                  } else {
                                    var valid10 = true;
                                  }

                                  if (valid10) {
                                    if (data32["stealth-block-first-party-cookies"] !== undefined) {
                                      const _errs79 = errors;

                                      if (typeof data32["stealth-block-first-party-cookies"] !== "boolean") {
                                        validate10.errors = [{
                                          instancePath: instancePath + "/stealth/stealth-block-first-party-cookies",
                                          schemaPath: "#/properties/stealth/properties/stealth-block-first-party-cookies/type",
                                          keyword: "type",
                                          params: {
                                            type: "boolean"
                                          },
                                          message: "must be boolean"
                                        }];
                                        return false;
                                      }

                                      var valid10 = _errs79 === errors;
                                    } else {
                                      var valid10 = true;
                                    }

                                    if (valid10) {
                                      if (data32["block-known-trackers"] !== undefined) {
                                        const _errs81 = errors;

                                        if (typeof data32["block-known-trackers"] !== "boolean") {
                                          validate10.errors = [{
                                            instancePath: instancePath + "/stealth/block-known-trackers",
                                            schemaPath: "#/properties/stealth/properties/block-known-trackers/type",
                                            keyword: "type",
                                            params: {
                                              type: "boolean"
                                            },
                                            message: "must be boolean"
                                          }];
                                          return false;
                                        }

                                        var valid10 = _errs81 === errors;
                                      } else {
                                        var valid10 = true;
                                      }

                                      if (valid10) {
                                        if (data32["strip-tracking-parameters"] !== undefined) {
                                          const _errs83 = errors;

                                          if (typeof data32["strip-tracking-parameters"] !== "boolean") {
                                            validate10.errors = [{
                                              instancePath: instancePath + "/stealth/strip-tracking-parameters",
                                              schemaPath: "#/properties/stealth/properties/strip-tracking-parameters/type",
                                              keyword: "type",
                                              params: {
                                                type: "boolean"
                                              },
                                              message: "must be boolean"
                                            }];
                                            return false;
                                          }

                                          var valid10 = _errs83 === errors;
                                        } else {
                                          var valid10 = true;
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    } else {
                      validate10.errors = [{
                        instancePath: instancePath + "/stealth",
                        schemaPath: "#/properties/stealth/type",
                        keyword: "type",
                        params: {
                          type: "object"
                        },
                        message: "must be object"
                      }];
                      return false;
                    }
                  }

                  var valid0 = _errs65 === errors;
                } else {
                  var valid0 = true;
                }
              }
            }
          }
        }
      }
    } else {
      validate10.errors = [{
        instancePath,
        schemaPath: "#/type",
        keyword: "type",
        params: {
          type: "object"
        },
        message: "must be object"
      }];
      return false;
    }
  }

  validate10.errors = vErrors;
  return errors === 0;
}

/***/ }),

/***/ 3800:
/***/ ((module) => {

/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Adguard Browser Extension.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * As it is not possible to use one library in node and browser environments,
 * we have to implementation of simple file download interface.
 * The one for node uses axios, the one for browser XMLHttpRequest.
 *
 * @type {{getLocalFile, getExternalFile}}
 */
module.exports = (() => {
    'use strict';

    /**
     * If url protocol is not http or https return true, else false
     * @param url
     * @returns {boolean}
     */
    const isLocal = (url) => {
        const parsedUrl = new URL(url);
        const protocols = ['http:', 'https:'];
        return !protocols.includes(parsedUrl.protocol);
    };

    /**
     * Executes async request via fetch
     * fetch doesn't allow to download urls with file:// scheme
     *
     * @param url Url
     * @param contentType Content type
     * @returns {Promise}
     */
    const executeRequestAsyncFetch = async (url, contentType) => {
        const response = await fetch(url, {
            cache: 'no-cache',
            headers: {
                Pragma: 'no-cache',
                'Content-Type': contentType,
            }
        });

        if (response.status !== 200 && response.status !== 0) {
            throw new Error(`Response status for url ${url} is invalid: ${response.status}`);
        }

        // Don't check response headers if url is local,
        // because edge extension doesn't provide headers for such url
        if (!isLocal(response.url)) {
            const responseContentType = response.headers.get('Content-Type');
            if (!responseContentType || !responseContentType.includes(contentType)) {
                throw new Error(`Response content type should be: "${contentType}"`);
            }
        }

        const responseText = await response.text();

        return responseText.trim().split(/[\r\n]+/);
    };

    /**
     * Executes async request via XMLHttpRequest
     * XMLHttpRequest is undefined in the service worker
     *
     * @param {string} url Url
     * @param {string} contentType Content type
     * @returns {Promise}
     */
    const executeRequestAsyncXhr = (url, contentType) => {
        return new Promise((resolve, reject) => {
            const onRequestLoad = (response) => {
                if (response.status !== 200 && response.status !== 0) {
                    reject(new Error(`Response status for url ${url} is invalid: ${response.status}`));
                }

                const responseText = response.responseText ? response.responseText : response.data;

                // Don't check response headers if url is local,
                // because edge extension doesn't provide headers for such url
                if (!isLocal(response.responseURL)) {
                    const responseContentType = response.getResponseHeader('Content-Type');
                    if (!responseContentType || !responseContentType.includes(contentType)) {
                        reject(new Error(`Response content type should be: "${contentType}"`));
                    }
                }
                const lines = responseText.trim().split(/[\r\n]+/);
                resolve(lines);
            };

            const request = new XMLHttpRequest();

            try {
                request.open('GET', url);
                request.setRequestHeader('Pragma', 'no-cache');
                request.overrideMimeType(contentType);
                request.mozBackgroundRequest = true;
                request.onload = function () {
                    onRequestLoad(request);
                };
                request.onerror = () => reject(new Error(`Request error happened: ${request.statusText || 'status text empty'}`));
                request.onabort = () => reject(new Error(`Request was aborted with status text: ${request.statusText}`));
                request.ontimeout = () => reject(new Error(`Request timed out with status text: ${request.statusText}`));

                request.send(null);
            } catch (ex) {
                reject(ex);
            }
        });
    };

    /**
     * Downloads filter rules from external url
     *
     * @param {string} url Filter file absolute URL or relative path
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const getExternalFile = (url) => {
        return executeRequestAsyncFetch(url, 'text/plain');
    };

    /**
     * Get filter rules from local path
     *
     * @param {string} url local path
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const getLocalFile = (url) => {
        if (typeof XMLHttpRequest !== 'undefined') {
            return executeRequestAsyncXhr(url, 'text/plain');
        }
        if (typeof fetch !== 'undefined') {
            return executeRequestAsyncFetch(url, 'text/plain');
        }
        throw new Error('XMLHttpRequest or fetch are undefined, getting local files inside service worker is not working');
    };

    return {
        getLocalFile: getLocalFile,
        getExternalFile: getExternalFile,
    };
})();


/***/ }),

/***/ 652:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Adguard Browser Extension.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * The utility tool resolves preprocessor directives in filter content.
 *
 * Directives syntax:
 * !#if, !#endif - filters maintainers can use these conditions to supply different rules depending on the ad blocker type.
 * condition - just like in some popular programming languages, pre-processor conditions are based on constants declared by ad blockers. Ad blocker authors define on their own what exact constants do they declare.
 * !#include - this directive allows to include contents of a specified file into the filter.
 *
 * Condition constants should be declared in FilterCompilerConditionsConstants
 *
 * More details:
 * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/917
 */
const FiltersDownloaderCreator = (FileDownloadWrapper) => {
    "use strict";

    const CONDITION_DIRECTIVE_START = "!#if";
    const CONDITION_DIRECTIVE_END = "!#endif";

    const CONDITION_OPERATOR_NOT = "!";
    const CONDITION_OPERATOR_AND = "&&";
    const CONDITION_OPERATOR_OR = "||";
    const CONDITION_BRACKET_OPEN_CHAR = "(";
    const CONDITION_BRACKET_CLOSE_CHAR = ")";

    const INCLUDE_DIRECTIVE = "!#include";

    const REGEXP_ABSOLUTE_URL = /^([a-z]+:\/\/|\/\/)/i;
    const REGEXP_EXTERNAL_ABSOLUTE_URL = /^((?!file)[a-z]+:\/\/|\/\/)/i;

    /**
     * Checks brackets in string
     *
     * @param str
     */
    const checkBracketsBalance = (str) => {
        let depth = 0;
        for (let i in str) {
            if (str[i] === CONDITION_BRACKET_OPEN_CHAR) {
                // if the char is an opening parenthesis then we increase the depth
                depth++;
            } else if (str[i] === CONDITION_BRACKET_CLOSE_CHAR) {
                // if the char is an closing parenthesis then we decrease the depth
                depth--;
            }
            //  if the depth is negative we have a closing parenthesis
            //  before any matching opening parenthesis
            if (depth < 0) {
                return false;
            }
        }
        // If the depth is not null then a closing parenthesis is missing
        if (depth > 0) {
            return false;
        }

        return true;
    };

    /**
     * Finds end of condition block started with startIndex
     *
     * @param rules
     * @param startIndex
     */
    const findConditionEnd = (rules, startIndex) => {
        const stack = [];
        for (let j = startIndex; j < rules.length; j++) {
            let internalRule = rules[j];

            if (internalRule.startsWith(CONDITION_DIRECTIVE_START)) {
                stack.push(CONDITION_DIRECTIVE_START);

            } else if (internalRule.startsWith(CONDITION_DIRECTIVE_END)) {
                if (stack.length > 0) {
                    stack.pop();
                } else {
                    return j;
                }
            }
        }

        return -1;
    };

    /**
     * Resolves constant expression
     *
     * @param expression
     * @param definedProperties
     */
    const resolveConditionConstant = (expression, definedProperties) => {
        if (!expression) {
            throw new Error('Invalid directives: Empty condition');
        }

        let trim = expression.trim();
        return trim === "true" || definedProperties[trim];
    };

    /**
     * Calculates conditional expression
     *
     * @param expression
     * @param definedProperties
     */
    const resolveExpression = (expression, definedProperties) => {
        if (!expression) {
            throw new Error('Invalid directives: Empty condition');
        }

        expression = expression.trim();

        if (!checkBracketsBalance(expression)) {
            throw new Error('Invalid directives: Incorrect brackets: ' + expression);
        }

        //Replace bracketed expressions
        const openBracketIndex = expression.lastIndexOf(CONDITION_BRACKET_OPEN_CHAR);
        if (openBracketIndex !== -1) {
            const endBracketIndex = expression.indexOf(CONDITION_BRACKET_CLOSE_CHAR, openBracketIndex);
            const innerExpression = expression.substring(openBracketIndex + 1, endBracketIndex);
            const innerResult = resolveExpression(innerExpression, definedProperties);
            const resolvedInner = expression.substring(0, openBracketIndex) +
                innerResult + expression.substring(endBracketIndex + 1);

            return resolveExpression(resolvedInner, definedProperties);
        }

        let result;

        // Resolve logical operators
        const indexOfAndOperator = expression.indexOf(CONDITION_OPERATOR_AND);
        const indexOfOrOperator = expression.indexOf(CONDITION_OPERATOR_OR);
        const indexOfNotOperator = expression.indexOf(CONDITION_OPERATOR_NOT);

        if (indexOfOrOperator !== -1) {
            result = resolveExpression(expression.substring(0, indexOfOrOperator - 1), definedProperties) ||
                resolveExpression(expression.substring(indexOfOrOperator + CONDITION_OPERATOR_OR.length, expression.length), definedProperties);
        } else if (indexOfAndOperator !== -1) {
            result = resolveExpression(expression.substring(0, indexOfAndOperator - 1), definedProperties) &&
                resolveExpression(expression.substring(indexOfAndOperator + CONDITION_OPERATOR_AND.length, expression.length), definedProperties);
        } else if (indexOfNotOperator === 0) {
            result = !resolveExpression(expression.substring(CONDITION_OPERATOR_NOT.length), definedProperties);
        } else {
            result = resolveConditionConstant(expression, definedProperties);
        }

        return result;
    };

    /**
     * Validates and resolves condition directive
     *
     * @param directive
     * @param definedProperties
     */
    const resolveCondition = (directive, definedProperties) => {
        const expression = directive.substring(CONDITION_DIRECTIVE_START.length).trim();

        return resolveExpression(expression, definedProperties);
    };

    /**
     * Resolves conditions directives
     *
     * @param rules
     * @param definedProperties
     */
    const resolveConditions = (rules, definedProperties) => {
        if (!definedProperties) {
            return rules;
        }

        let result = [];

        for (let i = 0; i < rules.length; i++) {
            let rule = rules[i];

            if (rule.indexOf(CONDITION_DIRECTIVE_START) === 0) {
                let endLineIndex = findConditionEnd(rules, i + 1);
                if (endLineIndex === -1) {
                    throw new Error('Invalid directives: Condition end not found: ' + rule);
                }

                let conditionValue = resolveCondition(rule, definedProperties);
                if (conditionValue) {
                    let rulesUnderCondition = rules.slice(i + 1, endLineIndex);
                    // Resolve inner conditions in recursion
                    result = result.concat(resolveConditions(rulesUnderCondition, definedProperties));
                }

                // Skip to the end of block
                i = endLineIndex;
            } else if (rule.indexOf(CONDITION_DIRECTIVE_END) === 0) {
                // Found condition end without start
                throw new Error('Invalid directives: Found unexpected condition end: ' + rule);
            } else {
                result.push(rule);
            }
        }

        return result;
    };

    /**
     * Validates url to be the same origin with original filterUrl
     *
     * @param url
     * @param filterUrlOrigin
     */
    const validateUrl = function (url, filterUrlOrigin) {
        if (filterUrlOrigin) {
            if (REGEXP_ABSOLUTE_URL.test(url)) {

                // Include url is absolute
                const urlOrigin = parseURL(url).origin;
                const filterOrigin = parseURL(filterUrlOrigin).origin;
                if (urlOrigin !== filterOrigin) {
                    throw new Error('Include url is rejected with origin: ' + urlOrigin);
                }
            }
        }
    };

    /**
     * Validates and resolves include directive
     *
     * @param {string} line
     * @param {?string} filterOrigin Filter file URL origin or null
     * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const resolveInclude = function (line, filterOrigin, definedProperties) {
        if (line.indexOf(INCLUDE_DIRECTIVE) !== 0) {
            return Promise.resolve(line);
        } else {
            const url = line.substring(INCLUDE_DIRECTIVE.length).trim();
            validateUrl(url, filterOrigin);
            return downloadFilterRules(url, filterOrigin, definedProperties);
        }
    };

    /**
     * Resolves include directives
     *
     * @param {Array} rules   array of rules
     * @param {?string} filterOrigin Filter file URL origin or null
     * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const resolveIncludes = (rules, filterOrigin, definedProperties) => {
        const dfds = [];

        for (let rule of rules) {
            dfds.push(resolveInclude(rule, filterOrigin, definedProperties));
        }

        return Promise.all(dfds).then((values) => {
            let result = [];

            values.forEach(function (v) {
                if (Array.isArray(v)) {
                    result = result.concat(v);
                } else {
                    result.push(v);
                }
            });

            return result;
        });
    };

    /**
     * Compiles filter content
     *
     * @param {Array} rules Array of strings
     * @param {?string} filterUrlOrigin Filter file URL origin or null
     * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const compile = (rules, filterOrigin, definedProperties) => {
        try {
            // Resolve 'if' conditions
            const resolvedConditionsResult = resolveConditions(rules, definedProperties);

            // Resolve 'includes' directives
            return resolveIncludes(resolvedConditionsResult, filterOrigin, definedProperties);
        } catch (ex) {
            return Promise.reject(ex);
        }
    };

    /**
     * Downloads filter rules from url
     *
     * @param {string} url Filter file URL
     * @param {?string} filterUrlOrigin Filter file URL origin or null
     * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const downloadFilterRules = (url, filterUrlOrigin, definedProperties) => {
        if (REGEXP_EXTERNAL_ABSOLUTE_URL.test(url) || REGEXP_EXTERNAL_ABSOLUTE_URL.test(filterUrlOrigin)) {
            return externalDownload(url, filterUrlOrigin, definedProperties);
        } else {
            return getLocalFile(url, filterUrlOrigin, definedProperties);
        }
    };

    /**
     * Downloads filter rules from external url
     *
     * @param {string} url Filter file absolute URL or relative path
     * @param {?string} filterUrlOrigin Filter file URL origin or null
     * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const externalDownload = (url, filterUrlOrigin, definedProperties) => {

        // getting absolute url for external file with relative url
        if (!REGEXP_ABSOLUTE_URL.test(url) && REGEXP_ABSOLUTE_URL.test(filterUrlOrigin)) {
            url = `${filterUrlOrigin}/${url}`;
        }

        return FileDownloadWrapper.getExternalFile(url, filterUrlOrigin, definedProperties).then((lines) => {
            // Filter origin could change in case url contains subdirectories
            // https://github.com/AdguardTeam/FiltersRegistry/pull/256
            filterUrlOrigin = getFilterUrlOrigin(url, null);

            // Resolve 'if' conditions and 'includes' directives
            const resolvedConditionsResult = resolveConditions(lines, definedProperties);
            return resolveIncludes(resolvedConditionsResult, filterUrlOrigin, definedProperties);
        });
    };

    /**
     * Get filter rules from local path
     *
     * @param {string} url local path
     * @param {?string} filterUrlOrigin origin path
     * @param {?object} definedProperties An object with the defined properties
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const getLocalFile = (url, filterUrlOrigin, definedProperties) => {
        if (filterUrlOrigin) {
            url = `${filterUrlOrigin}/${url}`;
        }

        filterUrlOrigin = getFilterUrlOrigin(url, filterUrlOrigin);

        return FileDownloadWrapper.getLocalFile(url, filterUrlOrigin, definedProperties).then((lines) => {
            filterUrlOrigin = getFilterUrlOrigin(url, null);

            // Resolve 'if' conditions and 'includes' directives
            const resolvedConditionsResult = resolveConditions(lines, definedProperties);
            return resolveIncludes(resolvedConditionsResult, filterUrlOrigin, definedProperties);
        });
    };

    /**
     * Get the `filterUrlOrigin` from url for relative path resolve
     *
     * @param {string} url Filter file URL
     * @param {string|null} filterUrlOrigin  existing origin url
     * @returns {string} valid origin url
     */
    const getFilterUrlOrigin = (url, filterUrlOrigin) => {
        if (filterUrlOrigin) {
            return filterUrlOrigin;
        } else {
            return url.substring(0, url.lastIndexOf('/'));
        }
    };

    /**
     * Downloads a specified filter and interpretes all the pre-processor directives from there.
     *
     * @param {string} url Filter file URL
     * @param {Object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc)
     * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected.
     */
    const download = async (url, definedProperties) => {
        try {
            let filterUrlOrigin;
            if (url && REGEXP_EXTERNAL_ABSOLUTE_URL.test(url)) {
                filterUrlOrigin = getFilterUrlOrigin(url)
            }

            const response = await downloadFilterRules(url, filterUrlOrigin, definedProperties);

            // only included filters can be empty
            if (response && response.join().trim() == '') {
                throw new Error("Response is empty");
            }

            return response;
        } catch (ex) {
            return Promise.reject(ex);
        }
    };

    /**
     * Parse url
     *
     * @param {string} url
     * @returns {object}  parsed url data
     */
    const parseURL = (url) => {
        if (typeof URL !== 'undefined') {
            return new URL(url);
        } else {
            let URL = (__webpack_require__(3548).URL);
            return new URL(url);
        }
    };

    return {
        compile: compile,
        download: download,
        resolveConditions: resolveConditions,
        resolveIncludes: resolveIncludes,
        getFilterUrlOrigin: getFilterUrlOrigin
    };
};

module.exports = FiltersDownloaderCreator;


/***/ }),

/***/ 9317:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

// This file replaces `index.js` in bundlers like webpack or Rollup,
// according to `browser` config in `package.json`.

const filtersDownloaderCreator = __webpack_require__(652);
const FileDownloadWrapper = __webpack_require__(3800);

const FiltersDownloader = filtersDownloaderCreator(FileDownloadWrapper);

module.exports = FiltersDownloader;


/***/ }),

/***/ 8782:
/***/ ((module, exports, __webpack_require__) => {

var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;
/**
 * AdGuard Scriptlets
 * Version 1.6.8
 */

(function (factory) {
     true ? !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
		__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
		(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
		__WEBPACK_AMD_DEFINE_FACTORY__),
		__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) :
    0;
}((function () {
    /**
     * Returns wildcard symbol
     * @returns {string} '*'
     */
    var getWildcardSymbol = function getWildcardSymbol() {
      return '*';
    };

    /**
     * Generate random six symbols id
     */
    function randomId() {
      return Math.random().toString(36).substr(2, 9);
    }

    /**
     * Set getter and setter to property if it's configurable
     * @param {Object} object target object with property
     * @param {string} property property name
     * @param {Object} descriptor contains getter and setter functions
     * @returns {boolean} is operation successful
     */
    function setPropertyAccess(object, property, descriptor) {
      var currentDescriptor = Object.getOwnPropertyDescriptor(object, property);

      if (currentDescriptor && !currentDescriptor.configurable) {
        return false;
      }

      Object.defineProperty(object, property, descriptor);
      return true;
    }

    /**
     * @typedef Chain
     * @property {Object} base
     * @property {string} prop
     * @property {string} [chain]
     */

    /**
     * Check if the property exists in the base object (recursively)
     *
     * If property doesn't exist in base object,
     * defines this property as 'undefined'
     * and returns base, property name and remaining part of property chain
     *
     * @param {Object} base
     * @param {string} chain
     * @returns {Chain}
     */
    function getPropertyInChain(base, chain) {
      var pos = chain.indexOf('.');

      if (pos === -1) {
        return {
          base: base,
          prop: chain
        };
      }

      var prop = chain.slice(0, pos); // https://github.com/AdguardTeam/Scriptlets/issues/128

      if (base === null) {
        // if base is null, return 'null' as base.
        // it's needed for triggering the reason logging while debugging
        return {
          base: base,
          prop: prop,
          chain: chain
        };
      }

      var nextBase = base[prop];
      chain = chain.slice(pos + 1);

      if (nextBase !== undefined) {
        return getPropertyInChain(nextBase, chain);
      }

      Object.defineProperty(base, prop, {
        configurable: true
      });
      return {
        base: nextBase,
        prop: prop,
        chain: chain
      };
    }

    /**
     * @typedef Chain
     * @property {Object} base
     * @property {string} prop
     * @property {string} [chain]
     */

    /**
     * Check if the property exists in the base object (recursively).
     * Similar to getPropertyInChain but upgraded for json-prune:
     * handle wildcard properties and does not define nonexistent base property as 'undefined'
     *
     * @param {Object} base
     * @param {string} chain
     * @param {boolean} [lookThrough=false]
     * should the method look through it's props in order to wildcard
     * @param {Array} [output=[]] result acc
     * @returns {Chain[]} array of objects
     */

    function getWildcardPropertyInChain(base, chain) {
      var lookThrough = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
      var output = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
      var pos = chain.indexOf('.');

      if (pos === -1) {
        // for paths like 'a.b.*' every final nested prop should be processed
        if (chain === getWildcardSymbol() || chain === '[]') {
          // eslint-disable-next-line no-restricted-syntax
          for (var key in base) {
            // to process each key in base except inherited ones
            if (Object.prototype.hasOwnProperty.call(base, key)) {
              output.push({
                base: base,
                prop: key
              });
            }
          }
        } else {
          output.push({
            base: base,
            prop: chain
          });
        }

        return output;
      }

      var prop = chain.slice(0, pos);
      var shouldLookThrough = prop === '[]' && Array.isArray(base) || prop === getWildcardSymbol() && base instanceof Object;

      if (shouldLookThrough) {
        var nextProp = chain.slice(pos + 1);
        var baseKeys = Object.keys(base); // if there is a wildcard prop in input chain (e.g. 'ad.*.src' for 'ad.0.src ad.1.src'),
        // each one of base keys should be considered as a potential chain prop in final path

        baseKeys.forEach(function (key) {
          var item = base[key];
          getWildcardPropertyInChain(item, nextProp, lookThrough, output);
        });
      }

      var nextBase = base[prop];
      chain = chain.slice(pos + 1);

      if (nextBase !== undefined) {
        getWildcardPropertyInChain(nextBase, chain, lookThrough, output);
      }

      return output;
    }

    /**
     * Determines whether the passed value is NaN
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
     * @param {*} num
     * @returns {boolean}
     */
    var nativeIsNaN = function nativeIsNaN(num) {
      var native = Number.isNaN || window.isNaN; // eslint-disable-line compat/compat

      return native(num);
    };
    /**
     * Determines whether the passed value is a finite number
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite
     * @param {*} num
     * @returns {boolean}
     */

    var nativeIsFinite = function nativeIsFinite(num) {
      var native = Number.isFinite || window.isFinite; // eslint-disable-line compat/compat

      return native(num);
    };
    /**
     * Parses string for a number, if possible, otherwise returns null.
     * @param {*} rawDelay
     * @returns {number|null}
     */

    var getNumberFromString = function getNumberFromString(rawString) {
      var parsedDelay = parseInt(rawString, 10);
      var validDelay = nativeIsNaN(parsedDelay) ? null : parsedDelay;
      return validDelay;
    };

    /**
     * Converts object to array of pairs.
     * Object.entries() polyfill because it is not supported by IE
     * https://caniuse.com/?search=Object.entries
     * @param {Object} object
     * @returns {Array} array of pairs
     */
    var getObjectEntries = function getObjectEntries(object) {
      var keys = Object.keys(object);
      var entries = [];
      keys.forEach(function (key) {
        return entries.push([key, object[key]]);
      });
      return entries;
    };
    /**
     * Converts array of pairs to object.
     * Object.fromEntries() polyfill because it is not supported by IE
     * https://caniuse.com/?search=Object.fromEntries
     * @param {Array} entries - array of pairs
     * @returns {Object}
     */

    var getObjectFromEntries = function getObjectFromEntries(entries) {
      var output = entries.reduce(function (acc, el) {
        var key = el[0];
        var value = el[1];
        acc[key] = value;
        return acc;
      }, {});
      return output;
    };
    /**
     * Checks whether the obj is an empty object
     * @param {Object} obj
     * @returns {boolean}
     */

    var isEmptyObject = function isEmptyObject(obj) {
      return Object.keys(obj).length === 0;
    };
    /**
     * Checks whether the obj is an empty object
     * @param {Object} obj
     * @param {string} prop
     * @returns {Object|null}
     */

    var safeGetDescriptor = function safeGetDescriptor(obj, prop) {
      var descriptor = Object.getOwnPropertyDescriptor(obj, prop);

      if (descriptor && descriptor.configurable) {
        return descriptor;
      }

      return null;
    };

    /**
     * String.prototype.replaceAll polyfill
     * @param {string} input input string
     * @param {string} substr to look for
     * @param {string} newSubstr replacement
     * @returns {string}
     */

    var replaceAll = function replaceAll(input, substr, newSubstr) {
      return input.split(substr).join(newSubstr);
    };
    /**
     * Escapes special chars in string
     * @param {string} str
     * @returns {string}
     */

    var escapeRegExp = function escapeRegExp(str) {
      return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    };
    /**
     * A literal string or regexp pattern wrapped in forward slashes.
     * For example, 'simpleStr' or '/adblock|_0x/'.
     * @typedef {string} RawStrPattern
     */

    /**
     * Converts string to the regexp
     * TODO think about nested dependencies, but be careful with dependency loops
     * @param {RawStrPattern} [input=''] literal string or regexp pattern; defaults to '' (empty string)
     * @returns {RegExp} regular expression; defaults to /.?/
     * @throws {SyntaxError} Throw an error for invalid regex pattern
     */

    var toRegExp = function toRegExp() {
      var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
      var DEFAULT_VALUE = '.?';
      var FORWARD_SLASH = '/';

      if (input === '') {
        return new RegExp(DEFAULT_VALUE);
      }

      if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) {
        return new RegExp(input.slice(1, -1));
      }

      var escaped = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
      return new RegExp(escaped);
    };
    /**
     * Checks whether the input string can be converted to regexp
     * @param {RawStrPattern} input literal string or regexp pattern
     * @returns {boolean}
     */

    var validateStrPattern = function validateStrPattern(input) {
      var FORWARD_SLASH = '/';
      var str = input;

      if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) {
        str = input.slice(1, -1);
      }

      var isValid;

      try {
        isValid = new RegExp(str);
        isValid = true;
      } catch (e) {
        isValid = false;
      }

      return isValid;
    };
    /**
     * Get string before regexp first match
     * @param {string} str
     * @param {RegExp} rx
     */

    var getBeforeRegExp = function getBeforeRegExp(str, rx) {
      var index = str.search(rx);
      return str.substring(0, index);
    };
    /**
     * Checks whether the string starts with the substring
     * @param {string} str full string
     * @param {string} prefix substring
     * @returns {boolean}
     */

    var startsWith = function startsWith(str, prefix) {
      // if str === '', (str && false) will return ''
      // that's why it has to be !!str
      return !!str && str.indexOf(prefix) === 0;
    };
    /**
     * Checks whether the string ends with the substring
     * @param {string} str full string
     * @param {string} ending substring
     * @returns {boolean}
     */

    var endsWith = function endsWith(str, ending) {
      // if str === '', (str && false) will return ''
      // that's why it has to be !!str
      return !!str && str.indexOf(ending) === str.length - ending.length;
    };
    var substringAfter = function substringAfter(str, separator) {
      if (!str) {
        return str;
      }

      var index = str.indexOf(separator);
      return index < 0 ? '' : str.substring(index + separator.length);
    };
    var substringBefore = function substringBefore(str, separator) {
      if (!str || !separator) {
        return str;
      }

      var index = str.indexOf(separator);
      return index < 0 ? str : str.substring(0, index);
    };
    /**
     * Wrap str in single quotes and replaces single quotes to double one
     * @param {string} str
     */

    var wrapInSingleQuotes = function wrapInSingleQuotes(str) {
      if (str[0] === '\'' && str[str.length - 1] === '\'' || str[0] === '"' && str[str.length - 1] === '"') {
        str = str.substring(1, str.length - 1);
      } // eslint-disable-next-line no-useless-escape


      str = str.replace(/\'/g, '"');
      return "'".concat(str, "'");
    };
    /**
     * Returns substring enclosed in the widest braces
     * @param {string} str
     */

    var getStringInBraces = function getStringInBraces(str) {
      var firstIndex = str.indexOf('(');
      var lastIndex = str.lastIndexOf(')');
      return str.substring(firstIndex + 1, lastIndex);
    };
    /**
     * Prepares RTCPeerConnection config as string for proper logging
     * @param {*} config
     * @returns {string} stringified config
    */

    var convertRtcConfigToString = function convertRtcConfigToString(config) {
      var UNDEF_STR = 'undefined';
      var str = UNDEF_STR;

      if (config === null) {
        str = 'null';
      } else if (config instanceof Object) {
        var SERVERS_PROP_NAME = 'iceServers';
        var URLS_PROP_NAME = 'urls';
        /*
            const exampleConfig = {
                'iceServers': [
                    'urls': ['stun:35.66.206.188:443'],
                ],
            };
        */

        if (Object.prototype.hasOwnProperty.call(config, SERVERS_PROP_NAME) && Object.prototype.hasOwnProperty.call(config[SERVERS_PROP_NAME][0], URLS_PROP_NAME) && !!config[SERVERS_PROP_NAME][0][URLS_PROP_NAME]) {
          str = config[SERVERS_PROP_NAME][0][URLS_PROP_NAME].toString();
        }
      }

      return str;
    };
    /**
     * Checks whether the match input string can be converted to regexp,
     * used for match inputs with possible negation
     * @param {string} match literal string or regexp pattern
     * @returns {boolean}
     */

    var validateMatchStr = function validateMatchStr(match) {
      var INVERT_MARKER = '!';
      var str = match;

      if (startsWith(match, INVERT_MARKER)) {
        str = match.slice(1);
      }

      return validateStrPattern(str);
    };
    /**
     * @typedef {Object} MatchData
     * @property {boolean} isInvertedMatch
     * @property {RegExp} matchRegexp
     */

    /**
     * Parses match arg with possible negation for no matching.
     * Needed for prevent-setTimeout, prevent-setInterval,
     * prevent-requestAnimationFrame and prevent-window-open
     * @param {string} match
     * @returns {MatchData|null} data obj or null for invalid regexp pattern
     */

    var parseMatchArg = function parseMatchArg(match) {
      var INVERT_MARKER = '!';
      var isInvertedMatch = startsWith(match, INVERT_MARKER);
      var matchValue = isInvertedMatch ? match.slice(1) : match;
      var matchRegexp = toRegExp(matchValue);
      return {
        isInvertedMatch: isInvertedMatch,
        matchRegexp: matchRegexp
      };
    };
    /**
     * @typedef {Object} DelayData
     * @property {boolean} isInvertedDelayMatch
     * @property {number|null} delayMatch
     */

    /**
     * Parses delay arg with possible negation for no matching.
     * Needed for prevent-setTimeout and prevent-setInterval
     * @param {string} delay
     * @returns {DelayData}
     */

    var parseDelayArg = function parseDelayArg(delay) {
      var INVERT_MARKER = '!';
      var isInvertedDelayMatch = startsWith(delay, INVERT_MARKER);
      var delayValue = isInvertedDelayMatch ? delay.slice(1) : delay;
      delayValue = parseInt(delayValue, 10);
      var delayMatch = nativeIsNaN(delayValue) ? null : delayValue;
      return {
        isInvertedDelayMatch: isInvertedDelayMatch,
        delayMatch: delayMatch
      };
    };
    /**
     * Converts object to string for logging
     * @param {Object} obj data object
     * @returns {string}
     */

    var objectToString = function objectToString(obj) {
      return isEmptyObject(obj) ? '{}' : getObjectEntries(obj).map(function (pair) {
        var key = pair[0];
        var value = pair[1];
        var recordValueStr = value;

        if (value instanceof Object) {
          recordValueStr = "{ ".concat(objectToString(value), " }");
        }

        return "".concat(key, ":\"").concat(recordValueStr, "\"");
      }).join(' ');
    };
    /**
     * Converts types into a string
     * @param {*} value
     * @returns {string}
     */

    var convertTypeToString = function convertTypeToString(value) {
      var output;

      if (typeof value === 'undefined') {
        output = 'undefined';
      } else if (typeof value === 'object') {
        if (value === null) {
          output = 'null';
        } else {
          output = objectToString(value);
        }
      } else {
        output = value.toString();
      }

      return output;
    };

    /**
     * Generates function which silents global errors on page generated by scriptlet
     * If error doesn't belong to our error we transfer it to the native onError handler
     * @param {string} rid - unique identifier of scriptlet
     * @return {onError}
     */
    function createOnErrorHandler(rid) {
      // eslint-disable-next-line consistent-return
      var nativeOnError = window.onerror;
      return function onError(error) {
        if (typeof error === 'string' && error.indexOf(rid) !== -1) {
          return true;
        }

        if (nativeOnError instanceof Function) {
          for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
            args[_key - 1] = arguments[_key];
          }

          return nativeOnError.apply(this, [error].concat(args));
        }

        return false;
      };
    }

    /**
     * Noop function
     * @return {undefined} undefined
     */
    var noopFunc = function noopFunc() {};
    /**
     * Function returns null
     * @return {null} null
     */

    var noopNull = function noopNull() {
      return null;
    };
    /**
     * Function returns true
     * @return {boolean} true
     */

    var trueFunc = function trueFunc() {
      return true;
    };
    /**
     * Function returns false
     * @return {boolean} false
     */

    var falseFunc = function falseFunc() {
      return false;
    };
    /**
     * Function returns this
     */

    function noopThis() {
      return this;
    }
    /**
     * Function returns empty string
     * @return {string} empty string
     */

    var noopStr = function noopStr() {
      return '';
    };
    /**
     * Function returns empty array
     * @return {Array} empty array
     */

    var noopArray = function noopArray() {
      return [];
    };
    /**
     * Function returns empty object
     * @return {Object} empty object
     */

    var noopObject = function noopObject() {
      return {};
    };
    /**
     * Function returns Promise.reject()
     */

    var noopPromiseReject = function noopPromiseReject() {
      return Promise.reject();
    }; // eslint-disable-line compat/compat

    /**
     * Returns Promise object that is resolved with an empty response
     */
    // eslint-disable-next-line compat/compat

    var noopPromiseResolve = function noopPromiseResolve() {
      return Promise.resolve(new Response());
    };

    /* eslint-disable no-console, no-underscore-dangle */

    /**
     * Hit used only for debug purposes now
     * @param {Source} source
     * @param {string} [message] - optional message;
     * use LOG_MARKER = 'log: ' at the start of a message
     * for logging scriptlets
     */
    var hit = function hit(source, message) {
      if (source.verbose !== true) {
        return;
      }

      try {
        var log = console.log.bind(console);
        var trace = console.trace.bind(console); // eslint-disable-line compat/compat

        var prefix = source.ruleText || '';

        if (source.domainName) {
          var AG_SCRIPTLET_MARKER = '#%#//';
          var UBO_SCRIPTLET_MARKER = '##+js';
          var ruleStartIndex;

          if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
            ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
          } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
            ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
          } // delete all domains from ruleText and leave just rule part


          var rulePart = source.ruleText.slice(ruleStartIndex); // prepare applied scriptlet rule for specific domain

          prefix = "".concat(source.domainName).concat(rulePart);
        } // Used to check if scriptlet uses 'hit' function for logging


        var LOG_MARKER = 'log: ';

        if (message) {
          if (message.indexOf(LOG_MARKER) === -1) {
            log("".concat(prefix, " message:\n").concat(message));
          } else {
            log(message.slice(LOG_MARKER.length));
          }
        }

        log("".concat(prefix, " trace start"));

        if (trace) {
          trace();
        }

        log("".concat(prefix, " trace end"));
      } catch (e) {// try catch for Edge 15
        // In according to this issue https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14495220/
        // console.log throws an error
      } // This is necessary for unit-tests only!


      if (typeof window.__debug === 'function') {
        window.__debug(source);
      }
    };

    /**
     * DOM tree changes observer. Used for 'remove-attr' and 'remove-class' scriptlets
     * @param {Function} callback
     * @param {Boolean} observeAttrs - optional parameter - should observer check attributes changes
     */
    var observeDOMChanges = function observeDOMChanges(callback) {
      var observeAttrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
      var attrsToObserve = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];

      /**
       * Returns a wrapper, passing the call to 'method' at maximum once per 'delay' milliseconds.
       * Those calls that fall into the "cooldown" period, are ignored
       * @param {Function} method
       * @param {Number} delay - milliseconds
       */
      var throttle = function throttle(method, delay) {
        var wait = false;
        var savedArgs;

        var wrapper = function wrapper() {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }

          if (wait) {
            savedArgs = args;
            return;
          }

          method.apply(void 0, args);
          wait = true;
          setTimeout(function () {
            wait = false;

            if (savedArgs) {
              wrapper(savedArgs);
              savedArgs = null;
            }
          }, delay);
        };

        return wrapper;
      };
      /**
       * 'delay' in milliseconds for 'throttle' method
       */


      var THROTTLE_DELAY_MS = 20;
      /**
       * Used for remove-class
       */
      // eslint-disable-next-line no-use-before-define, compat/compat

      var observer = new MutationObserver(throttle(callbackWrapper, THROTTLE_DELAY_MS));

      var connect = function connect() {
        if (attrsToObserve.length > 0) {
          observer.observe(document.documentElement, {
            childList: true,
            subtree: true,
            attributes: observeAttrs,
            attributeFilter: attrsToObserve
          });
        } else {
          observer.observe(document.documentElement, {
            childList: true,
            subtree: true,
            attributes: observeAttrs
          });
        }
      };

      var disconnect = function disconnect() {
        observer.disconnect();
      };

      function callbackWrapper() {
        disconnect();
        callback();
        connect();
      }

      connect();
    };

    /**
     * Checks if the stackTrace contains stackRegexp
     * https://github.com/AdguardTeam/Scriptlets/issues/82
     * @param {string|undefined} stackMatch - input stack value to match
     * @param {string} stackTrace - script error stack trace
     * @returns {boolean}
     */

    var matchStackTrace = function matchStackTrace(stackMatch, stackTrace) {
      if (!stackMatch || stackMatch === '') {
        return true;
      }

      var stackRegexp = toRegExp(stackMatch);
      var refinedStackTrace = stackTrace.split('\n').slice(2) // get rid of our own functions in the stack trace
      .map(function (line) {
        return line.trim();
      }) // trim the lines
      .join('\n');
      return stackRegexp.test(refinedStackTrace);
    };

    /**
     * Some browsers do not support Array.prototype.flat()
     * for example, Opera 42 which is used for browserstack tests
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
     * @param {Array} input
     */
    var flatten = function flatten(input) {
      var stack = [];
      input.forEach(function (el) {
        return stack.push(el);
      });
      var res = [];

      while (stack.length) {
        // pop value from stack
        var next = stack.pop();

        if (Array.isArray(next)) {
          // push back array items, won't modify the original input
          next.forEach(function (el) {
            return stack.push(el);
          });
        } else {
          res.push(next);
        }
      } // reverse to restore input order


      return res.reverse();
    };

    /**
     * Finds shadow-dom host (elements with shadowRoot property) in DOM of rootElement.
     * @param {HTMLElement} rootElement
     * @returns {HTMLElement[]} shadow-dom hosts
     */

    var findHostElements = function findHostElements(rootElement) {
      var hosts = []; // Element.querySelectorAll() returns list of elements
      // which are defined in DOM of Element.
      // Meanwhile, inner DOM of the element with shadowRoot property
      // is absolutely another DOM and which can not be reached by querySelectorAll('*')

      var domElems = rootElement.querySelectorAll('*');
      domElems.forEach(function (el) {
        if (el.shadowRoot) {
          hosts.push(el);
        }
      });
      return hosts;
    };
    /**
     * A collection of nodes.
     *
     * @external NodeList
     * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/NodeList NodeList}
     */

    /**
     * @typedef {Object} PierceData
     * @property {HTMLElement[]} targets found elements that match the specified selector
     * @property {HTMLElement[]} innerHosts inner shadow-dom hosts
     */

    /**
     * Pierces open shadow-dom in order to find:
     * - elements by 'selector' matching
     * - inner shadow-dom hosts
     * @param {string} selector
     * @param {HTMLElement[]|external:NodeList} hostElements
     * @returns {PierceData}
     */

    var pierceShadowDom = function pierceShadowDom(selector, hostElements) {
      var targets = [];
      var innerHostsAcc = []; // it's possible to get a few hostElements found by baseSelector on the page

      hostElements.forEach(function (host) {
        // check presence of selector element inside base element if it's not in shadow-dom
        var simpleElems = host.querySelectorAll(selector);
        targets = targets.concat([].slice.call(simpleElems));
        var shadowRootElem = host.shadowRoot;
        var shadowChildren = shadowRootElem.querySelectorAll(selector);
        targets = targets.concat([].slice.call(shadowChildren)); // find inner shadow-dom hosts inside processing shadow-dom

        innerHostsAcc.push(findHostElements(shadowRootElem));
      }); // if there were more than one host element,
      // innerHostsAcc is an array of arrays and should be flatten

      var innerHosts = flatten(innerHostsAcc);
      return {
        targets: targets,
        innerHosts: innerHosts
      };
    };

    /**
     * Prepares cookie string if given parameters are ok
     * @param {string} name cookie name to set
     * @param {string} value cookie value to set
     * @returns {string|null} cookie string if ok OR null if not
     */

    var prepareCookie = function prepareCookie(name, value) {
      if (!name || !value) {
        return null;
      }

      var valueToSet;

      if (value === 'true') {
        valueToSet = 'true';
      } else if (value === 'True') {
        valueToSet = 'True';
      } else if (value === 'false') {
        valueToSet = 'false';
      } else if (value === 'False') {
        valueToSet = 'False';
      } else if (value === 'yes') {
        valueToSet = 'yes';
      } else if (value === 'Yes') {
        valueToSet = 'Yes';
      } else if (value === 'Y') {
        valueToSet = 'Y';
      } else if (value === 'no') {
        valueToSet = 'no';
      } else if (value === 'ok') {
        valueToSet = 'ok';
      } else if (value === 'OK') {
        valueToSet = 'OK';
      } else if (/^\d+$/.test(value)) {
        valueToSet = parseFloat(value);

        if (nativeIsNaN(valueToSet)) {
          return null;
        }

        if (Math.abs(valueToSet) < 0 || Math.abs(valueToSet) > 15) {
          return null;
        }
      } else {
        return null;
      }

      var pathToSet = 'path=/;'; // eslint-disable-next-line max-len

      var cookieData = "".concat(encodeURIComponent(name), "=").concat(encodeURIComponent(valueToSet), "; ").concat(pathToSet);
      return cookieData;
    };

    var shouldMatchAnyDelay = function shouldMatchAnyDelay(delay) {
      return delay === getWildcardSymbol();
    };
    /**
     * Handles input delay value
     * @param {*} delay
     * @returns {number} proper number delay value
     */

    var getMatchDelay = function getMatchDelay(delay) {
      var DEFAULT_DELAY = 1000;
      var parsedDelay = parseInt(delay, 10);
      var delayMatch = nativeIsNaN(parsedDelay) ? DEFAULT_DELAY // default scriptlet value
      : parsedDelay;
      return delayMatch;
    };
    /**
     * Checks delay match condition
     * @param {*} inputDelay
     * @param {number} realDelay
     * @returns {boolean}
     */

    var isDelayMatched = function isDelayMatched(inputDelay, realDelay) {
      return shouldMatchAnyDelay(inputDelay) || realDelay === getMatchDelay(inputDelay);
    };
    /**
     * Handles input boost value
     * @param {*} boost
     * @returns {number} proper number boost multiplier value
     */

    var getBoostMultiplier = function getBoostMultiplier(boost) {
      var DEFAULT_MULTIPLIER = 0.05;
      var MIN_MULTIPLIER = 0.02;
      var MAX_MULTIPLIER = 50;
      var parsedBoost = parseFloat(boost);
      var boostMultiplier = nativeIsNaN(parsedBoost) || !nativeIsFinite(parsedBoost) ? DEFAULT_MULTIPLIER // default scriptlet value
      : parsedBoost;

      if (boostMultiplier < MIN_MULTIPLIER) {
        boostMultiplier = MIN_MULTIPLIER;
      }

      if (boostMultiplier > MAX_MULTIPLIER) {
        boostMultiplier = MAX_MULTIPLIER;
      }

      return boostMultiplier;
    };

    /**
     * Collects Request options to object
     * @param {Request} request
     * @returns {Object} data object
     */

    var getRequestData = function getRequestData(request) {
      var REQUEST_INIT_OPTIONS = ['url', 'method', 'headers', 'body', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity'];
      var entries = REQUEST_INIT_OPTIONS.map(function (key) {
        // if request has no such option, value will be undefined
        var value = request[key];
        return [key, value];
      });
      return getObjectFromEntries(entries);
    };
    /**
     * Collects fetch args to object
     * @param {*} args fetch args
     * @returns {Object} data object
     */

    var getFetchData = function getFetchData(args) {
      var fetchPropsObj = {};
      var fetchUrl;
      var fetchInit;

      if (args[0] instanceof Request) {
        // if Request passed to fetch, it will be in array
        var requestData = getRequestData(args[0]);
        fetchUrl = requestData.url;
        fetchInit = requestData;
      } else {
        fetchUrl = args[0]; // eslint-disable-line prefer-destructuring

        fetchInit = args[1]; // eslint-disable-line prefer-destructuring
      }

      fetchPropsObj.url = fetchUrl;

      if (fetchInit instanceof Object) {
        Object.keys(fetchInit).forEach(function (prop) {
          fetchPropsObj[prop] = fetchInit[prop];
        });
      }

      return fetchPropsObj;
    };
    /**
     * Parse propsToMatch input string into object;
     * used for prevent-fetch and prevent-xhr
     * @param {string} propsToMatchStr
     * @returns {Object} object where 'key' is prop name and 'value' is prop value
     */

    var parseMatchProps = function parseMatchProps(propsToMatchStr) {
      var PROPS_DIVIDER = ' ';
      var PAIRS_MARKER = ':';
      var propsObj = {};
      var props = propsToMatchStr.split(PROPS_DIVIDER);
      props.forEach(function (prop) {
        var dividerInd = prop.indexOf(PAIRS_MARKER);

        if (dividerInd === -1) {
          propsObj.url = prop;
        } else {
          var key = prop.slice(0, dividerInd);
          var value = prop.slice(dividerInd + 1);
          propsObj[key] = value;
        }
      });
      return propsObj;
    };
    /**
     * Validates parsed data values
     * @param {Object} data
     * @returns {boolean}
     */

    var validateParsedData = function validateParsedData(data) {
      return Object.values(data).every(function (value) {
        return validateStrPattern(value);
      });
    };
    /**
     * Converts valid parsed data to data obj for further matching
     * @param {Object} data
     * @returns {Object}
     */

    var getMatchPropsData = function getMatchPropsData(data) {
      var matchData = {};
      Object.keys(data).forEach(function (key) {
        matchData[key] = toRegExp(data[key]);
      });
      return matchData;
    };

    var handleOldReplacement = function handleOldReplacement(replacement) {
      var result; // defaults to return noopFunc instead of window.open

      if (!replacement) {
        result = noopFunc;
      } else if (replacement === 'trueFunc') {
        result = trueFunc;
      } else if (replacement.indexOf('=') > -1) {
        // We should return noopFunc instead of window.open
        // but with some property if website checks it (examples 5, 6)
        // https://github.com/AdguardTeam/Scriptlets/issues/71
        var isProp = startsWith(replacement, '{') && endsWith(replacement, '}');

        if (isProp) {
          var propertyPart = replacement.slice(1, -1);
          var propertyName = substringBefore(propertyPart, '=');
          var propertyValue = substringAfter(propertyPart, '=');

          if (propertyValue === 'noopFunc') {
            result = {};
            result[propertyName] = noopFunc;
          }
        }
      }

      return result;
    };
    var createDecoy = function createDecoy(args) {
      var OBJECT_TAG_NAME = 'object';
      var OBJECT_URL_PROP_NAME = 'data';
      var IFRAME_TAG_NAME = 'iframe';
      var IFRAME_URL_PROP_NAME = 'src';
      var replacement = args.replacement,
          url = args.url,
          delay = args.delay;
      var tag;
      var urlProp;

      if (replacement === 'obj') {
        tag = OBJECT_TAG_NAME;
        urlProp = OBJECT_URL_PROP_NAME;
      } else {
        tag = IFRAME_TAG_NAME;
        urlProp = IFRAME_URL_PROP_NAME;
      }

      var decoy = document.createElement(tag);
      decoy[urlProp] = url;
      decoy.style.setProperty('height', '1px', 'important');
      decoy.style.setProperty('position', 'fixed', 'important');
      decoy.style.setProperty('top', '-1px', 'important');
      decoy.style.setProperty('width', '1px', 'important');
      document.body.appendChild(decoy);
      setTimeout(function () {
        return decoy.remove();
      }, delay * 1000);
      return decoy;
    };
    var getPreventGetter = function getPreventGetter(nativeGetter) {
      var preventGetter = function preventGetter(target, prop) {
        if (prop && prop === 'closed') {
          return false;
        }

        if (typeof nativeGetter === 'function') {
          return noopFunc;
        }

        return prop && target[prop];
      };

      return preventGetter;
    };

    /**
     * Validates event type
     * @param {*} type
     * @returns {boolean}
     */
    var validateType = function validateType(type) {
      // https://github.com/AdguardTeam/Scriptlets/issues/125
      return typeof type !== 'undefined';
    };
    /**
     * Validates event listener
     * @param {*} listener
     * @returns {boolean}
     */

    var validateListener = function validateListener(listener) {
      // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters
      return typeof listener !== 'undefined' && (typeof listener === 'function' || typeof listener === 'object' // https://github.com/AdguardTeam/Scriptlets/issues/76
      && listener !== null && typeof listener.handleEvent === 'function');
    };
    /**
     * Serialize valid event listener
     * https://developer.mozilla.org/en-US/docs/Web/API/EventListener
     * @param {EventListener} listener valid listener
     * @returns {string}
     */

    var listenerToString = function listenerToString(listener) {
      return typeof listener === 'function' ? listener.toString() : listener.handleEvent.toString();
    };

    /**
     * This file must export all used dependencies
     */

    var dependencies = /*#__PURE__*/Object.freeze({
        __proto__: null,
        getWildcardSymbol: getWildcardSymbol,
        randomId: randomId,
        setPropertyAccess: setPropertyAccess,
        getPropertyInChain: getPropertyInChain,
        getWildcardPropertyInChain: getWildcardPropertyInChain,
        replaceAll: replaceAll,
        escapeRegExp: escapeRegExp,
        toRegExp: toRegExp,
        validateStrPattern: validateStrPattern,
        getBeforeRegExp: getBeforeRegExp,
        startsWith: startsWith,
        endsWith: endsWith,
        substringAfter: substringAfter,
        substringBefore: substringBefore,
        wrapInSingleQuotes: wrapInSingleQuotes,
        getStringInBraces: getStringInBraces,
        convertRtcConfigToString: convertRtcConfigToString,
        validateMatchStr: validateMatchStr,
        parseMatchArg: parseMatchArg,
        parseDelayArg: parseDelayArg,
        objectToString: objectToString,
        convertTypeToString: convertTypeToString,
        createOnErrorHandler: createOnErrorHandler,
        noopFunc: noopFunc,
        noopNull: noopNull,
        trueFunc: trueFunc,
        falseFunc: falseFunc,
        noopThis: noopThis,
        noopStr: noopStr,
        noopArray: noopArray,
        noopObject: noopObject,
        noopPromiseReject: noopPromiseReject,
        noopPromiseResolve: noopPromiseResolve,
        hit: hit,
        observeDOMChanges: observeDOMChanges,
        matchStackTrace: matchStackTrace,
        findHostElements: findHostElements,
        pierceShadowDom: pierceShadowDom,
        flatten: flatten,
        prepareCookie: prepareCookie,
        nativeIsNaN: nativeIsNaN,
        nativeIsFinite: nativeIsFinite,
        getNumberFromString: getNumberFromString,
        shouldMatchAnyDelay: shouldMatchAnyDelay,
        getMatchDelay: getMatchDelay,
        isDelayMatched: isDelayMatched,
        getBoostMultiplier: getBoostMultiplier,
        getRequestData: getRequestData,
        getFetchData: getFetchData,
        parseMatchProps: parseMatchProps,
        validateParsedData: validateParsedData,
        getMatchPropsData: getMatchPropsData,
        getObjectEntries: getObjectEntries,
        getObjectFromEntries: getObjectFromEntries,
        isEmptyObject: isEmptyObject,
        safeGetDescriptor: safeGetDescriptor,
        handleOldReplacement: handleOldReplacement,
        createDecoy: createDecoy,
        getPreventGetter: getPreventGetter,
        validateType: validateType,
        validateListener: validateListener,
        listenerToString: listenerToString
    });

    /**
     * Concat dependencies to scriptlet code
     * @param {string} scriptlet string view of scriptlet
     */

    function attachDependencies(scriptlet) {
      var _scriptlet$injections = scriptlet.injections,
          injections = _scriptlet$injections === void 0 ? [] : _scriptlet$injections; // eslint-disable-next-line max-len

      return injections.reduce(function (accum, dep) {
        return "".concat(accum, "\n").concat(dependencies[dep.name]);
      }, scriptlet.toString());
    }
    /**
     * Add scriptlet call to existing code
     * @param {Function} scriptlet
     * @param {string} code
     */

    function addCall(scriptlet, code) {
      return "".concat(code, ";\n        const updatedArgs = args ? [].concat(source).concat(args) : [source];\n        try {\n            ").concat(scriptlet.name, ".apply(this, updatedArgs);\n        } catch (e) {\n            console.log(e);\n        }\n    ");
    }
    /**
     * Wrap function into IIFE (Immediately invoked function expression)
     *
     * @param {Source} source - object with scriptlet properties
     * @param {string} code - scriptlet source code with dependencies
     *
     * @returns {string} full scriptlet code
     *
     * @example
     * const source = {
     *      args: ["aaa", "bbb"],
     *      name: 'noeval',
     * };
     * const code = "function noeval(source, args) { alert(source); } noeval.apply(this, args);"
     * const result = wrapInIIFE(source, code);
     *
     * // result
     * `(function(source, args) {
     *      function noeval(source) { alert(source); }
     *      noeval.apply(this, args);
     * )({"args": ["aaa", "bbb"], "name":"noeval"}, ["aaa", "bbb"])`
     */

    function passSourceAndProps(source, code) {
      if (source.hit) {
        source.hit = source.hit.toString();
      }

      var sourceString = JSON.stringify(source);
      var argsString = source.args ? "[".concat(source.args.map(JSON.stringify), "]") : undefined;
      var params = argsString ? "".concat(sourceString, ", ").concat(argsString) : sourceString;
      return "(function(source, args){\n".concat(code, "\n})(").concat(params, ");");
    }
    /**
     * Wrap code in no name function
     * @param {string} code which must be wrapped
     */

    function wrapInNonameFunc(code) {
      return "function(source, args){\n".concat(code, "\n}");
    }

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

      return obj;
    }

    var defineProperty = _defineProperty;

    /**
     * Iterate over iterable argument and evaluate current state with transitions
     * @param {string} init first transition name
     * @param {Array|Collection|string} iterable
     * @param {Object} transitions transtion functions
     * @param {any} args arguments which should be passed to transition functions
     */
    function iterateWithTransitions(iterable, transitions, init, args) {
      var state = init || Object.keys(transitions)[0];

      for (var i = 0; i < iterable.length; i += 1) {
        state = transitions[state](iterable, i, args);
      }

      return state;
    }
    /**
     * AdGuard scriptlet rule mask
     */


    var ADG_SCRIPTLET_MASK = '#//scriptlet';
    /**
     * Helper to accumulate an array of strings char by char
     */

    var wordSaver = function wordSaver() {
      var str = '';
      var strs = [];

      var saveSymb = function saveSymb(s) {
        str += s;
        return str;
      };

      var saveStr = function saveStr() {
        strs.push(str);
        str = '';
      };

      var getAll = function getAll() {
        return [].concat(strs);
      };

      return {
        saveSymb: saveSymb,
        saveStr: saveStr,
        getAll: getAll
      };
    };

    var substringAfter$1 = function substringAfter(str, separator) {
      if (!str) {
        return str;
      }

      var index = str.indexOf(separator);
      return index < 0 ? '' : str.substring(index + separator.length);
    };
    /**
     * Parse and validate scriptlet rule
     * @param {*} ruleText
     * @returns {{name: string, args: Array<string>}}
     */


    var parseRule = function parseRule(ruleText) {
      var _transitions;

      ruleText = substringAfter$1(ruleText, ADG_SCRIPTLET_MASK);
      /**
       * Transition names
       */

      var TRANSITION = {
        OPENED: 'opened',
        PARAM: 'param',
        CLOSED: 'closed'
      };
      /**
       * Transition function: the current index position in start, end or between params
       * @param {string} rule
       * @param {number} index
       * @param {Object} Object
       * @property {Object} Object.sep contains prop symb with current separator char
       */

      var opened = function opened(rule, index, _ref) {
        var sep = _ref.sep;
        var char = rule[index];
        var transition;

        switch (char) {
          case ' ':
          case '(':
          case ',':
            {
              transition = TRANSITION.OPENED;
              break;
            }

          case '\'':
          case '"':
            {
              sep.symb = char;
              transition = TRANSITION.PARAM;
              break;
            }

          case ')':
            {
              transition = index === rule.length - 1 ? TRANSITION.CLOSED : TRANSITION.OPENED;
              break;
            }

          default:
            {
              throw new Error('The rule is not a scriptlet');
            }
        }

        return transition;
      };
      /**
       * Transition function: the current index position inside param
       * @param {string} rule
       * @param {number} index
       * @param {Object} Object
       * @property {Object} Object.sep contains prop `symb` with current separator char
       * @property {Object} Object.saver helper which allow to save strings by car by char
       */


      var param = function param(rule, index, _ref2) {
        var saver = _ref2.saver,
            sep = _ref2.sep;
        var char = rule[index];

        switch (char) {
          case '\'':
          case '"':
            {
              var preIndex = index - 1;
              var before = rule[preIndex];

              if (char === sep.symb && before !== '\\') {
                sep.symb = null;
                saver.saveStr();
                return TRANSITION.OPENED;
              }
            }
          // eslint-disable-next-line no-fallthrough

          default:
            {
              saver.saveSymb(char);
              return TRANSITION.PARAM;
            }
        }
      };

      var transitions = (_transitions = {}, defineProperty(_transitions, TRANSITION.OPENED, opened), defineProperty(_transitions, TRANSITION.PARAM, param), defineProperty(_transitions, TRANSITION.CLOSED, function () {}), _transitions);
      var sep = {
        symb: null
      };
      var saver = wordSaver();
      var state = iterateWithTransitions(ruleText, transitions, TRANSITION.OPENED, {
        sep: sep,
        saver: saver
      });

      if (state !== 'closed') {
        throw new Error("Invalid scriptlet rule ".concat(ruleText));
      }

      var args = saver.getAll();
      return {
        name: args[0],
        args: args.slice(1)
      };
    };

    /* eslint-disable max-len */

    /**
     * @scriptlet abort-on-property-read
     *
     * @description
     * Aborts a script when it attempts to **read** the specified property.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#abort-on-property-readjs-
     *
     * Related ABP source:
     * https://github.com/adblockplus/adblockpluscore/blob/6b2a309054cc23432102b85d13f12559639ef495/lib/content/snippets.js#L864
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('abort-on-property-read', property)
     * ```
     *
     * - `property` - required, path to a property (joined with `.` if needed). The property must be attached to `window`
     *
     * **Examples**
     * ```
     * ! Aborts script when it tries to access `window.alert`
     * example.org#%#//scriptlet('abort-on-property-read', 'alert')
     *
     * ! Aborts script when it tries to access `navigator.language`
     * example.org#%#//scriptlet('abort-on-property-read', 'navigator.language')
     * ```
     */

    /* eslint-enable max-len */

    function abortOnPropertyRead(source, property) {
      if (!property) {
        return;
      }

      var rid = randomId();

      var abort = function abort() {
        hit(source);
        throw new ReferenceError(rid);
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        setPropertyAccess(base, prop, {
          get: abort,
          set: function set() {}
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    abortOnPropertyRead.names = ['abort-on-property-read', // aliases are needed for matching the related scriptlet converted into our syntax
    'abort-on-property-read.js', 'ubo-abort-on-property-read.js', 'aopr.js', 'ubo-aopr.js', 'ubo-abort-on-property-read', 'ubo-aopr', 'abp-abort-on-property-read'];
    abortOnPropertyRead.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet abort-on-property-write
     *
     * @description
     * Aborts a script when it attempts to **write** the specified property.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#abort-on-property-writejs-
     *
     * Related ABP source:
     * https://github.com/adblockplus/adblockpluscore/blob/6b2a309054cc23432102b85d13f12559639ef495/lib/content/snippets.js#L896
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('abort-on-property-write', property)
     * ```
     *
     * - `property` - required, path to a property (joined with `.` if needed). The property must be attached to `window`
     *
     * **Examples**
     * ```
     * ! Aborts script when it tries to set `window.adblock` value
     * example.org#%#//scriptlet('abort-on-property-write', 'adblock')
     * ```
     */

    /* eslint-enable max-len */

    function abortOnPropertyWrite(source, property) {
      if (!property) {
        return;
      }

      var rid = randomId();

      var abort = function abort() {
        hit(source);
        throw new ReferenceError(rid);
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        setPropertyAccess(base, prop, {
          set: abort
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    abortOnPropertyWrite.names = ['abort-on-property-write', // aliases are needed for matching the related scriptlet converted into our syntax
    'abort-on-property-write.js', 'ubo-abort-on-property-write.js', 'aopw.js', 'ubo-aopw.js', 'ubo-abort-on-property-write', 'ubo-aopw', 'abp-abort-on-property-write'];
    abortOnPropertyWrite.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-setTimeout
     *
     * @description
     * Prevents a `setTimeout` call if:
     * 1) the text of the callback is matching the specified search string/regexp which does not start with `!`;
     * otherwise mismatched calls should be defused;
     * 2) the timeout is matching the specified delay; otherwise mismatched calls should be defused.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#no-settimeout-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-setTimeout'[, search[, delay]])
     * ```
     *
     * Call with no arguments will log calls to setTimeout while debugging (`log-setTimeout` superseding),
     * so production filter lists' rules definitely require at least one of the parameters:
     * - `search` - optional, string or regular expression; invalid regular expression will be skipped and all callbacks will be matched.
     * If starts with `!`, scriptlet will not match the stringified callback but all other will be defused.
     * If do not start with `!`, the stringified callback will be matched.
     * If not set, prevents all `setTimeout` calls due to specified `delay`.
     * - `delay` - optional, must be an integer.
     * If starts with `!`, scriptlet will not match the delay but all other will be defused.
     * If do not start with `!`, the delay passed to the `setTimeout` call will be matched.
     *
     * > If `prevent-setTimeout` without parameters logs smth like `setTimeout(undefined, 1000)`,
     * it means that no callback was passed to setTimeout() and that's not scriptlet issue
     *
     * **Examples**
     * 1. Prevents `setTimeout` calls if the callback matches `/\.test/` regardless of the delay.
     *     ```bash
     *     example.org#%#//scriptlet('prevent-setTimeout', '/\.test/')
     *     ```
     *
     *     For instance, the following call will be prevented:
     *     ```javascript
     *     setTimeout(function () {
     *         window.test = "value";
     *     }, 100);
     *     ```
     *
     * 2. Prevents `setTimeout` calls if the callback does not contain `value`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setTimeout', '!value')
     *     ```
     *
     *     For instance, only the first of the following calls will be prevented:
     *     ```javascript
     *     setTimeout(function () {
     *         window.test = "test -- prevented";
     *     }, 300);
     *     setTimeout(function () {
     *         window.test = "value -- executed";
     *     }, 400);
     *     setTimeout(function () {
     *         window.value = "test -- executed";
     *     }, 500);
     *     ```
     *
     * 3. Prevents `setTimeout` calls if the callback contains `value` and the delay is not set to `300`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setTimeout', 'value', '!300')
     *     ```
     *
     *     For instance, only the first of the following calls will not be prevented:
     *     ```javascript
     *     setTimeout(function () {
     *         window.test = "value 1 -- executed";
     *     }, 300);
     *     setTimeout(function () {
     *         window.test = "value 2 -- prevented";
     *     }, 400);
     *     setTimeout(function () {
     *         window.test = "value 3 -- prevented";
     *     }, 500);
     *     ```
     *
     * 4. Prevents `setTimeout` calls if the callback does not contain `value` and the delay is not set to `300`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setTimeout', '!value', '!300')
     *     ```
     *
     *     For instance, only the second of the following calls will be prevented:
     *     ```javascript
     *     setTimeout(function () {
     *         window.test = "test -- executed";
     *     }, 300);
     *     setTimeout(function () {
     *         window.test = "test -- prevented";
     *     }, 400);
     *     setTimeout(function () {
     *         window.test = "value -- executed";
     *     }, 400);
     *     setTimeout(function () {
     *         window.value = "test -- executed";
     *     }, 500);
     *     ```
     */

    /* eslint-enable max-len */

    function preventSetTimeout(source, match, delay) {
      // if browser does not support Proxy (e.g. Internet Explorer),
      // we use none-proxy "legacy" wrapper for preventing
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
      var isProxySupported = typeof Proxy !== 'undefined';
      var nativeTimeout = window.setTimeout;
      var log = console.log.bind(console); // eslint-disable-line no-console
      // logs setTimeouts to console if no arguments have been specified

      var shouldLog = typeof match === 'undefined' && typeof delay === 'undefined';

      var _parseMatchArg = parseMatchArg(match),
          isInvertedMatch = _parseMatchArg.isInvertedMatch,
          matchRegexp = _parseMatchArg.matchRegexp;

      var _parseDelayArg = parseDelayArg(delay),
          isInvertedDelayMatch = _parseDelayArg.isInvertedDelayMatch,
          delayMatch = _parseDelayArg.delayMatch;

      var getShouldPrevent = function getShouldPrevent(callbackStr, timeout) {
        var shouldPrevent = false;

        if (!delayMatch) {
          shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch;
        } else if (!match) {
          shouldPrevent = timeout === delayMatch !== isInvertedDelayMatch;
        } else {
          shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch && timeout === delayMatch !== isInvertedDelayMatch;
        }

        return shouldPrevent;
      };

      var legacyTimeoutWrapper = function legacyTimeoutWrapper(callback, timeout) {
        var shouldPrevent = false; // https://github.com/AdguardTeam/Scriptlets/issues/105

        var cbString = String(callback);

        if (shouldLog) {
          hit(source);
          log("setTimeout(".concat(cbString, ", ").concat(timeout, ")"));
        } else {
          shouldPrevent = getShouldPrevent(cbString, timeout);
        }

        if (shouldPrevent) {
          hit(source);
          return nativeTimeout(noopFunc, timeout);
        }

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

        return nativeTimeout.apply(window, [callback, timeout].concat(args));
      };

      var handlerWrapper = function handlerWrapper(target, thisArg, args) {
        var callback = args[0];
        var timeout = args[1];
        var shouldPrevent = false; // https://github.com/AdguardTeam/Scriptlets/issues/105

        var cbString = String(callback);

        if (shouldLog) {
          hit(source);
          log("setTimeout(".concat(cbString, ", ").concat(timeout, ")"));
        } else {
          shouldPrevent = getShouldPrevent(cbString, timeout);
        }

        if (shouldPrevent) {
          hit(source);
          args[0] = noopFunc;
        }

        return target.apply(thisArg, args);
      };

      var setTimeoutHandler = {
        apply: handlerWrapper
      };
      window.setTimeout = isProxySupported ? new Proxy(window.setTimeout, setTimeoutHandler) : legacyTimeoutWrapper;
    }
    preventSetTimeout.names = ['prevent-setTimeout', // aliases are needed for matching the related scriptlet converted into our syntax
    'no-setTimeout-if.js', // new implementation of setTimeout-defuser.js
    'ubo-no-setTimeout-if.js', 'nostif.js', // new short name of no-setTimeout-if
    'ubo-nostif.js', 'ubo-no-setTimeout-if', 'ubo-nostif', // old scriptlet names which should be supported as well.
    // should be removed eventually.
    // do not remove until other filter lists maintainers use them
    'setTimeout-defuser.js', 'ubo-setTimeout-defuser.js', 'ubo-setTimeout-defuser', 'std.js', 'ubo-std.js', 'ubo-std'];
    preventSetTimeout.injections = [hit, noopFunc, parseMatchArg, parseDelayArg, toRegExp, startsWith, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-setInterval
     *
     * @description
     * Prevents a `setInterval` call if:
     * 1) the text of the callback is matching the specified `search` string/regexp which does not start with `!`;
     * otherwise mismatched calls should be defused;
     * 2) the interval is matching the specified `delay`; otherwise mismatched calls should be defused.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#no-setinterval-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-setInterval'[, search[, delay]])
     * ```
     *
     * Call with no arguments will log calls to setInterval while debugging (`log-setInterval` superseding),
     * so production filter lists' rules definitely require at least one of the parameters:
     * - `search` - optional, string or regular expression; invalid regular expression will be skipped and all callbacks will be matched.
     * If starts with `!`, scriptlet will not match the stringified callback but all other will be defused.
     * If do not start with `!`, the stringified callback will be matched.
     * If not set, prevents all `setInterval` calls due to specified `delay`.
     * - `delay` - optional, must be an integer.
     * If starts with `!`, scriptlet will not match the delay but all other will be defused.
     * If do not start with `!`, the delay passed to the `setInterval` call will be matched.
     *
     * > If `prevent-setInterval` without parameters logs smth like `setInterval(undefined, 1000)`,
     * it means that no callback was passed to setInterval() and that's not scriptlet issue

     *  **Examples**
     * 1. Prevents `setInterval` calls if the callback matches `/\.test/` regardless of the delay.
     *     ```bash
     *     example.org#%#//scriptlet('prevent-setInterval', '/\.test/')
     *     ```
     *
     *     For instance, the following call will be prevented:
     *     ```javascript
     *     setInterval(function () {
     *         window.test = "value";
     *     }, 100);
     *     ```
     *
     * 2. Prevents `setInterval` calls if the callback does not contain `value`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setInterval', '!value')
     *     ```
     *
     *     For instance, only the first of the following calls will be prevented:
     *     ```javascript
     *     setInterval(function () {
     *         window.test = "test -- prevented";
     *     }, 300);
     *     setInterval(function () {
     *         window.test = "value -- executed";
     *     }, 400);
     *     setInterval(function () {
     *         window.value = "test -- executed";
     *     }, 500);
     *     ```
     *
     * 3. Prevents `setInterval` calls if the callback contains `value` and the delay is not set to `300`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setInterval', 'value', '!300')
     *     ```
     *
     *     For instance, only the first of the following calls will not be prevented:
     *     ```javascript
     *     setInterval(function () {
     *         window.test = "value 1 -- executed";
     *     }, 300);
     *     setInterval(function () {
     *         window.test = "value 2 -- prevented";
     *     }, 400);
     *     setInterval(function () {
     *         window.test = "value 3 -- prevented";
     *     }, 500);
     *     ```
     *
     * 4. Prevents `setInterval` calls if the callback does not contain `value` and the delay is not set to `300`.
     *     ```
     *     example.org#%#//scriptlet('prevent-setInterval', '!value', '!300')
     *     ```
     *
     *     For instance, only the second of the following calls will be prevented:
     *     ```javascript
     *     setInterval(function () {
     *         window.test = "test -- executed";
     *     }, 300);
     *     setInterval(function () {
     *         window.test = "test -- prevented";
     *     }, 400);
     *     setInterval(function () {
     *         window.test = "value -- executed";
     *     }, 400);
     *     setInterval(function () {
     *         window.value = "test -- executed";
     *     }, 500);
     *     ```
     */

    /* eslint-enable max-len */

    function preventSetInterval(source, match, delay) {
      // if browser does not support Proxy (e.g. Internet Explorer),
      // we use none-proxy "legacy" wrapper for preventing
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
      var isProxySupported = typeof Proxy !== 'undefined';
      var nativeInterval = window.setInterval;
      var log = console.log.bind(console); // eslint-disable-line no-console
      // logs setIntervals to console if no arguments have been specified

      var shouldLog = typeof match === 'undefined' && typeof delay === 'undefined';

      var _parseMatchArg = parseMatchArg(match),
          isInvertedMatch = _parseMatchArg.isInvertedMatch,
          matchRegexp = _parseMatchArg.matchRegexp;

      var _parseDelayArg = parseDelayArg(delay),
          isInvertedDelayMatch = _parseDelayArg.isInvertedDelayMatch,
          delayMatch = _parseDelayArg.delayMatch;

      var getShouldPrevent = function getShouldPrevent(callbackStr, interval) {
        var shouldPrevent = false;

        if (!delayMatch) {
          shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch;
        } else if (!match) {
          shouldPrevent = interval === delayMatch !== isInvertedDelayMatch;
        } else {
          shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch && interval === delayMatch !== isInvertedDelayMatch;
        }

        return shouldPrevent;
      };

      var legacyIntervalWrapper = function legacyIntervalWrapper(callback, interval) {
        var shouldPrevent = false; // https://github.com/AdguardTeam/Scriptlets/issues/105

        var cbString = String(callback);

        if (shouldLog) {
          hit(source);
          log("setInterval(".concat(cbString, ", ").concat(interval, ")"));
        } else {
          shouldPrevent = getShouldPrevent(cbString, interval);
        }

        if (shouldPrevent) {
          hit(source);
          return nativeInterval(noopFunc, interval);
        }

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

        return nativeInterval.apply(window, [callback, interval].concat(args));
      };

      var handlerWrapper = function handlerWrapper(target, thisArg, args) {
        var callback = args[0];
        var interval = args[1];
        var shouldPrevent = false; // https://github.com/AdguardTeam/Scriptlets/issues/105

        var cbString = String(callback);

        if (shouldLog) {
          hit(source);
          log("setInterval(".concat(cbString, ", ").concat(interval, ")"));
        } else {
          shouldPrevent = getShouldPrevent(cbString, interval);
        }

        if (shouldPrevent) {
          hit(source);
          args[0] = noopFunc;
        }

        return target.apply(thisArg, args);
      };

      var setIntervalHandler = {
        apply: handlerWrapper
      };
      window.setInterval = isProxySupported ? new Proxy(window.setInterval, setIntervalHandler) : legacyIntervalWrapper;
    }
    preventSetInterval.names = ['prevent-setInterval', // aliases are needed for matching the related scriptlet converted into our syntax
    'no-setInterval-if.js', // new implementation of setInterval-defuser.js
    'ubo-no-setInterval-if.js', 'setInterval-defuser.js', // old name should be supported as well
    'ubo-setInterval-defuser.js', 'nosiif.js', // new short name of no-setInterval-if
    'ubo-nosiif.js', 'sid.js', // old short scriptlet name
    'ubo-sid.js', 'ubo-no-setInterval-if', 'ubo-setInterval-defuser', 'ubo-nosiif', 'ubo-sid'];
    preventSetInterval.injections = [hit, noopFunc, parseMatchArg, parseDelayArg, toRegExp, startsWith, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-window-open
     *
     * @description
     * Prevents `window.open` calls when URL either matches or not matches the specified string/regexp. Using it without parameters prevents all `window.open` calls.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#windowopen-defuserjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-window-open'[, match[, delay[, replacement]]])
     * ```
     *
     * - `match` - optional, string or regular expression. If not set or regular expression is invalid, all window.open calls will be matched.
     * If starts with `!`, scriptlet will not match the stringified callback but all other will be defused.
     * If do not start with `!`, the stringified callback will be matched.
     * - `delay` - optional, number of seconds. If not set, scriptlet will return `null`,
     * otherwise valid sham window object as injected `iframe` will be returned
     * for accessing its methods (blur(), focus() etc.) and will be removed after the delay.
     * - `replacement` - optional, string; one of the predefined constants:
     *     - `obj` - for returning an object instead of default iframe;
     *        for cases when the page requires a valid `window` instance to be returned
     *     - `log` - for logging window.open calls; permitted for production filter lists.
     *
     * **Examples**
     * 1. Prevent all `window.open` calls:
     * ```
     *     example.org#%#//scriptlet('prevent-window-open')
     * ```
     *
     * 2. Prevent `window.open` for all URLs containing `example`:
     * ```
     *     example.org#%#//scriptlet('prevent-window-open', 'example')
     * ```
     *
     * 3. Prevent `window.open` for all URLs matching RegExp `/example\./`:
     * ```
     *     example.org#%#//scriptlet('prevent-window-open', '/example\./')
     * ```
     *
     * 4. Prevent `window.open` for all URLs **NOT** containing `example`:
     * ```
     *     example.org#%#//scriptlet('prevent-window-open', '!example')
     * ```
     *
     * Old syntax of prevent-window-open parameters:
     * - `match` - optional, defaults to "matching", any positive number or nothing for "matching", 0 or empty string for "not matching"
     * - `search` - optional, string or regexp for matching the URL passed to `window.open` call; defaults to search all `window.open` call
     * - `replacement` - optional, string to return prop value or property instead of window.open; defaults to return noopFunc.
     * **Examples**
     * ```
     *     example.org#%#//scriptlet('prevent-window-open', '1', '/example\./')
     *     example.org#%#//scriptlet('prevent-window-open', '0', 'example')
     *     example.org#%#//scriptlet('prevent-window-open', '', '', 'trueFunc')
     *     example.org#%#//scriptlet('prevent-window-open', '1', '', '{propName=noopFunc}')
     * ```
     *
     * > For better compatibility with uBO, old syntax is not recommended to use.
     */

    /* eslint-enable max-len */

    function preventWindowOpen(source) {
      var match = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getWildcardSymbol();
      var delay = arguments.length > 2 ? arguments[2] : undefined;
      var replacement = arguments.length > 3 ? arguments[3] : undefined;
      // default match value is needed for preventing all window.open calls
      // if scriptlet runs without args
      var nativeOpen = window.open;
      var isNewSyntax = match !== '0' && match !== '1';

      var oldOpenWrapper = function oldOpenWrapper(str) {
        match = Number(match) > 0; // 'delay' was 'search' prop for matching in old syntax

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

        if (!validateStrPattern(delay)) {
          // eslint-disable-next-line no-console
          console.log("Invalid parameter: ".concat(delay));
          return nativeOpen.apply(window, [str].concat(args));
        }

        var searchRegexp = toRegExp(delay);

        if (match !== searchRegexp.test(str)) {
          return nativeOpen.apply(window, [str].concat(args));
        }

        hit(source);
        return handleOldReplacement(replacement);
      };

      var newOpenWrapper = function newOpenWrapper(url) {
        var shouldLog = replacement && replacement.indexOf('log') > -1;

        for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
          args[_key2 - 1] = arguments[_key2];
        }

        if (shouldLog) {
          var argsStr = args && args.length > 0 ? ", ".concat(args.join(', ')) : '';
          var logMessage = "log: window-open: ".concat(url).concat(argsStr);
          hit(source, logMessage);
        }

        var shouldPrevent = false;

        if (match === getWildcardSymbol()) {
          shouldPrevent = true;
        } else if (validateMatchStr(match)) {
          var _parseMatchArg = parseMatchArg(match),
              isInvertedMatch = _parseMatchArg.isInvertedMatch,
              matchRegexp = _parseMatchArg.matchRegexp;

          shouldPrevent = matchRegexp.test(url) !== isInvertedMatch;
        } else {
          // eslint-disable-next-line no-console
          console.log("Invalid parameter: ".concat(match));
          shouldPrevent = false;
        }

        if (shouldPrevent) {
          var parsedDelay = parseInt(delay, 10);
          var result;

          if (nativeIsNaN(parsedDelay)) {
            result = noopNull();
          } else {
            var decoyArgs = {
              replacement: replacement,
              url: url,
              delay: parsedDelay
            };
            var decoy = createDecoy(decoyArgs);
            var popup = decoy.contentWindow;

            if (typeof popup === 'object' && popup !== null) {
              Object.defineProperty(popup, 'closed', {
                value: false
              });
              Object.defineProperty(popup, 'opener', {
                value: window
              });
              Object.defineProperty(popup, 'frameElement', {
                value: null
              });
            } else {
              var nativeGetter = decoy.contentWindow && decoy.contentWindow.get;
              Object.defineProperty(decoy, 'contentWindow', {
                get: getPreventGetter(nativeGetter)
              });
              popup = decoy.contentWindow;
            }

            result = popup;
          }

          hit(source);
          return result;
        }

        return nativeOpen.apply(window, [url].concat(args));
      };

      window.open = isNewSyntax ? newOpenWrapper : oldOpenWrapper; // Protect window.open from native code check

      window.open.toString = nativeOpen.toString.bind(nativeOpen);
    }
    preventWindowOpen.names = ['prevent-window-open', // aliases are needed for matching the related scriptlet converted into our syntax
    'window.open-defuser.js', 'ubo-window.open-defuser.js', 'ubo-window.open-defuser', 'nowoif.js', 'ubo-nowoif.js', 'ubo-nowoif'];
    preventWindowOpen.injections = [hit, validateStrPattern, validateMatchStr, toRegExp, nativeIsNaN, parseMatchArg, handleOldReplacement, createDecoy, getPreventGetter, noopNull, getWildcardSymbol, noopFunc, trueFunc, startsWith, endsWith, substringBefore, substringAfter];

    /* eslint-disable max-len */

    /**
     * @scriptlet abort-current-inline-script
     *
     * @description
     * Aborts an inline script when it attempts to **read** or **write to** the specified property
     * AND when the contents of the `<script>` element contains the specified
     * text or matches the regular expression.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#abort-current-inline-scriptjs-
     *
     * Related ABP source:
     * https://github.com/adblockplus/adblockpluscore/blob/6b2a309054cc23432102b85d13f12559639ef495/lib/content/snippets.js#L928
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('abort-current-inline-script', property[, search])
     * ```
     *
     * - `property` - required, path to a property (joined with `.` if needed). The property must be attached to `window`
     * - `search` - optional, string or regular expression that must match the inline script content.
     * Defaults to abort all scripts which are trying to access the specified property.
     * Invalid regular expression will cause exit and rule will not work.
     *
     * > Note please that for inline script with addEventListener in it
     * `property` should be set as `EventTarget.prototype.addEventListener`,
     * not just `addEventListener`.
     *
     * **Examples**
     * 1. Aborts all inline scripts trying to access `window.alert`
     *     ```
     *     example.org#%#//scriptlet('abort-current-inline-script', 'alert')
     *     ```
     *
     * 2. Aborts inline scripts which are trying to access `window.alert` and contain `Hello, world`.
     *     ```
     *     example.org#%#//scriptlet('abort-current-inline-script', 'alert', 'Hello, world')
     *     ```
     *
     *     For instance, the following script will be aborted
     *     ```html
     *     <script>alert("Hello, world");</script>
     *     ```
     *
     * 3. Aborts inline scripts which are trying to access `window.alert` and match this regexp: `/Hello.+world/`.
     *     ```
     *     example.org#%#//scriptlet('abort-current-inline-script', 'alert', '/Hello.+world/')
     *     ```
     *
     *     For instance, the following scripts will be aborted:
     *     ```html
     *     <script>alert("Hello, big world");</script>
     *     ```
     *     ```html
     *     <script>alert("Hello, little world");</script>
     *     ```
     *
     *     This script will not be aborted:
     *     ```html
     *     <script>alert("Hi, little world");</script>
     *     ```
     */

    /* eslint-enable max-len */

    function abortCurrentInlineScript(source, property, search) {
      var searchRegexp = toRegExp(search);
      var rid = randomId();
      var SRC_DATA_MARKER = 'data:text/javascript;base64,';

      var getCurrentScript = function getCurrentScript() {
        if ('currentScript' in document) {
          return document.currentScript; // eslint-disable-line compat/compat
        }

        var scripts = document.getElementsByTagName('script');
        return scripts[scripts.length - 1];
      };

      var ourScript = getCurrentScript();

      var abort = function abort() {
        var scriptEl = getCurrentScript();

        if (!scriptEl) {
          return;
        }

        var content = scriptEl.textContent; // We are using Node.prototype.textContent property descriptor
        // to get the real script content
        // even when document.currentScript.textContent is replaced.
        // https://github.com/AdguardTeam/Scriptlets/issues/57#issuecomment-593638991

        try {
          var textContentGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').get;
          content = textContentGetter.call(scriptEl);
        } catch (e) {} // eslint-disable-line no-empty
        // https://github.com/AdguardTeam/Scriptlets/issues/130


        if (content.length === 0 && typeof scriptEl.src !== 'undefined' && startsWith(scriptEl.src, SRC_DATA_MARKER)) {
          var encodedContent = scriptEl.src.slice(SRC_DATA_MARKER.length);
          content = window.atob(encodedContent);
        }

        if (scriptEl instanceof HTMLScriptElement && content.length > 0 && scriptEl !== ourScript && searchRegexp.test(content)) {
          hit(source);
          throw new ReferenceError(rid);
        }
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain; // The scriptlet might be executed before the chain property has been created
        // (for instance, document.body before the HTML body was loaded).
        // In this case we're checking whether the base element exists or not
        // and if not, we simply exit without overriding anything.
        // e.g. https://github.com/AdguardTeam/Scriptlets/issues/57#issuecomment-575841092

        if (base instanceof Object === false && base === null) {
          var props = property.split('.');
          var propIndex = props.indexOf(prop);
          var baseName = props[propIndex - 1];
          console.log("The scriptlet had been executed before the ".concat(baseName, " was loaded.")); // eslint-disable-line no-console, max-len

          return;
        }

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        var currentValue = base[prop];
        var origDescriptor = Object.getOwnPropertyDescriptor(base, prop);

        if (origDescriptor instanceof Object === false || origDescriptor.get instanceof Function === false) {
          currentValue = base[prop];
          origDescriptor = undefined;
        }

        setPropertyAccess(base, prop, {
          set: function set(value) {
            abort();

            if (origDescriptor instanceof Object) {
              origDescriptor.set.call(base, value);
            } else {
              currentValue = value;
            }
          },
          get: function get() {
            abort();

            if (origDescriptor instanceof Object) {
              return origDescriptor.get.call(base);
            }

            return currentValue;
          }
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    abortCurrentInlineScript.names = ['abort-current-inline-script', // aliases are needed for matching the related scriptlet converted into our syntax
    'abort-current-script.js', 'ubo-abort-current-script.js', 'acs.js', 'ubo-acs.js', // "ubo"-aliases with no "js"-ending
    'ubo-abort-current-script', 'ubo-acs', // obsolete but supported aliases
    'abort-current-inline-script.js', 'ubo-abort-current-inline-script.js', 'acis.js', 'ubo-acis.js', 'ubo-abort-current-inline-script', 'ubo-acis', 'abp-abort-current-inline-script'];
    abortCurrentInlineScript.injections = [randomId, setPropertyAccess, getPropertyInChain, toRegExp, startsWith, createOnErrorHandler, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet set-constant
     *
     * @description
     * Creates a constant property and assigns it one of the values from the predefined list.
     *
     * > Actually, it's not a constant. Please note, that it can be rewritten with a value of a different type.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#set-constantjs-
     *
     * Related ABP snippet:
     * https://github.com/adblockplus/adblockpluscore/blob/adblockpluschrome-3.9.4/lib/content/snippets.js#L1361
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('set-constant', property, value[, stack])
     * ```
     *
     * - `property` - required, path to a property (joined with `.` if needed). The property must be attached to `window`.
     * - `value` - required. Possible values:
     *     - positive decimal integer `<= 32767`
     *     - one of the predefined constants:
     *         - `undefined`
     *         - `false`
     *         - `true`
     *         - `null`
     *         - `emptyObj` - empty object
     *         - `emptyArr` - empty array
     *         - `noopFunc` - function with empty body
     *         - `trueFunc` - function returning true
     *         - `falseFunc` - function returning false
     *         - `noopPromiseResolve` - function returning Promise object that is resolved with an empty response
     *         - `noopPromiseReject` - function returning Promise.reject()
     *         - `''` - empty string
     *         - `-1` - number value `-1`
     *         - `yes`
     *         - `no`
     * - `stack` - optional, string or regular expression that must match the current function call stack trace;
     * if regular expression is invalid it will be skipped
     *
     * **Examples**
     * ```
     * ! Any access to `window.first` will return `false`
     * example.org#%#//scriptlet('set-constant', 'first', 'false')
     *
     * ✔ window.first === false
     * ```
     *
     * ```
     * ! Any call to `window.second()` will return `true`
     * example.org#%#//scriptlet('set-constant', 'second', 'trueFunc')
     *
     * ✔ window.second() === true
     * ✔ window.second.toString() === "function trueFunc() {return true;}"
     * ```
     *
     * ```
     * ! Any call to `document.third()` will return `true` if the method is related to `checking.js`
     * example.org#%#//scriptlet('set-constant', 'document.third', 'trueFunc', 'checking.js')
     *
     * ✔ document.third() === true  // if the condition described above is met
     * ```
     */

    /* eslint-enable max-len */

    function setConstant(source, property, value, stack) {
      if (!property || !matchStackTrace(stack, new Error().stack)) {
        return;
      } // eslint-disable-next-line no-console


      var log = console.log.bind(console);
      var emptyArr = noopArray();
      var emptyObj = noopObject();
      var constantValue;

      if (value === 'undefined') {
        constantValue = undefined;
      } else if (value === 'false') {
        constantValue = false;
      } else if (value === 'true') {
        constantValue = true;
      } else if (value === 'null') {
        constantValue = null;
      } else if (value === 'emptyArr') {
        constantValue = emptyArr;
      } else if (value === 'emptyObj') {
        constantValue = emptyObj;
      } else if (value === 'noopFunc') {
        constantValue = noopFunc;
      } else if (value === 'trueFunc') {
        constantValue = trueFunc;
      } else if (value === 'falseFunc') {
        constantValue = falseFunc;
      } else if (value === 'noopPromiseResolve') {
        constantValue = noopPromiseResolve;
      } else if (value === 'noopPromiseReject') {
        constantValue = noopPromiseReject;
      } else if (/^\d+$/.test(value)) {
        constantValue = parseFloat(value);

        if (nativeIsNaN(constantValue)) {
          return;
        }

        if (Math.abs(constantValue) > 0x7FFF) {
          return;
        }
      } else if (value === '-1') {
        constantValue = -1;
      } else if (value === '') {
        constantValue = '';
      } else if (value === 'yes') {
        constantValue = 'yes';
      } else if (value === 'no') {
        constantValue = 'no';
      } else {
        return;
      }

      var getCurrentScript = function getCurrentScript() {
        if ('currentScript' in document) {
          return document.currentScript; // eslint-disable-line compat/compat
        }

        var scripts = document.getElementsByTagName('script');
        return scripts[scripts.length - 1];
      };

      var ourScript = getCurrentScript();
      var canceled = false;

      var mustCancel = function mustCancel(value) {
        if (canceled) {
          return canceled;
        }

        canceled = value !== undefined && constantValue !== undefined && typeof value !== typeof constantValue;
        return canceled;
      };

      var trapProp = function trapProp(base, prop, configurable, handler) {
        if (!handler.init(base[prop])) {
          return false;
        }

        var origDescriptor = Object.getOwnPropertyDescriptor(base, prop);
        var prevGetter;
        var prevSetter; // This is required to prevent scriptlets overwrite each over

        if (origDescriptor instanceof Object) {
          // This check is required to avoid defining non-configurable props
          if (!origDescriptor.configurable) {
            if (source.verbose) {
              log("set-constant: property '".concat(prop, "' is not configurable"));
            }

            return false;
          }

          base[prop] = constantValue;

          if (origDescriptor.get instanceof Function) {
            prevGetter = origDescriptor.get;
          }

          if (origDescriptor.set instanceof Function) {
            prevSetter = origDescriptor.set;
          }
        }

        Object.defineProperty(base, prop, {
          configurable: configurable,
          get: function get() {
            if (prevGetter !== undefined) {
              prevGetter();
            }

            return handler.get();
          },
          set: function set(a) {
            if (prevSetter !== undefined) {
              prevSetter(a);
            }

            handler.set(a);
          }
        });
        return true;
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain; // Handler method init is used to keep track of factual value
        // and apply mustCancel() check only on end prop

        var undefPropHandler = {
          factValue: undefined,
          init: function init(a) {
            this.factValue = a;
            return true;
          },
          get: function get() {
            return this.factValue;
          },
          set: function set(a) {
            // Prevent breakage due to loop assignments like win.obj = win.obj
            if (this.factValue === a) {
              return;
            }

            this.factValue = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          }
        };
        var endPropHandler = {
          factValue: undefined,
          init: function init(a) {
            if (mustCancel(a)) {
              return false;
            }

            this.factValue = a;
            return true;
          },
          get: function get() {
            // .currrentSript script check so we won't trap other scriptlets on the same chain
            // eslint-disable-next-line compat/compat
            return document.currentScript === ourScript ? this.factValue : constantValue;
          },
          set: function set(a) {
            if (!mustCancel(a)) {
              return;
            }

            constantValue = a;
          }
        }; // End prop case

        if (!chain) {
          var isTrapped = trapProp(base, prop, false, endPropHandler);

          if (isTrapped) {
            hit(source);
          }

          return;
        } // Defined prop in chain


        var propValue = owner[prop];

        if (propValue instanceof Object || typeof propValue === 'object' && propValue !== null) {
          setChainPropAccess(propValue, chain);
        } // Undefined prop in chain


        trapProp(owner, prop, true, undefPropHandler);
      };

      setChainPropAccess(window, property);
    }
    setConstant.names = ['set-constant', // aliases are needed for matching the related scriptlet converted into our syntax
    'set-constant.js', 'ubo-set-constant.js', 'set.js', 'ubo-set.js', 'ubo-set-constant', 'ubo-set', 'abp-override-property-read'];
    setConstant.injections = [hit, noopArray, noopObject, noopFunc, trueFunc, falseFunc, noopPromiseReject, noopPromiseResolve, getPropertyInChain, setPropertyAccess, toRegExp, matchStackTrace, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet remove-cookie
     *
     * @description
     * Removes current page cookies by passed string matching with name. For current domain and subdomains. Runs on load and before unload.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#cookie-removerjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('remove-cookie'[, match])
     * ```
     *
     * - `match` - optional, string or regex matching the cookie name. If not specified all accessible cookies will be removed.
     *
     * **Examples**
     * 1. Removes all cookies:
     * ```
     *     example.org#%#//scriptlet('remove-cookie')
     * ```
     *
     * 2. Removes cookies which name contains `example` string.
     * ```
     *     example.org#%#//scriptlet('remove-cookie', 'example')
     * ```
     *
     *     For instance this cookie will be removed
     *     ```javascript
     *     document.cookie = '__example=randomValue';
     *     ```
     */

    /* eslint-enable max-len */

    function removeCookie(source, match) {
      var matchRegexp = toRegExp(match);

      var removeCookieFromHost = function removeCookieFromHost(cookieName, hostName) {
        var cookieSpec = "".concat(cookieName, "=");
        var domain1 = "; domain=".concat(hostName);
        var domain2 = "; domain=.".concat(hostName);
        var path = '; path=/';
        var expiration = '; expires=Thu, 01 Jan 1970 00:00:00 GMT';
        document.cookie = cookieSpec + expiration;
        document.cookie = cookieSpec + domain1 + expiration;
        document.cookie = cookieSpec + domain2 + expiration;
        document.cookie = cookieSpec + path + expiration;
        document.cookie = cookieSpec + domain1 + path + expiration;
        document.cookie = cookieSpec + domain2 + path + expiration;
        hit(source);
      };

      var rmCookie = function rmCookie() {
        document.cookie.split(';').forEach(function (cookieStr) {
          var pos = cookieStr.indexOf('=');

          if (pos === -1) {
            return;
          }

          var cookieName = cookieStr.slice(0, pos).trim();

          if (!matchRegexp.test(cookieName)) {
            return;
          }

          var hostParts = document.location.hostname.split('.');

          for (var i = 0; i <= hostParts.length - 1; i += 1) {
            var hostName = hostParts.slice(i).join('.');

            if (hostName) {
              removeCookieFromHost(cookieName, hostName);
            }
          }
        });
      };

      rmCookie();
      window.addEventListener('beforeunload', rmCookie);
    }
    removeCookie.names = ['remove-cookie', // aliases are needed for matching the related scriptlet converted into our syntax
    'cookie-remover.js', 'ubo-cookie-remover.js', 'ubo-cookie-remover'];
    removeCookie.injections = [toRegExp, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-addEventListener
     *
     * @description
     * Prevents adding event listeners for the specified events and callbacks.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#addeventlistener-defuserjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-addEventListener'[, typeSearch[, listenerSearch]])
     * ```
     *
     * - `typeSearch` - optional, string or regular expression matching the type (event name);
     * defaults to match all types; invalid regular expression will cause exit and rule will not work
     * - `listenerSearch` - optional, string or regular expression matching the listener function body;
     * defaults to match all listeners; invalid regular expression will cause exit and rule will not work
     *
     * **Examples**
     * 1. Prevent all `click` listeners:
     * ```
     *     example.org#%#//scriptlet('prevent-addEventListener', 'click')
     * ```

    2. Prevent 'click' listeners with the callback body containing `searchString`.
     * ```
     *     example.org#%#//scriptlet('prevent-addEventListener', 'click', 'searchString')
     * ```
     *
     *     For instance, this listener will not be called:
     * ```javascript
     *     el.addEventListener('click', () => {
     *         window.test = 'searchString';
     *     });
     * ```
     */

    /* eslint-enable max-len */

    function preventAddEventListener(source, typeSearch, listenerSearch) {
      var typeSearchRegexp = toRegExp(typeSearch);
      var listenerSearchRegexp = toRegExp(listenerSearch);
      var nativeAddEventListener = window.EventTarget.prototype.addEventListener;

      function addEventListenerWrapper(type, listener) {
        var shouldPrevent = false;

        if (validateType(type) && validateListener(listener)) {
          shouldPrevent = typeSearchRegexp.test(type.toString()) && listenerSearchRegexp.test(listenerToString(listener));
        }

        if (shouldPrevent) {
          hit(source);
          return undefined;
        }

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

        return nativeAddEventListener.apply(this, [type, listener].concat(args));
      }

      window.EventTarget.prototype.addEventListener = addEventListenerWrapper; // https://github.com/AdguardTeam/Scriptlets/issues/143

      window.addEventListener = addEventListenerWrapper;
      document.addEventListener = addEventListenerWrapper;
    }
    preventAddEventListener.names = ['prevent-addEventListener', // aliases are needed for matching the related scriptlet converted into our syntax
    'addEventListener-defuser.js', 'ubo-addEventListener-defuser.js', 'aeld.js', 'ubo-aeld.js', 'ubo-addEventListener-defuser', 'ubo-aeld'];
    preventAddEventListener.injections = [hit, toRegExp, validateType, validateListener, listenerToString];

    /* eslint-disable consistent-return, no-eval */
    /**
     * @scriptlet prevent-bab
     *
     * @description
     * Prevents BlockAdblock script from detecting an ad blocker.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#bab-defuserjs-
     *
     * It also can be used as `$redirect` sometimes.
     * See [redirect description](../wiki/about-redirects.md#prevent-bab).
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-bab')
     * ```
     */

    function preventBab(source) {
      var nativeSetTimeout = window.setTimeout;
      var babRegex = /\.bab_elementid.$/;

      var timeoutWrapper = function timeoutWrapper(callback) {
        if (typeof callback !== 'string' || !babRegex.test(callback)) {
          for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
            args[_key - 1] = arguments[_key];
          }

          return nativeSetTimeout.apply(window, [callback].concat(args));
        }

        hit(source);
      };

      window.setTimeout = timeoutWrapper;
      var signatures = [['blockadblock'], ['babasbm'], [/getItem\('babn'\)/], ['getElementById', 'String.fromCharCode', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'charAt', 'DOMContentLoaded', 'AdBlock', 'addEventListener', 'doScroll', 'fromCharCode', '<<2|r>>4', 'sessionStorage', 'clientWidth', 'localStorage', 'Math', 'random']];

      var check = function check(str) {
        if (typeof str !== 'string') {
          return false;
        }

        for (var i = 0; i < signatures.length; i += 1) {
          var tokens = signatures[i];
          var match = 0;

          for (var j = 0; j < tokens.length; j += 1) {
            var token = tokens[j];
            var found = token instanceof RegExp ? token.test(str) : str.indexOf(token) > -1;

            if (found) {
              match += 1;
            }
          }

          if (match / tokens.length >= 0.8) {
            return true;
          }
        }

        return false;
      };

      var nativeEval = window.eval;

      var evalWrapper = function evalWrapper(str) {
        if (!check(str)) {
          return nativeEval(str);
        }

        hit(source);
        var bodyEl = document.body;

        if (bodyEl) {
          bodyEl.style.removeProperty('visibility');
        }

        var el = document.getElementById('babasbmsgx');

        if (el) {
          el.parentNode.removeChild(el);
        }
      };

      window.eval = evalWrapper.bind(window);
    }
    preventBab.names = ['prevent-bab', // aliases are needed for matching the related scriptlet converted into our syntax
    'nobab.js', 'ubo-nobab.js', 'bab-defuser.js', 'ubo-bab-defuser.js', 'ubo-nobab', 'ubo-bab-defuser'];
    preventBab.injections = [hit];

    /* eslint-disable no-unused-vars, no-extra-bind, func-names */
    /* eslint-disable max-len */

    /**
     * @scriptlet nowebrtc
     *
     * @description
     * Disables WebRTC by overriding `RTCPeerConnection`. The overridden function will log every attempt to create a new connection.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#nowebrtcjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('nowebrtc')
     * ```
     */

    /* eslint-enable max-len */

    function nowebrtc(source) {
      var propertyName = '';

      if (window.RTCPeerConnection) {
        propertyName = 'RTCPeerConnection';
      } else if (window.webkitRTCPeerConnection) {
        propertyName = 'webkitRTCPeerConnection';
      }

      if (propertyName === '') {
        return;
      }

      var rtcReplacement = function rtcReplacement(config) {
        // eslint-disable-next-line max-len
        hit(source, "Document tried to create an RTCPeerConnection: ".concat(convertRtcConfigToString(config)));
      };

      rtcReplacement.prototype = {
        close: noopFunc,
        createDataChannel: noopFunc,
        createOffer: noopFunc,
        setRemoteDescription: noopFunc
      };
      var rtc = window[propertyName];
      window[propertyName] = rtcReplacement;

      if (rtc.prototype) {
        rtc.prototype.createDataChannel = function (a, b) {
          return {
            close: noopFunc,
            send: noopFunc
          };
        }.bind(null);
      }
    }
    nowebrtc.names = ['nowebrtc', // aliases are needed for matching the related scriptlet converted into our syntax
    'nowebrtc.js', 'ubo-nowebrtc.js', 'ubo-nowebrtc'];
    nowebrtc.injections = [hit, noopFunc, convertRtcConfigToString];

    /**
     * @scriptlet log-addEventListener
     *
     * @description
     * Logs all addEventListener calls to the console.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#addeventlistener-loggerjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('log-addEventListener')
     * ```
     */

    function logAddEventListener(source) {
      // eslint-disable-next-line no-console
      var log = console.log.bind(console);
      var nativeAddEventListener = window.EventTarget.prototype.addEventListener;

      function addEventListenerWrapper(type, listener) {
        if (validateType(type) && validateListener(listener)) {
          var logMessage = "addEventListener(\"".concat(type, "\", ").concat(listenerToString(listener), ")");
          log(logMessage);
          hit(source);
        } else if (source.verbose) {
          // logging while debugging
          var _logMessage = "Invalid event type or listener passed to addEventListener:\ntype: ".concat(convertTypeToString(type), "\nlistener: ").concat(convertTypeToString(listener));

          log(_logMessage);
        }

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

        return nativeAddEventListener.apply(this, [type, listener].concat(args));
      }

      window.EventTarget.prototype.addEventListener = addEventListenerWrapper;
    }
    logAddEventListener.names = ['log-addEventListener', // aliases are needed for matching the related scriptlet converted into our syntax
    'addEventListener-logger.js', 'ubo-addEventListener-logger.js', 'aell.js', 'ubo-aell.js', 'ubo-addEventListener-logger', 'ubo-aell'];
    logAddEventListener.injections = [hit, validateType, validateListener, listenerToString, convertTypeToString, objectToString, isEmptyObject, getObjectEntries];

    /* eslint-disable no-console, no-eval */
    /**
     * @scriptlet log-eval
     *
     * @description
     * Logs all `eval()` or `new Function()` calls to the console.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('log-eval')
     * ```
     */

    function logEval(source) {
      var log = console.log.bind(console); // wrap eval function

      var nativeEval = window.eval;

      function evalWrapper(str) {
        hit(source);
        log("eval(\"".concat(str, "\")"));
        return nativeEval(str);
      }

      window.eval = evalWrapper; // wrap new Function

      var nativeFunction = window.Function;

      function FunctionWrapper() {
        hit(source);

        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        log("new Function(".concat(args.join(', '), ")"));
        return nativeFunction.apply(this, [].concat(args));
      }

      FunctionWrapper.prototype = Object.create(nativeFunction.prototype);
      FunctionWrapper.prototype.constructor = FunctionWrapper;
      window.Function = FunctionWrapper;
    }
    logEval.names = ['log-eval'];
    logEval.injections = [hit];

    /**
     * @scriptlet log
     *
     * @description
     * A simple scriptlet which only purpose is to print arguments to console.
     * This scriptlet can be helpful for debugging and troubleshooting other scriptlets.
     *
     * **Example**
     * ```
     * example.org#%#//scriptlet('log', 'arg1', 'arg2')
     * ```
     */
    function log() {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      console.log(args); // eslint-disable-line no-console
    }
    log.names = ['log'];

    /* eslint-disable no-eval, no-extra-bind */
    /**
     * @scriptlet noeval
     *
     * @description
     * Prevents page to use eval.
     * Notifies about attempts in the console
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#noevaljs-
     *
     * It also can be used as `$redirect` rules sometimes.
     * See [redirect description](../wiki/about-redirects.md#noeval).
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('noeval')
     * ```
     */

    function noeval(source) {
      window.eval = function evalWrapper(s) {
        hit(source, "AdGuard has prevented eval:\n".concat(s));
      }.bind();
    }
    noeval.names = ['noeval', // aliases are needed for matching the related scriptlet converted into our syntax
    'noeval.js', 'silent-noeval.js', 'ubo-noeval.js', 'ubo-silent-noeval.js', 'ubo-noeval', 'ubo-silent-noeval'];
    noeval.injections = [hit];

    /* eslint-disable no-eval, no-extra-bind, func-names */
    /**
     * @scriptlet prevent-eval-if
     *
     * @description
     * Prevents page to use eval matching payload.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#noeval-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-eval-if'[, search])
     * ```
     *
     * - `search` - optional, string or regular expression matching the stringified eval payload;
     * defaults to match all stringified eval payloads;
     * invalid regular expression will cause exit and rule will not work
     *
     * **Examples**
     * ```
     * ! Prevents eval if it matches 'test'
     * example.org#%#//scriptlet('prevent-eval-if', 'test')
     * ```
     */

    function preventEvalIf(source, search) {
      var searchRegexp = toRegExp(search);
      var nativeEval = window.eval;

      window.eval = function (payload) {
        if (!searchRegexp.test(payload.toString())) {
          return nativeEval.call(window, payload);
        }

        hit(source, payload);
        return undefined;
      }.bind(window);
    }
    preventEvalIf.names = ['prevent-eval-if', // aliases are needed for matching the related scriptlet converted into our syntax
    'noeval-if.js', 'ubo-noeval-if.js', 'ubo-noeval-if'];
    preventEvalIf.injections = [toRegExp, hit];

    /* eslint-disable no-console, func-names, no-multi-assign */
    /**
     * @scriptlet prevent-fab-3.2.0
     *
     * @description
     * Prevents execution of the FAB script v3.2.0.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#fuckadblockjs-320-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-fab-3.2.0')
     * ```
     */

    function preventFab(source) {
      hit(source); // redefines Fab function for adblock detection

      var Fab = function Fab() {};

      Fab.prototype.check = noopFunc;
      Fab.prototype.clearEvent = noopFunc;
      Fab.prototype.emitEvent = noopFunc;

      Fab.prototype.on = function (a, b) {
        if (!a) {
          b();
        }

        return this;
      };

      Fab.prototype.onDetected = noopThis;

      Fab.prototype.onNotDetected = function (a) {
        a();
        return this;
      };

      Fab.prototype.setOption = noopFunc;
      Fab.prototype.options = {
        set: noopFunc,
        get: noopFunc
      };
      var fab = new Fab();
      var getSetFab = {
        get: function get() {
          return Fab;
        },
        set: function set() {}
      };
      var getsetfab = {
        get: function get() {
          return fab;
        },
        set: function set() {}
      }; // redefined Fab data properties which if 'FuckAdBlock' variable exists

      if (Object.prototype.hasOwnProperty.call(window, 'FuckAdBlock')) {
        window.FuckAdBlock = Fab;
      } else {
        // or redefined Fab accessor properties
        Object.defineProperty(window, 'FuckAdBlock', getSetFab);
      }

      if (Object.prototype.hasOwnProperty.call(window, 'BlockAdBlock')) {
        window.BlockAdBlock = Fab;
      } else {
        Object.defineProperty(window, 'BlockAdBlock', getSetFab);
      }

      if (Object.prototype.hasOwnProperty.call(window, 'SniffAdBlock')) {
        window.SniffAdBlock = Fab;
      } else {
        Object.defineProperty(window, 'SniffAdBlock', getSetFab);
      }

      if (Object.prototype.hasOwnProperty.call(window, 'fuckAdBlock')) {
        window.fuckAdBlock = fab;
      } else {
        Object.defineProperty(window, 'fuckAdBlock', getsetfab);
      }

      if (Object.prototype.hasOwnProperty.call(window, 'blockAdBlock')) {
        window.blockAdBlock = fab;
      } else {
        Object.defineProperty(window, 'blockAdBlock', getsetfab);
      }

      if (Object.prototype.hasOwnProperty.call(window, 'sniffAdBlock')) {
        window.sniffAdBlock = fab;
      } else {
        Object.defineProperty(window, 'sniffAdBlock', getsetfab);
      }
    }
    preventFab.names = ['prevent-fab-3.2.0', // aliases are needed for matching the related scriptlet converted into our syntax
    'nofab.js', 'ubo-nofab.js', 'fuckadblock.js-3.2.0', 'ubo-fuckadblock.js-3.2.0', 'ubo-nofab'];
    preventFab.injections = [hit, noopFunc, noopThis];

    /* eslint-disable no-console, func-names, no-multi-assign */
    /**
     * @scriptlet set-popads-dummy
     *
     * @description
     * Sets static properties PopAds and popns.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#popads-dummyjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('set-popads-dummy')
     * ```
     */

    function setPopadsDummy(source) {
      delete window.PopAds;
      delete window.popns;
      Object.defineProperties(window, {
        PopAds: {
          get: function get() {
            hit(source);
            return {};
          }
        },
        popns: {
          get: function get() {
            hit(source);
            return {};
          }
        }
      });
    }
    setPopadsDummy.names = ['set-popads-dummy', // aliases are needed for matching the related scriptlet converted into our syntax
    'popads-dummy.js', 'ubo-popads-dummy.js', 'ubo-popads-dummy'];
    setPopadsDummy.injections = [hit];

    /**
     * @scriptlet prevent-popads-net
     *
     * @description
     * Aborts on property write (PopAds, popns), throws reference error with random id.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#popadsnetjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-popads-net')
     * ```
     */

    function preventPopadsNet(source) {
      var rid = randomId();

      var throwError = function throwError() {
        throw new ReferenceError(rid);
      };

      delete window.PopAds;
      delete window.popns;
      Object.defineProperties(window, {
        PopAds: {
          set: throwError
        },
        popns: {
          set: throwError
        }
      });
      window.onerror = createOnErrorHandler(rid).bind();
      hit(source);
    }
    preventPopadsNet.names = ['prevent-popads-net', // aliases are needed for matching the related scriptlet converted into our syntax
    'popads.net.js', 'ubo-popads.net.js', 'ubo-popads.net'];
    preventPopadsNet.injections = [createOnErrorHandler, randomId, hit];

    /* eslint-disable func-names */
    /**
     * @scriptlet prevent-adfly
     *
     * @description
     * Prevents anti-adblock scripts on adfly short links.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#adfly-defuserjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-adfly')
     * ```
     */

    function preventAdfly(source) {
      var isDigit = function isDigit(data) {
        return /^\d$/.test(data);
      };

      var handler = function handler(encodedURL) {
        var evenChars = '';
        var oddChars = '';

        for (var i = 0; i < encodedURL.length; i += 1) {
          if (i % 2 === 0) {
            evenChars += encodedURL.charAt(i);
          } else {
            oddChars = encodedURL.charAt(i) + oddChars;
          }
        }

        var data = (evenChars + oddChars).split('');

        for (var _i = 0; _i < data.length; _i += 1) {
          if (isDigit(data[_i])) {
            for (var ii = _i + 1; ii < data.length; ii += 1) {
              if (isDigit(data[ii])) {
                // eslint-disable-next-line no-bitwise
                var temp = parseInt(data[_i], 10) ^ parseInt(data[ii], 10);

                if (temp < 10) {
                  data[_i] = temp.toString();
                }

                _i = ii;
                break;
              }
            }
          }
        }

        data = data.join('');
        var decodedURL = window.atob(data).slice(16, -16);
        /* eslint-disable compat/compat */

        if (window.stop) {
          window.stop();
        }
        /* eslint-enable compat/compat */


        window.onbeforeunload = null;
        window.location.href = decodedURL;
      };

      var val; // Do not apply handler more than one time

      var applyHandler = true;
      var result = setPropertyAccess(window, 'ysmm', {
        configurable: false,
        set: function set(value) {
          if (applyHandler) {
            applyHandler = false;

            try {
              if (typeof value === 'string') {
                handler(value);
              }
            } catch (err) {} // eslint-disable-line no-empty

          }

          val = value;
        },
        get: function get() {
          return val;
        }
      });

      if (result) {
        hit(source);
      } else {
        window.console.error('Failed to set up prevent-adfly scriptlet');
      }
    }
    preventAdfly.names = ['prevent-adfly', // aliases are needed for matching the related scriptlet converted into our syntax
    'adfly-defuser.js', 'ubo-adfly-defuser.js', 'ubo-adfly-defuser'];
    preventAdfly.injections = [setPropertyAccess, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet debug-on-property-read
     *
     * @description
     * This scriptlet is basically the same as [abort-on-property-read](#abort-on-property-read), but instead of aborting it starts the debugger.
     *
     * **It is not supposed to be used in production filter lists!**
     *
     * **Syntax**
     * ```
     * ! Debug script if it tries to access `window.alert`
     * example.org#%#//scriptlet('debug-on-property-read', 'alert')
     * ! of `window.open`
     * example.org#%#//scriptlet('debug-on-property-read', 'open')
     * ```
     */

    /* eslint-enable max-len */

    function debugOnPropertyRead(source, property) {
      if (!property) {
        return;
      }

      var rid = randomId();

      var abort = function abort() {
        hit(source);
        debugger; // eslint-disable-line no-debugger
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        setPropertyAccess(base, prop, {
          get: abort,
          set: noopFunc
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    debugOnPropertyRead.names = ['debug-on-property-read'];
    debugOnPropertyRead.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit, noopFunc];

    /* eslint-disable max-len */

    /**
     * @scriptlet debug-on-property-write
     *
     * @description
     * This scriptlet is basically the same as [abort-on-property-write](#abort-on-property-write), but instead of aborting it starts the debugger.
     *
     * **It is not supposed to be used in production filter lists!**
     *
     * **Syntax**
     * ```
     * ! Aborts script when it tries to write in property `window.test`
     * example.org#%#//scriptlet('debug-on-property-write', 'test')
     * ```
     */

    /* eslint-enable max-len */

    function debugOnPropertyWrite(source, property) {
      if (!property) {
        return;
      }

      var rid = randomId();

      var abort = function abort() {
        hit(source);
        debugger; // eslint-disable-line no-debugger
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        setPropertyAccess(base, prop, {
          set: abort
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    debugOnPropertyWrite.names = ['debug-on-property-write'];
    debugOnPropertyWrite.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet debug-current-inline-script
     *
     * @description
     * This scriptlet is basically the same as [abort-current-inline-script](#abort-current-inline-script), but instead of aborting it starts the debugger.
     *
     * **It is not supposed to be used in production filter lists!**
     *
     * **Syntax**
     *```
     * ! Aborts script when it tries to access `window.alert`
     * example.org#%#//scriptlet('debug-current-inline-script', 'alert')
     * ```
     */

    /* eslint-enable max-len */

    function debugCurrentInlineScript(source, property, search) {
      var searchRegexp = toRegExp(search);
      var rid = randomId();

      var getCurrentScript = function getCurrentScript() {
        if ('currentScript' in document) {
          return document.currentScript; // eslint-disable-line compat/compat
        }

        var scripts = document.getElementsByTagName('script');
        return scripts[scripts.length - 1];
      };

      var ourScript = getCurrentScript();

      var abort = function abort() {
        var scriptEl = getCurrentScript();

        if (!scriptEl) {
          return;
        }

        var content = scriptEl.textContent; // We are using Node.prototype.textContent property descriptor
        // to get the real script content
        // even when document.currentScript.textContent is replaced.
        // https://github.com/AdguardTeam/Scriptlets/issues/57#issuecomment-593638991

        try {
          var textContentGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').get;
          content = textContentGetter.call(scriptEl);
        } catch (e) {} // eslint-disable-line no-empty


        if (scriptEl instanceof HTMLScriptElement && content.length > 0 && scriptEl !== ourScript && searchRegexp.test(content)) {
          hit(source);
          debugger; // eslint-disable-line no-debugger
        }
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain; // The scriptlet might be executed before the chain property has been created
        // (for instance, document.body before the HTML body was loaded).
        // In this case we're checking whether the base element exists or not
        // and if not, we simply exit without overriding anything.
        // e.g. https://github.com/AdguardTeam/Scriptlets/issues/57#issuecomment-575841092

        if (base instanceof Object === false && base === null) {
          var props = property.split('.');
          var propIndex = props.indexOf(prop);
          var baseName = props[propIndex - 1];
          console.log("The scriptlet had been executed before the ".concat(baseName, " was loaded.")); // eslint-disable-line no-console, max-len

          return;
        }

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        var currentValue = base[prop];
        setPropertyAccess(base, prop, {
          set: function set(value) {
            abort();
            currentValue = value;
          },
          get: function get() {
            abort();
            return currentValue;
          }
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    debugCurrentInlineScript.names = ['debug-current-inline-script'];
    debugCurrentInlineScript.injections = [randomId, setPropertyAccess, getPropertyInChain, toRegExp, createOnErrorHandler, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet remove-attr
     *
     * @description
     * Removes the specified attributes from DOM nodes. This scriptlet runs once when the page loads
     * and after that periodically in order to DOM tree changes by default,
     * or as specified by applying argument.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#remove-attrjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('remove-attr', attrs[, selector, applying])
     * ```
     *
     * - `attrs` — required, attribute or list of attributes joined by '|'
     * - `selector` — optional, CSS selector, specifies DOM nodes from which the attributes will be removed
     * - `applying` — optional, one or more space-separated flags that describe the way scriptlet apply, defaults to 'asap stay'; possible flags:
     *     - `asap` — runs as fast as possible **once**
     *     - `complete` — runs **once** after the whole page has been loaded
     *     - `stay` — as fast as possible **and** stays on the page observing possible DOM changes
     *
     * **Examples**
     * 1.  Removes by attribute
     *     ```
     *     example.org#%#//scriptlet('remove-attr', 'example|test')
     *     ```
     *
     *     ```html
     *     <!-- before  -->
     *     <div example="true" test="true">Some text</div>
     *
     *     <!-- after -->
     *     <div>Some text</div>
     *     ```
     *
     * 2. Removes with specified selector
     *     ```
     *     example.org#%#//scriptlet('remove-attr', 'example', 'div[class="inner"]')
     *     ```
     *
     *     ```html
     *     <!-- before -->
     *     <div class="wrapper" example="true">
     *         <div class="inner" example="true">Some text</div>
     *     </div>
     *
     *     <!-- after -->
     *     <div class="wrapper" example="true">
     *         <div class="inner">Some text</div>
     *     </div>
     *     ```
     *
     *  3. Using flags
     *     ```
     *     example.org#%#//scriptlet('remove-attr', 'example', 'html', 'asap complete')
     *     ```
     */

    /* eslint-enable max-len */

    function removeAttr(source, attrs, selector) {
      var applying = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'asap stay';

      if (!attrs) {
        return;
      }

      attrs = attrs.split(/\s*\|\s*/);

      if (!selector) {
        selector = "[".concat(attrs.join('],['), "]");
      }

      var rmattr = function rmattr() {
        var nodes = [];

        try {
          nodes = [].slice.call(document.querySelectorAll(selector));
        } catch (e) {
          // eslint-disable-next-line no-console
          console.log("Invalid remove-attr selector arg: '".concat(selector, "'"));
        }

        var removed = false;
        nodes.forEach(function (node) {
          attrs.forEach(function (attr) {
            node.removeAttribute(attr);
            removed = true;
          });
        });

        if (removed) {
          hit(source);
        }
      };

      var FLAGS_DIVIDER = ' ';
      var ASAP_FLAG = 'asap';
      var COMPLETE_FLAG = 'complete';
      var STAY_FLAG = 'stay';
      var VALID_FLAGS = [STAY_FLAG, ASAP_FLAG, COMPLETE_FLAG];
      /* eslint-disable no-restricted-properties */

      var passedFlags = applying.trim().split(FLAGS_DIVIDER).filter(function (f) {
        return VALID_FLAGS.indexOf(f) !== -1;
      });

      var run = function run() {
        rmattr();

        if (!passedFlags.indexOf(STAY_FLAG) !== -1) {
          return;
        } // 'true' for observing attributes


        observeDOMChanges(rmattr, true);
      };

      if (passedFlags.indexOf(ASAP_FLAG) !== -1) {
        rmattr();
      }

      if (document.readyState !== 'complete' && passedFlags.indexOf(COMPLETE_FLAG) !== -1) {
        window.addEventListener('load', run, {
          once: true
        });
      } else if (passedFlags.indexOf(STAY_FLAG) !== -1) {
        // Do not call rmattr() twice for 'asap stay' flag
        if (passedFlags.length === 1) {
          rmattr();
        } // 'true' for observing attributes


        observeDOMChanges(rmattr, true);
      }
    }
    removeAttr.names = ['remove-attr', // aliases are needed for matching the related scriptlet converted into our syntax
    'remove-attr.js', 'ubo-remove-attr.js', 'ra.js', 'ubo-ra.js', 'ubo-remove-attr', 'ubo-ra'];
    removeAttr.injections = [hit, observeDOMChanges];

    /* eslint-disable max-len */

    /**
     * @scriptlet set-attr
     *
     * @description
     * Sets the specified attribute on the specified elements. This scriptlet runs once when the page loads
     * and after that and after that on DOM tree changes.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('set-attr', selector, attr[, value])
     * ```
     *
     * - `selector` — required, CSS selector, specifies DOM nodes to set attributes on
     * - `attr` — required, attribute to be set
     * - `value` — the value to assign to the attribute, defaults to ''. Possible values:
     *     - `''` - empty string
     *     - positive decimal integer `<= 32767`
     *
     * **Examples**
     * 1.  Set attribute by selector
     *     ```
     *     example.org#%#//scriptlet('set-attr', 'div.class > a.class', 'test-attribute', '0')
     *     ```
     *
     *     ```html
     *     <!-- before  -->
     *     <a class="class">Some text</div>
     *
     *     <!-- after -->
     *     <a class="class" test-attribute="0">Some text</div>
     *     ```
     * 2.  Set attribute without value
     *     ```
     *     example.org#%#//scriptlet('set-attr', 'div.class > a.class', 'test-attribute')
     *     ```
     *
     *     ```html
     *     <!-- before  -->
     *     <a class="class">Some text</div>
     *
     *     <!-- after -->
     *     <a class="class" test-attribute>Some text</div>
     *     ```
     */

    /* eslint-enable max-len */

    function setAttr(source, selector, attr) {
      var value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';

      if (!selector || !attr) {
        return;
      } // Drop strings that cant be parsed into number, negative numbers and numbers below 32767


      if (value.length !== 0 && (nativeIsNaN(parseInt(value, 10)) || parseInt(value, 10) < 0 || parseInt(value, 10) > 0x7FFF)) {
        return;
      }

      var setAttr = function setAttr() {
        var nodes = [].slice.call(document.querySelectorAll(selector));
        var set = false;
        nodes.forEach(function (node) {
          node.setAttribute(attr, value);
          set = true;
        });

        if (set) {
          hit(source);
        }
      };

      setAttr();
      observeDOMChanges(setAttr, true);
    }
    setAttr.names = ['set-attr'];
    setAttr.injections = [hit, observeDOMChanges, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet remove-class
     *
     * @description
     * Removes the specified classes from DOM nodes. This scriptlet runs once after the page loads
     * and after that periodically in order to DOM tree changes.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#remove-classjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('remove-class', classes[, selector, applying])
     * ```
     *
     * - `classes` — required, class or list of classes separated by '|'
     * - `selector` — optional, CSS selector, specifies DOM nodes from which the classes will be removed.
     * If there is no `selector`, each class of `classes` independently will be removed from all nodes which has one
     * - `applying` — optional, one or more space-separated flags that describe the way scriptlet apply, defaults to 'asap stay'; possible flags:
     *     - `asap` — runs as fast as possible **once**
     *     - `complete` — runs **once** after the whole page has been loaded
     *     - `stay` — as fast as possible **and** stays on the page observing possible DOM changes
     *
     * **Examples**
     * 1.  Removes by classes
     *     ```
     *     example.org#%#//scriptlet('remove-class', 'example|test')
     *     ```
     *
     *     ```html
     *     <!-- before  -->
     *     <div id="first" class="nice test">Some text</div>
     *     <div id="second" class="rare example for test">Some text</div>
     *     <div id="third" class="testing better example">Some text</div>
     *
     *     <!-- after -->
     *     <div id="first" class="nice">Some text</div>
     *     <div id="second" class="rare for">Some text</div>
     *     <div id="third" class="testing better">Some text</div>
     *     ```
     *
     * 2. Removes with specified selector
     *     ```
     *     example.org#%#//scriptlet('remove-class', 'branding', 'div[class^="inner"]')
     *     ```
     *
     *     ```html
     *     <!-- before -->
     *     <div class="wrapper true branding">
     *         <div class="inner bad branding">Some text</div>
     *     </div>
     *
     *     <!-- after -->
     *     <div class="wrapper true branding">
     *         <div class="inner bad">Some text</div>
     *     </div>
     *     ```
     *
     *  3. Using flags
     *     ```
     *     example.org#%#//scriptlet('remove-class', 'branding', 'div[class^="inner"]', 'asap complete')
     *     ```
     */

    /* eslint-enable max-len */

    function removeClass(source, classNames, selector) {
      var applying = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'asap stay';

      if (!classNames) {
        return;
      }

      classNames = classNames.split(/\s*\|\s*/);
      var selectors = [];

      if (!selector) {
        selectors = classNames.map(function (className) {
          return ".".concat(className);
        });
      }

      var removeClassHandler = function removeClassHandler() {
        var nodes = new Set();

        if (selector) {
          var foundNodes = [];

          try {
            foundNodes = [].slice.call(document.querySelectorAll(selector));
          } catch (e) {
            // eslint-disable-next-line no-console
            console.log("Invalid remove-class selector arg: '".concat(selector, "'"));
          }

          foundNodes.forEach(function (n) {
            return nodes.add(n);
          });
        } else if (selectors.length > 0) {
          selectors.forEach(function (s) {
            var elements = document.querySelectorAll(s);

            for (var i = 0; i < elements.length; i += 1) {
              var element = elements[i];
              nodes.add(element);
            }
          });
        }

        var removed = false;
        nodes.forEach(function (node) {
          classNames.forEach(function (className) {
            if (node.classList.contains(className)) {
              node.classList.remove(className);
              removed = true;
            }
          });
        });

        if (removed) {
          hit(source);
        }
      };

      var CLASS_ATTR_NAME = ['class'];
      var FLAGS_DIVIDER = ' ';
      var ASAP_FLAG = 'asap';
      var COMPLETE_FLAG = 'complete';
      var STAY_FLAG = 'stay';
      var VALID_FLAGS = [STAY_FLAG, ASAP_FLAG, COMPLETE_FLAG];
      /* eslint-disable no-restricted-properties */

      var passedFlags = applying.trim().split(FLAGS_DIVIDER).filter(function (f) {
        return VALID_FLAGS.indexOf(f) !== -1;
      });

      var run = function run() {
        removeClassHandler();

        if (!passedFlags.indexOf(STAY_FLAG) !== -1) {
          return;
        } // 'true' for observing attributes
        // 'class' for observing only classes


        observeDOMChanges(removeClassHandler, true, CLASS_ATTR_NAME);
      };

      if (passedFlags.indexOf(ASAP_FLAG) !== -1) {
        removeClassHandler();
      }

      if (document.readyState !== 'complete' && passedFlags.indexOf(COMPLETE_FLAG) !== -1) {
        window.addEventListener('load', run, {
          once: true
        });
      } else if (passedFlags.indexOf(STAY_FLAG) !== -1) {
        // Do not call removeClassHandler() twice for 'asap stay' flag
        if (passedFlags.length === 1) {
          removeClassHandler();
        } // 'true' for observing attributes
        // 'class' for observing only classes


        observeDOMChanges(removeClassHandler, true, CLASS_ATTR_NAME);
      }
    }
    removeClass.names = ['remove-class', // aliases are needed for matching the related scriptlet converted into our syntax
    'remove-class.js', 'ubo-remove-class.js', 'rc.js', 'ubo-rc.js', 'ubo-remove-class', 'ubo-rc'];
    removeClass.injections = [hit, observeDOMChanges];

    /**
     * @scriptlet disable-newtab-links
     *
     * @description
     * Prevents opening new tabs and windows if there is `target` attribute in element.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#disable-newtab-linksjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('disable-newtab-links')
     * ```
     */

    function disableNewtabLinks(source) {
      document.addEventListener('click', function (ev) {
        var target = ev.target;

        while (target !== null) {
          if (target.localName === 'a' && target.hasAttribute('target')) {
            ev.stopPropagation();
            ev.preventDefault();
            hit(source);
            break;
          }

          target = target.parentNode;
        }
      });
    }
    disableNewtabLinks.names = ['disable-newtab-links', // aliases are needed for matching the related scriptlet converted into our syntax
    'disable-newtab-links.js', 'ubo-disable-newtab-links.js', 'ubo-disable-newtab-links'];
    disableNewtabLinks.injections = [hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet adjust-setInterval
     *
     * @description
     * Adjusts interval for specified setInterval() callbacks.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#nano-setinterval-boosterjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('adjust-setInterval'[, match [, interval[, boost]]])
     * ```
     *
     * - `match` - optional, string or regular expression for stringified callback matching;
     * defaults to match all callbacks; invalid regular expression will cause exit and rule will not work
     * - `interval` - optional, defaults to 1000, matching setInterval delay; decimal integer OR '*' for any delay
     * - `boost` - optional, default to 0.05, float, capped at 50 times for up and down (0.02...50), interval multiplier
     *
     * **Examples**
     * 1. Adjust all setInterval() x20 times where interval equal 1000ms:
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval')
     *     ```
     *
     * 2. Adjust all setInterval() x20 times where callback matched with `example` and interval equal 1000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval', 'example')
     *     ```
     *
     * 3. Adjust all setInterval() x20 times where callback matched with `example` and interval equal 400ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval', 'example', '400')
     *     ```
     *
     * 4. Slow down setInterval() x2 times where callback matched with `example` and interval equal 1000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval', 'example', '', '2')
     *     ```
     * 5. Adjust all setInterval() x50 times where interval equal 2000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval', '', '2000', '0.02')
     *     ```
     * 6. Adjust all setInterval() x50 times where interval is randomized
     *     ```
     *     example.org#%#//scriptlet('adjust-setInterval', '', '*', '0.02')
     *     ```
     */

    /* eslint-enable max-len */

    function adjustSetInterval(source, match, interval, boost) {
      var nativeSetInterval = window.setInterval;
      var matchRegexp = toRegExp(match);

      var intervalWrapper = function intervalWrapper(cb, d) {
        if (matchRegexp.test(cb.toString()) && isDelayMatched(interval, d)) {
          d *= getBoostMultiplier(boost);
          hit(source);
        }

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

        return nativeSetInterval.apply(window, [cb, d].concat(args));
      };

      window.setInterval = intervalWrapper;
    }
    adjustSetInterval.names = ['adjust-setInterval', // aliases are needed for matching the related scriptlet converted into our syntax
    'nano-setInterval-booster.js', 'ubo-nano-setInterval-booster.js', 'nano-sib.js', 'ubo-nano-sib.js', 'ubo-nano-setInterval-booster', 'ubo-nano-sib'];
    adjustSetInterval.injections = [hit, toRegExp, getBoostMultiplier, isDelayMatched, nativeIsNaN, nativeIsFinite, getMatchDelay, getWildcardSymbol, shouldMatchAnyDelay];

    /* eslint-disable max-len */

    /**
     * @scriptlet adjust-setTimeout
     *
     * @description
     * Adjusts timeout for specified setTimeout() callbacks.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#nano-settimeout-boosterjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('adjust-setTimeout'[, match [, timeout[, boost]]])
     * ```
     *
     * - `match` - optional, string or regular expression for stringified callback matching;
     * defaults to match all callbacks; invalid regular expression will cause exit and rule will not work
     * - `timeout` - optional, defaults to 1000, matching setTimeout delay; decimal integer OR '*' for any delay
     * - `boost` - optional, default to 0.05, float, capped at 50 times for up and down (0.02...50), timeout multiplier
     *
     * **Examples**
     * 1. Adjust all setTimeout() x20 times where timeout equal 1000ms:
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout')
     *     ```
     *
     * 2. Adjust all setTimeout() x20 times where callback matched with `example` and timeout equal 1000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout', 'example')
     *     ```
     *
     * 3. Adjust all setTimeout() x20 times where callback matched with `example` and timeout equal 400ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout', 'example', '400')
     *     ```
     *
     * 4. Slow down setTimeout() x2 times where callback matched with `example` and timeout equal 1000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout', 'example', '', '2')
     *     ```
     * 5. Adjust all setTimeout() x50 times where timeout equal 2000ms
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout', '', '2000', '0.02')
     *     ```
     * 6. Adjust all setTimeout() x20 times where callback matched with `test` and timeout is randomized
     *     ```
     *     example.org#%#//scriptlet('adjust-setTimeout', 'test', '*')
     *     ```
     */

    /* eslint-enable max-len */

    function adjustSetTimeout(source, match, timeout, boost) {
      var nativeSetTimeout = window.setTimeout;
      var matchRegexp = toRegExp(match);

      var timeoutWrapper = function timeoutWrapper(cb, d) {
        if (matchRegexp.test(cb.toString()) && isDelayMatched(timeout, d)) {
          d *= getBoostMultiplier(boost);
          hit(source);
        }

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

        return nativeSetTimeout.apply(window, [cb, d].concat(args));
      };

      window.setTimeout = timeoutWrapper;
    }
    adjustSetTimeout.names = ['adjust-setTimeout', // aliases are needed for matching the related scriptlet converted into our syntax
    'nano-setTimeout-booster.js', 'ubo-nano-setTimeout-booster.js', 'nano-stb.js', 'ubo-nano-stb.js', 'ubo-nano-setTimeout-booster', 'ubo-nano-stb'];
    adjustSetTimeout.injections = [hit, toRegExp, getBoostMultiplier, isDelayMatched, nativeIsNaN, nativeIsFinite, getMatchDelay, getWildcardSymbol, shouldMatchAnyDelay];

    /* eslint-disable max-len */

    /**
     * @scriptlet dir-string
     *
     * @description
     * Wraps the `console.dir` API to call the `toString` method of the argument.
     * There are several adblock circumvention systems that detect browser devtools
     * and hide themselves. Therefore, if we force them to think
     * that devtools are open (using this scriptlet),
     * it will automatically disable the adblock circumvention script.
     *
     * Related ABP source:
     * https://github.com/adblockplus/adblockpluscore/blob/6b2a309054cc23432102b85d13f12559639ef495/lib/content/snippets.js#L766
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('dir-string'[, times])
     * ```
     * - `times` - optional, the number of times to call the `toString` method of the argument to `console.dir`
     *
     * **Example**
     * ```
     * ! Run 2 times
     * example.org#%#//scriptlet('dir-string', '2')
     * ```
     */

    /* eslint-enable max-len */

    function dirString(source, times) {
      var _console = console,
          dir = _console.dir;
      times = parseInt(times, 10);

      function dirWrapper(object) {
        // eslint-disable-next-line no-unused-vars
        var temp;

        for (var i = 0; i < times; i += 1) {
          // eslint-disable-next-line no-unused-expressions
          temp = "".concat(object);
        }

        if (typeof dir === 'function') {
          dir.call(this, object);
        }

        hit(source, temp);
      } // eslint-disable-next-line no-console


      console.dir = dirWrapper;
    }
    dirString.names = ['dir-string', 'abp-dir-string'];
    dirString.injections = [hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet json-prune
     *
     * @description
     * Removes specified properties from the result of calling JSON.parse and returns the caller
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#json-prunejs-
     *
     * Related ABP source:
     * https://github.com/adblockplus/adblockpluscore/blob/master/lib/content/snippets.js#L1285
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('json-prune'[, propsToRemove [, obligatoryProps [, stack]]])
     * ```
     *
     * - `propsToRemove` - optional, string of space-separated properties to remove
     * - `obligatoryProps` - optional, string of space-separated properties which must be all present for the pruning to occur
     * - `stack` - optional, string or regular expression that must match the current function call stack trace;
     * if regular expression is invalid it will be skipped
     *
     * > Note please that you can use wildcard `*` for chain property name.
     * e.g. 'ad.*.src' instead of 'ad.0.src ad.1.src ad.2.src ...'
     *
     * **Examples**
     * 1. Removes property `example` from the results of JSON.parse call
     *     ```
     *     example.org#%#//scriptlet('json-prune', 'example')
     *     ```
     *
     *     For instance, the following call will return `{ one: 1}`
     *
     *     ```html
     *     JSON.parse('{"one":1,"example":true}')
     *     ```
     *
     * 2. If there are no specified properties in the result of JSON.parse call, pruning will NOT occur
     *     ```
     *     example.org#%#//scriptlet('json-prune', 'one', 'obligatoryProp')
     *     ```
     *
     *     For instance, the following call will return `{ one: 1, two: 2}`
     *
     *     ```html
     *     JSON.parse('{"one":1,"two":2}')
     *     ```
     *
     * 3. A property in a list of properties can be a chain of properties
     *
     *     ```
     *     example.org#%#//scriptlet('json-prune', 'a.b', 'adpath.url.first')
     *     ```
     *
     * 4. Removes property `content.ad` from the results of JSON.parse call if its error stack trace contains `test.js`
     *     ```
     *     example.org#%#//scriptlet('json-prune', 'content.ad', '', 'test.js')
     *     ```
     *
     * 5. A property in a list of properties can be a chain of properties with wildcard in it
     *
     *     ```
     *     example.org#%#//scriptlet('json-prune', 'content.*.media.src', 'content.*.media.preroll')
     *     ```
     *
     * 6. Call with no arguments will log the current hostname and json payload at the console
     *     ```
     *     example.org#%#//scriptlet('json-prune')
     *     ```
     *
     * 7. Call with only second argument will log the current hostname and matched json payload at the console
     *     ```
     *     example.org#%#//scriptlet('json-prune', '', '"id":"117458"')
     *     ```
     */

    /* eslint-enable max-len */

    function jsonPrune(source, propsToRemove, requiredInitialProps, stack) {
      if (!!stack && !matchStackTrace(stack, new Error().stack)) {
        return;
      } // eslint-disable-next-line no-console


      var log = console.log.bind(console);
      var prunePaths = propsToRemove !== undefined && propsToRemove !== '' ? propsToRemove.split(/ +/) : [];
      var requiredPaths = requiredInitialProps !== undefined && requiredInitialProps !== '' ? requiredInitialProps.split(/ +/) : [];

      function isPruningNeeded(root) {
        if (!root) {
          return false;
        }

        var shouldProcess; // Only log hostname and matched JSON payload if only second argument is present

        if (prunePaths.length === 0 && requiredPaths.length > 0) {
          var rootString = JSON.stringify(root);
          var matchRegex = toRegExp(requiredPaths.join(''));
          var shouldLog = matchRegex.test(rootString);

          if (shouldLog) {
            log(window.location.hostname, root);
            shouldProcess = false;
            return shouldProcess;
          }
        }

        for (var i = 0; i < requiredPaths.length; i += 1) {
          var requiredPath = requiredPaths[i];
          var lastNestedPropName = requiredPath.split('.').pop();
          var hasWildcard = requiredPath.indexOf('.*.') > -1 || requiredPath.indexOf('*.') > -1 || requiredPath.indexOf('.*') > -1 || requiredPath.indexOf('.[].') > -1 || requiredPath.indexOf('[].') > -1 || requiredPath.indexOf('.[]') > -1; // if the path has wildcard, getPropertyInChain should 'look through' chain props

          var details = getWildcardPropertyInChain(root, requiredPath, hasWildcard); // start value of 'shouldProcess' due to checking below

          shouldProcess = !hasWildcard;

          for (var _i = 0; _i < details.length; _i += 1) {
            if (hasWildcard) {
              // if there is a wildcard,
              // at least one (||) of props chain should be present in object
              shouldProcess = !(details[_i].base[lastNestedPropName] === undefined) || shouldProcess;
            } else {
              // otherwise each one (&&) of them should be there
              shouldProcess = !(details[_i].base[lastNestedPropName] === undefined) && shouldProcess;
            }
          }
        }

        return shouldProcess;
      }
      /**
       * Prunes properties of 'root' object
       * @param {Object} root
       */


      var jsonPruner = function jsonPruner(root) {
        if (prunePaths.length === 0 && requiredPaths.length === 0) {
          log(window.location.hostname, root);
          return root;
        }

        try {
          if (isPruningNeeded(root) === false) {
            return root;
          } // if pruning is needed, we check every input pathToRemove
          // and delete it if root has it


          prunePaths.forEach(function (path) {
            var ownerObjArr = getWildcardPropertyInChain(root, path, true);
            ownerObjArr.forEach(function (ownerObj) {
              if (ownerObj !== undefined && ownerObj.base) {
                delete ownerObj.base[ownerObj.prop];
                hit(source);
              }
            });
          });
        } catch (e) {
          log(e.toString());
        }

        return root;
      };

      var nativeJSONParse = JSON.parse;

      var jsonParseWrapper = function jsonParseWrapper() {
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        // dealing with stringified json in args, which should be parsed.
        // so we call nativeJSONParse as JSON.parse which is bound to JSON object
        var root = nativeJSONParse.apply(JSON, args);
        return jsonPruner(root);
      }; // JSON.parse mocking


      jsonParseWrapper.toString = nativeJSONParse.toString.bind(nativeJSONParse);
      JSON.parse = jsonParseWrapper; // eslint-disable-next-line compat/compat

      var nativeResponseJson = Response.prototype.json; // eslint-disable-next-line func-names

      var responseJsonWrapper = function responseJsonWrapper() {
        var promise = nativeResponseJson.apply(this);
        return promise.then(function (obj) {
          return jsonPruner(obj);
        });
      }; // do nothing if browser does not support Response (e.g. Internet Explorer)
      // https://developer.mozilla.org/en-US/docs/Web/API/Response


      if (typeof Response === 'undefined') {
        return;
      } // eslint-disable-next-line compat/compat


      Response.prototype.json = responseJsonWrapper;
    }
    jsonPrune.names = ['json-prune', // aliases are needed for matching the related scriptlet converted into our syntax
    'json-prune.js', 'ubo-json-prune.js', 'ubo-json-prune', 'abp-json-prune'];
    jsonPrune.injections = [hit, matchStackTrace, getWildcardPropertyInChain, toRegExp, getWildcardSymbol];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-requestAnimationFrame
     *
     * @description
     * Prevents a `requestAnimationFrame` call
     * if the text of the callback is matching the specified search string which does not start with `!`;
     * otherwise mismatched calls should be defused.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#no-requestanimationframe-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-requestAnimationFrame'[, search])
     * ```
     *
     * - `search` - optional, string or regular expression; invalid regular expression will be skipped and all callbacks will be matched.
     * If starts with `!`, scriptlet will not match the stringified callback but all other will be defused.
     * If do not start with `!`, the stringified callback will be matched.
     *
     * Call with no argument will log all requestAnimationFrame calls while debugging.
     * So do not use the scriptlet without any parameter in production filter lists.
     *
     * **Examples**
     * 1. Prevents `requestAnimationFrame` calls if the callback matches `/\.test/`.
     *     ```bash
     *     example.org#%#//scriptlet('prevent-requestAnimationFrame', '/\.test/')
     *     ```
     *
     *     For instance, the following call will be prevented:
     *     ```javascript
     *     var times = 0;
     *     requestAnimationFrame(function change() {
     *         window.test = 'new value';
     *         if (times < 2) {
     *             times += 1;
     *             requestAnimationFrame(change);
     *         }
     *     });
     *     ```
     * 2. Prevents `requestAnimationFrame` calls if **does not match** 'check'.
     *     ```bash
     *     example.org#%#//scriptlet('prevent-requestAnimationFrame', '!check')
     *     ```
     *
     *     For instance, only the first call will be prevented:
     *
     *     ```javascript
     *     var timesFirst = 0;
     *     requestAnimationFrame(function changeFirst() {
     *         window.check = 'should not be prevented';
     *         if (timesFirst < 2) {
     *             timesFirst += 1;
     *             requestAnimationFrame(changeFirst);
     *         }
     *     });
     *
     *     var timesSecond = 0;
     *     requestAnimationFrame(function changeSecond() {
     *         window.second = 'should be prevented';
     *         if (timesSecond < 2) {
     *             timesSecond += 1;
     *             requestAnimationFrame(changeSecond);
     *         }
     *     });
     *     ```
     */

    /* eslint-enable max-len */

    function preventRequestAnimationFrame(source, match) {
      var nativeRequestAnimationFrame = window.requestAnimationFrame; // logs requestAnimationFrame to console if no arguments have been specified

      var shouldLog = typeof match === 'undefined';

      var _parseMatchArg = parseMatchArg(match),
          isInvertedMatch = _parseMatchArg.isInvertedMatch,
          matchRegexp = _parseMatchArg.matchRegexp;

      var rafWrapper = function rafWrapper(callback) {
        var shouldPrevent = false;

        if (shouldLog) {
          var logMessage = "log: requestAnimationFrame(\"".concat(callback.toString(), "\")");
          hit(source, logMessage);
        } else if (validateStrPattern(match)) {
          shouldPrevent = matchRegexp.test(callback.toString()) !== isInvertedMatch;
        }

        if (shouldPrevent) {
          hit(source);
          return nativeRequestAnimationFrame(noopFunc);
        }

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

        return nativeRequestAnimationFrame.apply(window, [callback].concat(args));
      };

      window.requestAnimationFrame = rafWrapper;
    }
    preventRequestAnimationFrame.names = ['prevent-requestAnimationFrame', // aliases are needed for matching the related scriptlet converted into our syntax
    'no-requestAnimationFrame-if.js', 'ubo-no-requestAnimationFrame-if.js', 'norafif.js', 'ubo-norafif.js', 'ubo-no-requestAnimationFrame-if', 'ubo-norafif'];
    preventRequestAnimationFrame.injections = [hit, noopFunc, parseMatchArg, validateStrPattern, toRegExp, startsWith];

    /* eslint-disable max-len */

    /**
     * @scriptlet set-cookie
     *
     * @description
     * Sets a cookie with the specified name and value. Cookie path defaults to root.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('set-cookie', name, value)
     * ```
     *
     * - `name` - required, cookie name to be set
     * - `value` - required, cookie value; possible values:
     *     - number `>= 0 && <= 15`
     *     - one of the predefined constants:
     *         - `true` / `True`
     *         - `false` / `False`
     *         - `yes` / `Yes` / `Y`
     *         - `no`
     *         - `ok` / `OK`
     *
     * **Examples**
     * ```
     * example.org#%#//scriptlet('set-cookie', 'ReadlyCookieConsent', '1')
     *
     * example.org#%#//scriptlet('set-cookie', 'gdpr-settings-cookie', 'true')
     * ```
     */

    /* eslint-enable max-len */

    function setCookie(source, name, value) {
      var cookieData = prepareCookie(name, value);

      if (cookieData) {
        hit(source);
        document.cookie = cookieData;
      }
    }
    setCookie.names = ['set-cookie'];
    setCookie.injections = [hit, nativeIsNaN, prepareCookie];

    /**
     * @scriptlet set-cookie-reload
     *
     * @description
     * Sets a cookie with the specified name and value, and then reloads the current page.
     * If reloading option is not needed, use [set-cookie](#set-cookie) scriptlet.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('set-cookie-reload', name, value)
     * ```
     *
     * - `name` - required, cookie name to be set
     * - `value` - required, cookie value; possible values:
     *     - number `>= 0 && <= 15`
     *     - one of the predefined constants:
     *         - `true` / `True`
     *         - `false` / `False`
     *         - `yes` / `Yes` / `Y`
     *         - `no`
     *         - `ok` / `OK`
     *
     * **Examples**
     * ```
     * example.org#%#//scriptlet('set-cookie-reload', 'checking', 'ok')
     *
     * example.org#%#//scriptlet('set-cookie-reload', 'gdpr-settings-cookie', '1')
     * ```
     */

    function setCookieReload(source, name, value) {
      var isCookieAlreadySet = document.cookie.split(';').some(function (cookieStr) {
        var pos = cookieStr.indexOf('=');

        if (pos === -1) {
          return false;
        }

        var cookieName = cookieStr.slice(0, pos).trim();
        var cookieValue = cookieStr.slice(pos + 1).trim();
        return name === cookieName && value === cookieValue;
      });
      var shouldReload = !isCookieAlreadySet;
      var cookieData = prepareCookie(name, value);

      if (cookieData) {
        hit(source);
        document.cookie = cookieData;

        if (shouldReload) {
          window.location.reload();
        }
      }
    }
    setCookieReload.names = ['set-cookie-reload'];
    setCookieReload.injections = [hit, nativeIsNaN, prepareCookie];

    /**
     * @scriptlet hide-in-shadow-dom
     *
     * @description
     * Hides elements inside open shadow DOM elements.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('hide-in-shadow-dom', selector[, baseSelector])
     * ```
     *
     * - `selector` — required, CSS selector of element in shadow-dom to hide
     * - `baseSelector` — optional, selector of specific page DOM element,
     * narrows down the part of the page DOM where shadow-dom host supposed to be,
     * defaults to document.documentElement
     *
     * > `baseSelector` should match element of the page DOM, but not of shadow DOM
     *
     * **Examples**
     * ```
     * ! hides menu bar
     * virustotal.com#%#//scriptlet('hide-in-shadow-dom', 'iron-pages', 'vt-virustotal-app')
     *
     * ! hides floating element
     * virustotal.com#%#//scriptlet('hide-in-shadow-dom', 'vt-ui-contact-fab')
     * ```
     */

    function hideInShadowDom(source, selector, baseSelector) {
      // do nothing if browser does not support ShadowRoot
      // https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot
      if (!Element.prototype.attachShadow) {
        return;
      }

      var hideElement = function hideElement(targetElement) {
        var DISPLAY_NONE_CSS = 'display:none!important;';
        targetElement.style.cssText = DISPLAY_NONE_CSS;
      };
      /**
       * Handles shadow-dom piercing and hiding of found elements
       */


      var hideHandler = function hideHandler() {
        // start value of shadow-dom hosts for the page dom
        var hostElements = !baseSelector ? findHostElements(document.documentElement) : document.querySelectorAll(baseSelector); // if there is shadow-dom host, they should be explored

        while (hostElements.length !== 0) {
          var isHidden = false;

          var _pierceShadowDom = pierceShadowDom(selector, hostElements),
              targets = _pierceShadowDom.targets,
              innerHosts = _pierceShadowDom.innerHosts;

          targets.forEach(function (targetEl) {
            hideElement(targetEl);
            isHidden = true;
          });

          if (isHidden) {
            hit(source);
          } // continue to pierce for inner shadow-dom hosts
          // and search inside them while the next iteration


          hostElements = innerHosts;
        }
      };

      hideHandler();
      observeDOMChanges(hideHandler, true);
    }
    hideInShadowDom.names = ['hide-in-shadow-dom'];
    hideInShadowDom.injections = [hit, observeDOMChanges, flatten, findHostElements, pierceShadowDom];

    /**
     * @scriptlet remove-in-shadow-dom
     *
     * @description
     * Removes elements inside open shadow DOM elements.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('remove-in-shadow-dom', selector[, baseSelector])
     * ```
     *
     * - `selector` — required, CSS selector of element in shadow-dom to remove
     * - `baseSelector` — optional, selector of specific page DOM element,
     * narrows down the part of the page DOM where shadow-dom host supposed to be,
     * defaults to document.documentElement
     *
     * > `baseSelector` should match element of the page DOM, but not of shadow DOM
     *
     * **Examples**
     * ```
     * ! removes menu bar
     * virustotal.com#%#//scriptlet('remove-in-shadow-dom', 'iron-pages', 'vt-virustotal-app')
     *
     * ! removes floating element
     * virustotal.com#%#//scriptlet('remove-in-shadow-dom', 'vt-ui-contact-fab')
     * ```
     */

    function removeInShadowDom(source, selector, baseSelector) {
      // do nothing if browser does not support ShadowRoot
      // https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot
      if (!Element.prototype.attachShadow) {
        return;
      }

      var removeElement = function removeElement(targetElement) {
        targetElement.remove();
      };
      /**
       * Handles shadow-dom piercing and removing of found elements
       */


      var removeHandler = function removeHandler() {
        // start value of shadow-dom hosts for the page dom
        var hostElements = !baseSelector ? findHostElements(document.documentElement) : document.querySelectorAll(baseSelector); // if there is shadow-dom host, they should be explored

        while (hostElements.length !== 0) {
          var isRemoved = false;

          var _pierceShadowDom = pierceShadowDom(selector, hostElements),
              targets = _pierceShadowDom.targets,
              innerHosts = _pierceShadowDom.innerHosts;

          targets.forEach(function (targetEl) {
            removeElement(targetEl);
            isRemoved = true;
          });

          if (isRemoved) {
            hit(source);
          } // continue to pierce for inner shadow-dom hosts
          // and search inside them while the next iteration


          hostElements = innerHosts;
        }
      };

      removeHandler();
      observeDOMChanges(removeHandler, true);
    }
    removeInShadowDom.names = ['remove-in-shadow-dom'];
    removeInShadowDom.injections = [hit, observeDOMChanges, flatten, findHostElements, pierceShadowDom];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-fetch
     *
     * @description
     * Prevents `fetch` calls if **all** given parameters match
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#no-fetch-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-fetch'[, propsToMatch])
     * ```
     *
     * - `propsToMatch` - optional, string of space-separated properties to match; possible props:
     *   - string or regular expression for matching the URL passed to fetch call; empty string, wildcard `*` or invalid regular expression will match all fetch calls
     *   - colon-separated pairs `name:value` where
     *     - `name` is [`init` option name](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters)
     *     - `value` is string or regular expression for matching the value of the option passed to fetch call; invalid regular expression will cause any value matching
     *
     * > Usage with no arguments will log fetch calls to browser console;
     * which is useful for debugging but permitted for production filter lists.
     *
     * **Examples**
     * 1. Prevent all fetch calls
     *     ```
     *     example.org#%#//scriptlet('prevent-fetch', '*')
     *     ```
     *
     * 2. Prevent fetch call for specific url
     *     ```
     *     example.org#%#//scriptlet('prevent-fetch', '/url\\.part/')
     *     ```
     *
     * 3. Prevent fetch call for specific request method
     *     ```
     *     example.org#%#//scriptlet('prevent-fetch', 'method:HEAD')
     *     ```
     *
     * 4. Prevent fetch call for specific url and request method
     *     ```
     *     example.org#%#//scriptlet('prevent-fetch', '/specified_url_part/ method:/HEAD|GET/')
     *     ```
     */

    /* eslint-enable max-len */

    function preventFetch(source, propsToMatch) {
      // do nothing if browser does not support fetch or Proxy (e.g. Internet Explorer)
      // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
      if (typeof fetch === 'undefined' || typeof Proxy === 'undefined') {
        return;
      }

      var handlerWrapper = function handlerWrapper(target, thisArg, args) {
        var shouldPrevent = false;
        var fetchData = getFetchData(args);

        if (typeof propsToMatch === 'undefined') {
          // log if no propsToMatch given
          var logMessage = "log: fetch( ".concat(objectToString(fetchData), " )");
          hit(source, logMessage);
        } else if (propsToMatch === '' || propsToMatch === getWildcardSymbol()) {
          // prevent all fetch calls
          shouldPrevent = true;
        } else {
          var parsedData = parseMatchProps(propsToMatch);

          if (!validateParsedData(parsedData)) {
            // eslint-disable-next-line no-console
            console.log("Invalid parameter: ".concat(propsToMatch));
            shouldPrevent = false;
          } else {
            var matchData = getMatchPropsData(parsedData); // prevent only if all props match

            shouldPrevent = Object.keys(matchData).every(function (matchKey) {
              var matchValue = matchData[matchKey];
              return Object.prototype.hasOwnProperty.call(fetchData, matchKey) && matchValue.test(fetchData[matchKey]);
            });
          }
        }

        if (shouldPrevent) {
          hit(source);
          return noopPromiseResolve();
        }

        return Reflect.apply(target, thisArg, args);
      };

      var fetchHandler = {
        apply: handlerWrapper
      };
      fetch = new Proxy(fetch, fetchHandler); // eslint-disable-line no-global-assign
    }
    preventFetch.names = ['prevent-fetch', // aliases are needed for matching the related scriptlet converted into our syntax
    'no-fetch-if.js', 'ubo-no-fetch-if.js', 'ubo-no-fetch-if'];
    preventFetch.injections = [hit, getFetchData, objectToString, parseMatchProps, validateParsedData, getMatchPropsData, noopPromiseResolve, getWildcardSymbol, toRegExp, validateStrPattern, isEmptyObject, getRequestData, getObjectEntries, getObjectFromEntries];

    /* eslint-disable max-len */

    /**
     * @scriptlet set-local-storage-item
     *
     * @description
     * Adds specified key and its value to localStorage object, or updates the value of the key if it already exists.
     *
     * **Syntax**
     * ```
     * example.com#%#//scriptlet('set-local-storage-item', 'key', 'value')
     * ```
     *
     * - `key` — required, key name to be set.
     * - `value` - required, key value; possible values:
     *     - positive decimal integer `<= 32767`
     *     - one of the predefined constants:
     *         - `undefined`
     *         - `false`
     *         - `true`
     *         - `null`
     *         - `emptyObj` - empty object
     *         - `emptyArr` - empty array
     *         - `''` - empty string
     *         - `yes`
     *         - `no`
     *
     * **Examples**
     * ```
     * example.org#%#//scriptlet('set-local-storage-item', 'player.live.current.mute', 'false')
     *
     * example.org#%#//scriptlet('set-local-storage-item', 'exit-intent-marketing', '1')
     * ```
     */

    /* eslint-enable max-len */

    function setLocalStorageItem(source, key, value) {
      if (!key || !value && value !== '') {
        return;
      }

      var keyValue;

      if (value === 'undefined') {
        keyValue = undefined;
      } else if (value === 'false') {
        keyValue = false;
      } else if (value === 'true') {
        keyValue = true;
      } else if (value === 'null') {
        keyValue = null;
      } else if (value === 'emptyArr') {
        keyValue = '[]';
      } else if (value === 'emptyObj') {
        keyValue = '{}';
      } else if (value === '') {
        keyValue = '';
      } else if (/^\d+$/.test(value)) {
        keyValue = parseFloat(value);

        if (nativeIsNaN(keyValue)) {
          return;
        }

        if (Math.abs(keyValue) > 0x7FFF) {
          return;
        }
      } else if (value === 'yes') {
        keyValue = 'yes';
      } else if (value === 'no') {
        keyValue = 'no';
      } else {
        return;
      }

      var setItem = function setItem(key, value) {
        var _window = window,
            localStorage = _window.localStorage; // setItem() may throw an exception if the storage is full.

        try {
          localStorage.setItem(key, value);
          hit(source);
        } catch (e) {
          if (source.verbose) {
            // eslint-disable-next-line no-console
            console.log("Was unable to set localStorage item due to: ".concat(e.message));
          }
        }
      };

      setItem(key, keyValue);
    }
    setLocalStorageItem.names = ['set-local-storage-item'];
    setLocalStorageItem.injections = [hit, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet set-session-storage-item
     *
     * @description
     * Adds specified key and its value to sessionStorage object, or updates the value of the key if it already exists.
     *
     * **Syntax**
     * ```
     * example.com#%#//scriptlet('set-session-storage-item', 'key', 'value')
     * ```
     *
     * - `key` — required, key name to be set.
     * - `value` - required, key value; possible values:
     *     - positive decimal integer `<= 32767`
     *     - one of the predefined constants:
     *         - `undefined`
     *         - `false`
     *         - `true`
     *         - `null`
     *         - `emptyObj` - empty object
     *         - `emptyArr` - empty array
     *         - `''` - empty string
     *         - `yes`
     *         - `no`
     *
     * **Examples**
     * ```
     * example.org#%#//scriptlet('set-session-storage-item', 'player.live.current.mute', 'false')
     *
     * example.org#%#//scriptlet('set-session-storage-item', 'exit-intent-marketing', '1')
     * ```
     */

    /* eslint-enable max-len */

    function setSessionStorageItem(source, key, value) {
      if (!key || !value && value !== '') {
        return;
      }

      var keyValue;

      if (value === 'undefined') {
        keyValue = undefined;
      } else if (value === 'false') {
        keyValue = false;
      } else if (value === 'true') {
        keyValue = true;
      } else if (value === 'null') {
        keyValue = null;
      } else if (value === 'emptyArr') {
        keyValue = '[]';
      } else if (value === 'emptyObj') {
        keyValue = '{}';
      } else if (value === '') {
        keyValue = '';
      } else if (/^\d+$/.test(value)) {
        keyValue = parseFloat(value);

        if (nativeIsNaN(keyValue)) {
          return;
        }

        if (Math.abs(keyValue) > 0x7FFF) {
          return;
        }
      } else if (value === 'yes') {
        keyValue = 'yes';
      } else if (value === 'no') {
        keyValue = 'no';
      } else {
        return;
      }

      var setItem = function setItem(key, value) {
        var _window = window,
            sessionStorage = _window.sessionStorage; // setItem() may throw an exception if the storage is full.

        try {
          sessionStorage.setItem(key, value);
          hit(source);
        } catch (e) {
          if (source.verbose) {
            // eslint-disable-next-line no-console
            console.log("Was unable to set sessionStorage item due to: ".concat(e.message));
          }
        }
      };

      setItem(key, keyValue);
    }
    setSessionStorageItem.names = ['set-session-storage-item'];
    setSessionStorageItem.injections = [hit, nativeIsNaN];

    /* eslint-disable max-len */

    /**
     * @scriptlet abort-on-stack-trace
     *
     * @description
     * Aborts a script when it attempts to utilize (read or write to) the specified property and it's error stack trace contains given value.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock-for-firefox-legacy/commit/7099186ae54e70b588d5e99554a05d783cabc8ff
     *
     * **Syntax**
     * ```
     * example.com#%#//scriptlet('abort-on-stack-trace', property, stack)
     * ```
     *
     * - `property` - required, path to a property. The property must be attached to window.
     * - `stack` - required, string that must match the current function call stack trace.
     *
     * **Examples**
     * ```
     * ! Aborts script when it tries to access `window.Ya` and it's error stack trace contains `test.js`
     * example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'test.js')
     *
     * ! Aborts script when it tries to access `window.Ya.videoAd` and it's error stack trace contains `test.js`
     * example.org#%#//scriptlet('abort-on-stack-trace', 'Ya.videoAd', 'test.js')
     *
     * ! Aborts script when stack trace matches with any of these parameters
     * example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'yandexFuncName')
     * example.org#%#//scriptlet('abort-on-stack-trace', 'Ya', 'yandexScriptName')
     * ```
     */

    /* eslint-enable max-len */

    function abortOnStackTrace(source, property, stack) {
      if (!property || !stack) {
        return;
      }

      var rid = randomId();

      var abort = function abort() {
        hit(source);
        throw new ReferenceError(rid);
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        var value = base[prop];

        if (!validateStrPattern(stack)) {
          // eslint-disable-next-line no-console
          console.log("Invalid parameter: ".concat(stack));
          return;
        }

        setPropertyAccess(base, prop, {
          get: function get() {
            if (matchStackTrace(stack, new Error().stack)) {
              abort();
            }

            return value;
          },
          set: function set(newValue) {
            if (matchStackTrace(stack, new Error().stack)) {
              abort();
            }

            value = newValue;
          }
        });
      };

      setChainPropAccess(window, property);
      window.onerror = createOnErrorHandler(rid).bind();
    }
    abortOnStackTrace.names = ['abort-on-stack-trace', // aliases are needed for matching the related scriptlet converted into our syntax
    'abort-on-stack-trace.js', 'ubo-abort-on-stack-trace.js', 'aost.js', 'ubo-aost.js', 'ubo-abort-on-stack-trace', 'ubo-aost', 'abp-abort-on-stack-trace'];
    abortOnStackTrace.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit, validateStrPattern, matchStackTrace, toRegExp];

    /* eslint-disable max-len */

    /**
     * @scriptlet log-on-stack-trace
     *
     * @description
     * This scriptlet is basically the same as [abort-on-stack-trace](#abort-on-stack-trace), but instead of aborting it logs:
     * - function and source script names pairs that access the given property
     * - was that get or set attempt
     * - script being injected or inline
     *
     * **Syntax**
     * ```
     * example.com#%#//scriptlet('log-on-stack-trace', 'property')
     * ```
     *
     * - `property` - required, path to a property. The property must be attached to window.
     */

    /* eslint-enable max-len */

    function logOnStacktrace(source, property) {
      if (!property) {
        return;
      }

      var refineStackTrace = function refineStackTrace(stackString) {
        // Split stack trace string by lines and remove first two elements ('Error' and getter call)
        // Remove '    at ' at the start of each string
        var stackSteps = stackString.split('\n').slice(2).map(function (line) {
          return line.replace(/ {4}at /, '');
        }); // Trim each line extracting funcName : fullPath pair

        var logInfoArray = stackSteps.map(function (line) {
          var funcName;
          var funcFullPath;
          /* eslint-disable-next-line no-useless-escape */

          var reg = /\(([^\)]+)\)/;

          if (line.match(reg)) {
            funcName = line.split(' ').slice(0, -1).join(' ');
            /* eslint-disable-next-line prefer-destructuring, no-useless-escape */

            funcFullPath = line.match(reg)[1];
          } else {
            // For when func name is not available
            funcName = 'function name is not available';
            funcFullPath = line;
          }

          return [funcName, funcFullPath];
        }); // Convert array into object for better display using console.table

        var logInfoObject = {};
        logInfoArray.forEach(function (pair) {
          /* eslint-disable-next-line prefer-destructuring */
          logInfoObject[pair[0]] = pair[1];
        });
        return logInfoObject;
      };

      var setChainPropAccess = function setChainPropAccess(owner, property) {
        var chainInfo = getPropertyInChain(owner, property);
        var base = chainInfo.base;
        var prop = chainInfo.prop,
            chain = chainInfo.chain;

        if (chain) {
          var setter = function setter(a) {
            base = a;

            if (a instanceof Object) {
              setChainPropAccess(a, chain);
            }
          };

          Object.defineProperty(owner, prop, {
            get: function get() {
              return base;
            },
            set: setter
          });
          return;
        }

        var value = base[prop];
        /* eslint-disable no-console, compat/compat */

        setPropertyAccess(base, prop, {
          get: function get() {
            hit(source);
            console.log("%cGet %c".concat(prop), 'color:red;', 'color:green;');
            console.table(refineStackTrace(new Error().stack));
            return value;
          },
          set: function set(newValue) {
            hit(source);
            console.log("%cSet %c".concat(prop), 'color:red;', 'color:green;');
            console.table(refineStackTrace(new Error().stack));
            value = newValue;
          }
        });
        /* eslint-enable no-console, compat/compat */
      };

      setChainPropAccess(window, property);
    }
    logOnStacktrace.names = ['log-on-stack-trace'];
    logOnStacktrace.injections = [getPropertyInChain, setPropertyAccess, hit];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-xhr
     *
     * @description
     * Prevents `xhr` calls if **all** given parameters match.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#no-xhr-ifjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-xhr'[, propsToMatch[, randomize]])
     * ```
     *
     * - propsToMatch - optional, string of space-separated properties to match; possible props:
     *   - string or regular expression for matching the URL passed to `.open()` call; empty string or wildcard * for all `.open()` calls match
     *   - colon-separated pairs name:value where
     *     - name is XMLHttpRequest object property name
     *     - value is string or regular expression for matching the value of the option passed to `.open()` call
     * - randomize - optional, defaults to `false`, boolean to randomize responseText of matched XMLHttpRequest's response,
     *
     * > Usage with no arguments will log XMLHttpRequest objects to browser console;
     * which is useful for debugging but permitted for production filter lists.
     *
     * **Examples**
     * 1. Log all XMLHttpRequests
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr')
     *     ```
     *
     * 2. Prevent all XMLHttpRequests
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr', '*')
     *     example.org#%#//scriptlet('prevent-xhr', '')
     *     ```
     *
     * 3. Prevent XMLHttpRequests for specific url
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr', 'example.org')
     *     ```
     *
     * 4. Prevent XMLHttpRequests for specific request method
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr', 'method:HEAD')
     *     ```
     *
     * 5. Prevent XMLHttpRequests for specific url and specified request methods
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr', 'example.org method:/HEAD|GET/')
     *     ```
     *
     * 6. Prevent XMLHttpRequests for specific url and randomize it's response text
     *     ```
     *     example.org#%#//scriptlet('prevent-xhr', 'example.org', 'true')
     *     ```
     */

    /* eslint-enable max-len */

    function preventXHR(source, propsToMatch, randomize) {
      // do nothing if browser does not support Proxy (e.g. Internet Explorer)
      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
      if (typeof Proxy === 'undefined') {
        return;
      }

      var shouldPrevent = false;
      var responseText = '';
      var responseUrl;

      var openWrapper = function openWrapper(target, thisArg, args) {
        // Get method and url from .open()
        var xhrData = {
          method: args[0],
          url: args[1]
        };
        responseUrl = xhrData.url;

        if (typeof propsToMatch === 'undefined') {
          // Log if no propsToMatch given
          var logMessage = "log: xhr( ".concat(objectToString(xhrData), " )");
          hit(source, logMessage);
        } else if (propsToMatch === '' || propsToMatch === getWildcardSymbol()) {
          // Prevent all fetch calls
          shouldPrevent = true;
        } else {
          var parsedData = parseMatchProps(propsToMatch);

          if (!validateParsedData(parsedData)) {
            // eslint-disable-next-line no-console
            console.log("Invalid parameter: ".concat(propsToMatch));
            shouldPrevent = false;
          } else {
            var matchData = getMatchPropsData(parsedData); // prevent only if all props match

            shouldPrevent = Object.keys(matchData).every(function (matchKey) {
              var matchValue = matchData[matchKey];
              return Object.prototype.hasOwnProperty.call(xhrData, matchKey) && matchValue.test(xhrData[matchKey]);
            });
          }
        }

        return Reflect.apply(target, thisArg, args);
      };

      var sendWrapper = function sendWrapper(target, thisArg, args) {
        if (!shouldPrevent) {
          return Reflect.apply(target, thisArg, args);
        }

        if (randomize === 'true') {
          // Generate random alphanumeric string of 10 symbols
          responseText = Math.random().toString(36).slice(-10);
        } // Mock response object


        Object.defineProperties(thisArg, {
          readyState: {
            value: 4,
            writable: false
          },
          response: {
            value: '',
            writable: false
          },
          responseText: {
            value: responseText,
            writable: false
          },
          responseURL: {
            value: responseUrl,
            writable: false
          },
          responseXML: {
            value: '',
            writable: false
          },
          status: {
            value: 200,
            writable: false
          },
          statusText: {
            value: 'OK',
            writable: false
          }
        }); // Mock events

        setTimeout(function () {
          var stateEvent = new Event('readystatechange');
          thisArg.dispatchEvent(stateEvent);
          var loadEvent = new Event('load');
          thisArg.dispatchEvent(loadEvent);
          var loadEndEvent = new Event('loadend');
          thisArg.dispatchEvent(loadEndEvent);
        }, 1);
        hit(source);
        return undefined;
      };

      var openHandler = {
        apply: openWrapper
      };
      var sendHandler = {
        apply: sendWrapper
      };
      XMLHttpRequest.prototype.open = new Proxy(XMLHttpRequest.prototype.open, openHandler);
      XMLHttpRequest.prototype.send = new Proxy(XMLHttpRequest.prototype.send, sendHandler);
    }
    preventXHR.names = ['prevent-xhr', // aliases are needed for matching the related scriptlet converted into our syntax
    'no-xhr-if.js', 'ubo-no-xhr-if.js', 'ubo-no-xhr-if'];
    preventXHR.injections = [hit, objectToString, getWildcardSymbol, parseMatchProps, validateParsedData, getMatchPropsData, toRegExp, validateStrPattern, isEmptyObject, getObjectEntries];

    /**
     * @scriptlet close-window
     *
     * @description
     * Closes the browser tab immediately.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('close-window'[, path])
     * ```
     *
     * - `path` — optional, string or regular expression
     * matching the current location's path: `window.location.pathname` + `window.location.search`.
     * Defaults to execute on every page.
     *
     * **Examples**
     * ```
     * ! closes any example.org tab
     * example.org#%#//scriptlet('close-window')
     *
     * ! closes specific example.org tab
     * example.org#%#//scriptlet('close-window', '/example-page.html')
     * ```
     */

    function forceWindowClose(source) {
      var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
      // eslint-disable-next-line no-console
      var log = console.log.bind(console); // https://github.com/AdguardTeam/Scriptlets/issues/158#issuecomment-993423036

      if (typeof window.close !== 'function') {
        if (source.verbose) {
          log('window.close() is not a function so \'close-window\' scriptlet is unavailable');
        }

        return;
      }

      var closeImmediately = function closeImmediately() {
        try {
          hit(source);
          window.close();
        } catch (e) {
          // log the error if window closing is impossible
          // https://developer.mozilla.org/en-US/docs/Web/API/Window/close
          log(e);
        }
      };

      if (path === '') {
        closeImmediately();
      } else {
        var pathRegexp = toRegExp(path);
        var currentPath = "".concat(window.location.pathname).concat(window.location.search);

        if (pathRegexp.test(currentPath)) {
          closeImmediately();
        }
      }
    }
    forceWindowClose.names = ['close-window', 'window-close-if.js', 'ubo-window-close-if.js', 'ubo-window-close-if'];
    forceWindowClose.injections = [hit, toRegExp];

    /* eslint-disable max-len */

    /**
     * @scriptlet prevent-refresh
     *
     * @description
     * Prevents reloading of a document through a meta "refresh" tag.
     *
     * Related UBO scriptlet:
     * https://github.com/gorhill/uBlock/wiki/Resources-Library#refresh-defuserjs-
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-refresh'[, delay])
     * ```
     *
     * - `delay` - optional, number of seconds for delay that indicates when scriptlet should run. If not set, source tag value will be applied.
     *
     * **Examples**
     * 1. Prevent reloading of a document through a meta "refresh" tag.
     * ```
     *     enrt.eu#%#//scriptlet('prevent-refresh')
     * ```
     *
     * 2. Prevent reloading of a document with delay.
     * ```
     *     cryptodirectories.com#%#//scriptlet('prevent-refresh', 3)
     * ```
     */

    /* eslint-enable max-len */

    function preventRefresh(source, delaySec) {
      var getMetaElements = function getMetaElements() {
        var metaNodes = [];

        try {
          metaNodes = document.querySelectorAll('meta[http-equiv="refresh" i][content]');
        } catch (e) {
          // 'i' attribute flag is problematic in Edge 15
          try {
            metaNodes = document.querySelectorAll('meta[http-equiv="refresh"][content]');
          } catch (e) {
            if (source.verbose) {
              // eslint-disable-next-line no-console
              console.log(e);
            }
          }
        }

        return Array.from(metaNodes);
      };

      var getMetaContentDelay = function getMetaContentDelay(metaElements) {
        var delays = metaElements.map(function (meta) {
          var contentString = meta.getAttribute('content');

          if (contentString.length === 0) {
            return null;
          }

          var contentDelay; // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-http-equiv

          var limiterIndex = contentString.indexOf(';');

          if (limiterIndex !== -1) {
            var delaySubstring = contentString.substring(0, limiterIndex);
            contentDelay = getNumberFromString(delaySubstring);
          } else {
            contentDelay = getNumberFromString(contentString);
          }

          return contentDelay;
        }).filter(function (delay) {
          return delay !== null;
        }); // Get smallest delay of all metas on the page

        var minDelay = delays.reduce(function (a, b) {
          return Math.min(a, b);
        }); // eslint-disable-next-line consistent-return

        return minDelay;
      };

      var stop = function stop() {
        var metaElements = getMetaElements();

        if (metaElements.length === 0) {
          return;
        }

        var secondsToRun = getNumberFromString(delaySec); // Check if argument is provided

        if (!secondsToRun) {
          secondsToRun = getMetaContentDelay(metaElements);
        } // Check if meta tag has delay


        if (!secondsToRun) {
          return;
        }

        var delayMs = secondsToRun * 1000;
        setTimeout(function () {
          window.stop();
          hit(source);
        }, delayMs);
      };

      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', stop, {
          once: true
        });
      } else {
        stop();
      }
    }
    preventRefresh.names = ['prevent-refresh', // Aliases are needed for matching the related scriptlet converted into our syntax
    // These are used by UBO rules syntax
    // https://github.com/gorhill/uBlock/wiki/Resources-Library#general-purpose-scriptlets
    'refresh-defuser.js', 'refresh-defuser', // Prefix 'ubo-' is required to run converted rules
    'ubo-refresh-defuser.js', 'ubo-refresh-defuser'];
    preventRefresh.injections = [hit, getNumberFromString, nativeIsNaN];

    /* eslint-disable max-len, consistent-return */

    /**
     * @scriptlet prevent-element-src-loading
     *
     * @description
     * Prevents target element source loading without triggering 'onerror' listeners and not breaking 'onload' ones.
     *
     * **Syntax**
     * ```
     * example.org#%#//scriptlet('prevent-src', tagName, match)
     * ```
     *
     * - `tagName` - required, case-insensitive target element tagName which `src` property resource loading will be silently prevented; possible values:
     *     - `script`
     *     - `img`
     *     - `iframe`
     * - `match` - required, string or regular expression for matching the element's URL;
     *
     * **Examples**
     * 1. Prevent script source loading:
     * ```
     *     example.org#%#//scriptlet('prevent-element-src-loading', 'script' ,'adsbygoogle')
     * ```
     */

    /* eslint-enable max-len */

    function preventElementSrcLoading(source, tagName, match) {
      // do nothing if browser does not support Proxy or Reflect
      if (typeof Proxy === 'undefined' || typeof Reflect === 'undefined') {
        return;
      }

      var srcMockData = {
        // "KCk9Pnt9" = "()=>{}"
        script: 'data:text/javascript;base64,KCk9Pnt9',
        // Empty 1x1 image
        img: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
        // Empty h1 tag
        iframe: 'data:text/html;base64, PGRpdj48L2Rpdj4='
      };
      var instance;

      if (tagName === 'script') {
        instance = HTMLScriptElement;
      } else if (tagName === 'img') {
        instance = HTMLImageElement;
      } else if (tagName === 'iframe') {
        instance = HTMLIFrameElement;
      } else {
        return;
      } // For websites that use Trusted Types
      // https://w3c.github.io/webappsec-trusted-types/dist/spec/


      var hasTrustedTypes = window.trustedTypes && typeof window.trustedTypes.createPolicy === 'function';
      var policy;

      if (hasTrustedTypes) {
        policy = window.trustedTypes.createPolicy('mock', {
          createScriptURL: function createScriptURL(arg) {
            return arg;
          }
        });
      }

      var SOURCE_PROPERTY_NAME = 'src';
      var searchRegexp = toRegExp(match);

      var setAttributeWrapper = function setAttributeWrapper(target, thisArg, args) {
        // Check if arguments are present
        if (!args[0] || !args[1]) {
          return Reflect.apply(target, thisArg, args);
        }

        var nodeName = thisArg.nodeName.toLowerCase();
        var attrName = args[0].toLowerCase();
        var attrValue = args[1];
        var isMatched = attrName === SOURCE_PROPERTY_NAME && tagName.toLowerCase() === nodeName && srcMockData[nodeName] && searchRegexp.test(attrValue);

        if (!isMatched) {
          return Reflect.apply(target, thisArg, args);
        }

        hit(source); // Forward the URI that corresponds with element's MIME type

        return Reflect.apply(target, thisArg, [attrName, srcMockData[nodeName]]);
      };

      var setAttributeHandler = {
        apply: setAttributeWrapper
      }; // eslint-disable-next-line max-len

      instance.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, setAttributeHandler);
      var origDescriptor = safeGetDescriptor(instance.prototype, SOURCE_PROPERTY_NAME);

      if (!origDescriptor) {
        return;
      }

      Object.defineProperty(instance.prototype, SOURCE_PROPERTY_NAME, {
        enumerable: true,
        configurable: true,
        get: function get() {
          return origDescriptor.get.call(this);
        },
        set: function set(urlValue) {
          var nodeName = this.nodeName.toLowerCase();
          var isMatched = tagName.toLowerCase() === nodeName && srcMockData[nodeName] && searchRegexp.test(urlValue);

          if (!isMatched) {
            origDescriptor.set.call(this, urlValue);
            return;
          } // eslint-disable-next-line no-undef


          if (policy && urlValue instanceof TrustedScriptURL) {
            var trustedSrc = policy.createScriptURL(urlValue);
            origDescriptor.set.call(this, trustedSrc);
            hit(source);
            return;
          }

          origDescriptor.set.call(this, srcMockData[nodeName]);
          hit(source);
        }
      });
    }
    preventElementSrcLoading.names = ['prevent-element-src-loading'];
    preventElementSrcLoading.injections = [hit, toRegExp, safeGetDescriptor];

    /**
     * This file must export all scriptlets which should be accessible
     */

    var scriptletList = /*#__PURE__*/Object.freeze({
        __proto__: null,
        abortOnPropertyRead: abortOnPropertyRead,
        abortOnPropertyWrite: abortOnPropertyWrite,
        preventSetTimeout: preventSetTimeout,
        preventSetInterval: preventSetInterval,
        preventWindowOpen: preventWindowOpen,
        abortCurrentInlineScript: abortCurrentInlineScript,
        setConstant: setConstant,
        removeCookie: removeCookie,
        preventAddEventListener: preventAddEventListener,
        preventBab: preventBab,
        nowebrtc: nowebrtc,
        logAddEventListener: logAddEventListener,
        logEval: logEval,
        log: log,
        noeval: noeval,
        preventEvalIf: preventEvalIf,
        preventFab: preventFab,
        setPopadsDummy: setPopadsDummy,
        preventPopadsNet: preventPopadsNet,
        preventAdfly: preventAdfly,
        debugOnPropertyRead: debugOnPropertyRead,
        debugOnPropertyWrite: debugOnPropertyWrite,
        debugCurrentInlineScript: debugCurrentInlineScript,
        removeAttr: removeAttr,
        setAttr: setAttr,
        removeClass: removeClass,
        disableNewtabLinks: disableNewtabLinks,
        adjustSetInterval: adjustSetInterval,
        adjustSetTimeout: adjustSetTimeout,
        dirString: dirString,
        jsonPrune: jsonPrune,
        preventRequestAnimationFrame: preventRequestAnimationFrame,
        setCookie: setCookie,
        setCookieReload: setCookieReload,
        hideInShadowDom: hideInShadowDom,
        removeInShadowDom: removeInShadowDom,
        preventFetch: preventFetch,
        setLocalStorageItem: setLocalStorageItem,
        setSessionStorageItem: setSessionStorageItem,
        abortOnStackTrace: abortOnStackTrace,
        logOnStacktrace: logOnStacktrace,
        preventXHR: preventXHR,
        forceWindowClose: forceWindowClose,
        preventRefresh: preventRefresh,
        preventElementSrcLoading: preventElementSrcLoading
    });

    /**
     * Store of ADG redirects names and their analogs.
     * As it is not a compatibility table, no need to keep in redirects array third-party redirects.
     *
     * Needed only for conversion purposes.
     * e.g. googletagmanager-gtm is removed and should be removed from compatibility table as well
     * but now it works as alias for google-analytics so it should stay valid for compiler
     */
    var redirects = [{
      adg: '1x1-transparent.gif',
      ubo: '1x1.gif',
      abp: '1x1-transparent-gif'
    }, {
      adg: '2x2-transparent.png',
      ubo: '2x2.png',
      abp: '2x2-transparent-png'
    }, {
      adg: '3x2-transparent.png',
      ubo: '3x2.png',
      abp: '3x2-transparent-png'
    }, {
      adg: '32x32-transparent.png',
      ubo: '32x32.png',
      abp: '32x32-transparent-png'
    }, {
      adg: 'amazon-apstag',
      ubo: 'amazon_apstag.js'
    }, {
      adg: 'ati-smarttag'
    }, {
      adg: 'didomi-loader'
    }, {
      adg: 'click2load.html',
      ubo: 'click2load.html'
    }, {
      adg: 'fingerprintjs2',
      ubo: 'fingerprint2.js'
    }, {
      adg: 'fingerprintjs3',
      ubo: 'fingerprint3.js'
    }, {
      adg: 'google-analytics',
      ubo: 'google-analytics_analytics.js'
    }, {
      adg: 'google-analytics-ga',
      ubo: 'google-analytics_ga.js'
    }, {
      adg: 'googlesyndication-adsbygoogle',
      ubo: 'googlesyndication_adsbygoogle.js'
    }, {
      // https://github.com/AdguardTeam/Scriptlets/issues/162
      adg: 'googlesyndication-adsbygoogle',
      ubo: 'googlesyndication.com/adsbygoogle.js'
    }, {
      // https://github.com/AdguardTeam/Scriptlets/issues/127
      adg: 'googletagmanager-gtm',
      ubo: 'google-analytics_ga.js'
    }, {
      adg: 'googletagservices-gpt',
      ubo: 'googletagservices_gpt.js'
    }, {
      adg: 'google-ima3'
    }, {
      adg: 'gemius'
    }, {
      adg: 'matomo'
    }, {
      adg: 'metrika-yandex-watch'
    }, {
      adg: 'metrika-yandex-tag'
    }, {
      adg: 'naver-wcslog'
    }, {
      adg: 'noeval',
      ubo: 'noeval-silent.js'
    }, {
      adg: 'noopcss',
      abp: 'blank-css'
    }, {
      adg: 'noopframe',
      ubo: 'noop.html',
      abp: 'blank-html'
    }, {
      adg: 'noopjs',
      ubo: 'noop.js',
      abp: 'blank-js'
    }, {
      adg: 'noopjson'
    }, {
      adg: 'nooptext',
      ubo: 'noop.txt',
      abp: 'blank-text'
    }, {
      adg: 'noopmp3-0.1s',
      ubo: 'noop-0.1s.mp3',
      abp: 'blank-mp3'
    }, {
      adg: 'noopmp4-1s',
      ubo: 'noop-1s.mp4',
      abp: 'blank-mp4'
    }, {
      adg: 'noopvmap-1.0',
      ubo: 'noop-vmap1.0.xml'
    }, {
      adg: 'noopvast-2.0'
    }, {
      adg: 'noopvast-3.0'
    }, {
      adg: 'prebid'
    }, {
      adg: 'prevent-bab',
      ubo: 'nobab.js'
    }, {
      adg: 'prevent-bab2',
      ubo: 'nobab2.js'
    }, {
      adg: 'prevent-fab-3.2.0',
      ubo: 'nofab.js'
    }, {
      adg: 'prevent-popads-net',
      ubo: 'popads.js'
    }, {
      adg: 'scorecardresearch-beacon',
      ubo: 'scorecardresearch_beacon.js'
    }, {
      adg: 'set-popads-dummy',
      ubo: 'popads-dummy.js'
    }, {
      adg: 'empty',
      ubo: 'empty'
    }, {
      adg: 'prebid-ads',
      ubo: 'prebid-ads.js'
    }];

    var JS_RULE_MARKER = '#%#';
    var COMMENT_MARKER = '!';
    /**
     * Checks if rule text is comment e.g. !!example.org##+js(set-constant.js, test, false)
     * @param {string} rule
     * @return {boolean}
     */

    var isComment = function isComment(rule) {
      return startsWith(rule, COMMENT_MARKER);
    };
    /* ************************************************************************
     *
     * Scriptlets
     *
     ************************************************************************** */

    /**
     * uBlock scriptlet rule mask
     */


    var UBO_SCRIPTLET_MASK_REG = /#@?#script:inject|#@?#\s*\+js/;
    var UBO_SCRIPTLET_MASK_1 = '##+js';
    var UBO_SCRIPTLET_MASK_2 = '##script:inject';
    var UBO_SCRIPTLET_EXCEPTION_MASK_1 = '#@#+js';
    var UBO_SCRIPTLET_EXCEPTION_MASK_2 = '#@#script:inject';
    /**
     * AdBlock Plus snippet rule mask
     */

    var ABP_SCRIPTLET_MASK = '#$#';
    var ABP_SCRIPTLET_EXCEPTION_MASK = '#@$#';
    /**
     * AdGuard CSS rule mask
     */

    var ADG_CSS_MASK_REG = /#@?\$#.+?\s*\{.*\}\s*$/g;
    /**
     * Checks if the `rule` is AdGuard scriptlet rule
     * @param {string} rule - rule text
     */

    var isAdgScriptletRule = function isAdgScriptletRule(rule) {
      return !isComment(rule) && rule.indexOf(ADG_SCRIPTLET_MASK) > -1;
    };
    /**
     * Checks if the `rule` is uBO scriptlet rule
     * @param {string} rule rule text
     */


    var isUboScriptletRule = function isUboScriptletRule(rule) {
      return (rule.indexOf(UBO_SCRIPTLET_MASK_1) > -1 || rule.indexOf(UBO_SCRIPTLET_MASK_2) > -1 || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_1) > -1 || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_2) > -1) && UBO_SCRIPTLET_MASK_REG.test(rule) && !isComment(rule);
    };
    /**
     * Checks if the `rule` is AdBlock Plus snippet
     * @param {string} rule rule text
     */


    var isAbpSnippetRule = function isAbpSnippetRule(rule) {
      return (rule.indexOf(ABP_SCRIPTLET_MASK) > -1 || rule.indexOf(ABP_SCRIPTLET_EXCEPTION_MASK) > -1) && rule.search(ADG_CSS_MASK_REG) === -1 && !isComment(rule);
    };
    /**
     * Finds scriptlet by it's name
     * @param {string} name - scriptlet name
     */


    var getScriptletByName = function getScriptletByName(name) {
      var scriptlets = Object.keys(scriptletList).map(function (key) {
        return scriptletList[key];
      });
      return scriptlets.find(function (s) {
        return s.names // full match name checking
        && (s.names.indexOf(name) > -1 // or check ubo alias name without '.js' at the end
        || !endsWith(name, '.js') && s.names.indexOf("".concat(name, ".js")) > -1);
      });
    };
    /**
     * Checks if the scriptlet name is valid
     * @param {string} name - Scriptlet name
     */


    var isValidScriptletName = function isValidScriptletName(name) {
      if (!name) {
        return false;
      }

      var scriptlet = getScriptletByName(name);

      if (!scriptlet) {
        return false;
      }

      return true;
    };
    /* ************************************************************************
     *
     * Redirects
     *
     ************************************************************************** */

    /**
     * Redirect resources markers
     */


    var ADG_UBO_REDIRECT_MARKER = 'redirect=';
    var ADG_UBO_REDIRECT_RULE_MARKER = 'redirect-rule=';
    var ABP_REDIRECT_MARKER = 'rewrite=abp-resource:';
    var EMPTY_REDIRECT_MARKER = 'empty';
    var VALID_SOURCE_TYPES = ['image', 'media', 'subdocument', 'stylesheet', 'script', 'xmlhttprequest', 'other'];
    /**
     * Source types for redirect rules if there is no one of them.
     * Used for ADG -> UBO conversion.
     */

    var ABSENT_SOURCE_TYPE_REPLACEMENT = [{
      NAME: 'nooptext',
      TYPES: VALID_SOURCE_TYPES
    }, {
      NAME: 'noopjs',
      TYPES: ['script']
    }, {
      NAME: 'noopframe',
      TYPES: ['subdocument']
    }, {
      NAME: '1x1-transparent.gif',
      TYPES: ['image']
    }, {
      NAME: 'noopmp3-0.1s',
      TYPES: ['media']
    }, {
      NAME: 'noopmp4-1s',
      TYPES: ['media']
    }, {
      NAME: 'googlesyndication-adsbygoogle',
      TYPES: ['xmlhttprequest', 'script']
    }, {
      NAME: 'google-analytics',
      TYPES: ['script']
    }, {
      NAME: 'googletagservices-gpt',
      TYPES: ['script']
    }];
    var validAdgRedirects = redirects.filter(function (el) {
      return el.adg;
    });
    /**
     * Compatibility object where KEYS = UBO redirect names and VALUES = ADG redirect names
     * It's used for UBO -> ADG converting
     */

    var uboToAdgCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
      return el.ubo;
    }).map(function (el) {
      return [el.ubo, el.adg];
    }));
    /**
     * Compatibility object where KEYS = ABP redirect names and VALUES = ADG redirect names
     * It's used for ABP -> ADG converting
     */

    var abpToAdgCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
      return el.abp;
    }).map(function (el) {
      return [el.abp, el.adg];
    }));
    /**
     * Compatibility object where KEYS = UBO redirect names and VALUES = ADG redirect names
     * It's used for ADG -> UBO converting
     */

    var adgToUboCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
      return el.ubo;
    }).map(function (el) {
      return [el.adg, el.ubo];
    }));
    /**
     * Needed for AdGuard redirect names validation where KEYS = **valid** AdGuard redirect names
     * 'adgToUboCompatibility' is still needed for ADG -> UBO converting
     */

    var validAdgCompatibility = getObjectFromEntries(validAdgRedirects.map(function (el) {
      return [el.adg, 'valid adg redirect'];
    }));
    var REDIRECT_RULE_TYPES = {
      VALID_ADG: {
        redirectMarker: ADG_UBO_REDIRECT_MARKER,
        redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
        compatibility: validAdgCompatibility
      },
      ADG: {
        redirectMarker: ADG_UBO_REDIRECT_MARKER,
        redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
        compatibility: adgToUboCompatibility
      },
      UBO: {
        redirectMarker: ADG_UBO_REDIRECT_MARKER,
        redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
        compatibility: uboToAdgCompatibility
      },
      ABP: {
        redirectMarker: ABP_REDIRECT_MARKER,
        compatibility: abpToAdgCompatibility
      }
    };
    /**
     * Parses redirect rule modifiers
     * @param {string} rule
     * @returns {Array}
     */

    var parseModifiers = function parseModifiers(rule) {
      return substringAfter(rule, '$').split(',');
    };
    /**
     * Gets redirect resource name
     * @param {string} rule
     * @param {string} marker - specific Adg/Ubo or Abp redirect resources marker
     * @returns {string} - redirect resource name
     */


    var getRedirectName = function getRedirectName(rule, marker) {
      var ruleModifiers = parseModifiers(rule);
      var redirectNamePart = ruleModifiers.find(function (el) {
        return el.indexOf(marker) > -1;
      });
      return substringAfter(redirectNamePart, marker);
    };
    /**
     * Checks if the `rule` is AdGuard redirect rule.
     * Discards comments and JS rules and checks if the `rule` has 'redirect' modifier.
     * @param {string} rule - rule text
     */


    var isAdgRedirectRule = function isAdgRedirectRule(rule) {
      var MARKER_IN_BASE_PART_MASK = '/((?!\\$|\\,).{1})redirect((-rule)?)=(.{0,}?)\\$(popup)?/';
      return !isComment(rule) && (rule.indexOf(REDIRECT_RULE_TYPES.ADG.redirectMarker) > -1 || rule.indexOf(REDIRECT_RULE_TYPES.ADG.redirectRuleMarker) > -1) // some js rules may have 'redirect=' in it, so we should get rid of them
      && rule.indexOf(JS_RULE_MARKER) === -1 // get rid of rules like '_redirect=*://look.$popup'
      && !toRegExp(MARKER_IN_BASE_PART_MASK).test(rule);
    }; // const getRedirectResourceMarkerData = ()

    /**
     * Checks if the `rule` satisfies the `type`
     * @param {string} rule - rule text
     * @param {'VALID_ADG'|'ADG'|'UBO'|'ABP'} type - type of a redirect rule
     */


    var isRedirectRuleByType = function isRedirectRuleByType(rule, type) {
      var _REDIRECT_RULE_TYPES$ = REDIRECT_RULE_TYPES[type],
          redirectMarker = _REDIRECT_RULE_TYPES$.redirectMarker,
          redirectRuleMarker = _REDIRECT_RULE_TYPES$.redirectRuleMarker,
          compatibility = _REDIRECT_RULE_TYPES$.compatibility;

      if (rule && !isComment(rule)) {
        var marker; // check if there is a $redirect-rule modifier in rule

        var markerIndex = redirectRuleMarker ? rule.indexOf(redirectRuleMarker) : -1;

        if (markerIndex > -1) {
          marker = redirectRuleMarker;
        } else {
          // check if there $redirect modifier in rule
          markerIndex = rule.indexOf(redirectMarker);

          if (markerIndex > -1) {
            marker = redirectMarker;
          } else {
            return false;
          }
        }

        var redirectName = getRedirectName(rule, marker);

        if (!redirectName) {
          return false;
        }

        return redirectName === Object.keys(compatibility).find(function (el) {
          return el === redirectName;
        });
      }

      return false;
    };
    /**
    * Checks if the `rule` is **valid** AdGuard redirect resource rule
    * @param {string} rule - rule text
    * @returns {boolean}
    */


    var isValidAdgRedirectRule = function isValidAdgRedirectRule(rule) {
      return isRedirectRuleByType(rule, 'VALID_ADG');
    };
    /**
    * Checks if the AdGuard redirect `rule` has Ubo analog. Needed for Adg->Ubo conversion
    * @param {string} rule - AdGuard rule text
    * @returns {boolean} - true if the rule can be converted to Ubo
    */


    var isAdgRedirectCompatibleWithUbo = function isAdgRedirectCompatibleWithUbo(rule) {
      return isAdgRedirectRule(rule) && isRedirectRuleByType(rule, 'ADG');
    };
    /**
    * Checks if the Ubo redirect `rule` has AdGuard analog. Needed for Ubo->Adg conversion
    * @param {string} rule - Ubo rule text
    * @returns {boolean} - true if the rule can be converted to AdGuard
    */


    var isUboRedirectCompatibleWithAdg = function isUboRedirectCompatibleWithAdg(rule) {
      return isRedirectRuleByType(rule, 'UBO');
    };
    /**
    * Checks if the Abp redirect `rule` has AdGuard analog. Needed for Abp->Adg conversion
    * @param {string} rule - Abp rule text
    * @returns {boolean} - true if the rule can be converted to AdGuard
    */


    var isAbpRedirectCompatibleWithAdg = function isAbpRedirectCompatibleWithAdg(rule) {
      return isRedirectRuleByType(rule, 'ABP');
    };
    /**
     * Checks if the rule has specified content type before Adg -> Ubo conversion.
     *
     * Used ONLY for Adg -> Ubo conversion
     * because Ubo redirect rules must contain content type, but Adg and Abp must not.
     *
     * Also source type can not be added automatically because of such valid rules:
     * ! Abp:
     * $rewrite=abp-resource:blank-js,xmlhttprequest
     * ! Adg:
     * $script,redirect=noopvast-2.0
     * $xmlhttprequest,redirect=noopvast-2.0
     *
     * @param {string} rule
     * @returns {boolean}
     */


    var hasValidContentType = function hasValidContentType(rule) {
      var ruleModifiers = parseModifiers(rule); // rule can have more than one source type modifier

      var sourceTypes = ruleModifiers.filter(function (el) {
        return VALID_SOURCE_TYPES.indexOf(el) > -1;
      });
      var isSourceTypeSpecified = sourceTypes.length > 0; // eslint-disable-next-line max-len

      var isEmptyRedirect = ruleModifiers.indexOf("".concat(ADG_UBO_REDIRECT_MARKER).concat(EMPTY_REDIRECT_MARKER)) > -1 || ruleModifiers.indexOf("".concat(ADG_UBO_REDIRECT_RULE_MARKER).concat(EMPTY_REDIRECT_MARKER)) > -1;

      if (isEmptyRedirect) {
        // no source type for 'empty' is allowed
        return true;
      }

      return isSourceTypeSpecified;
    };

    var validator = {
      UBO_SCRIPTLET_MASK_REG: UBO_SCRIPTLET_MASK_REG,
      ABP_SCRIPTLET_MASK: ABP_SCRIPTLET_MASK,
      ABP_SCRIPTLET_EXCEPTION_MASK: ABP_SCRIPTLET_EXCEPTION_MASK,
      isComment: isComment,
      isAdgScriptletRule: isAdgScriptletRule,
      isUboScriptletRule: isUboScriptletRule,
      isAbpSnippetRule: isAbpSnippetRule,
      getScriptletByName: getScriptletByName,
      isValidScriptletName: isValidScriptletName,
      ADG_UBO_REDIRECT_RULE_MARKER: ADG_UBO_REDIRECT_RULE_MARKER,
      REDIRECT_RULE_TYPES: REDIRECT_RULE_TYPES,
      ABSENT_SOURCE_TYPE_REPLACEMENT: ABSENT_SOURCE_TYPE_REPLACEMENT,
      isAdgRedirectRule: isAdgRedirectRule,
      isValidAdgRedirectRule: isValidAdgRedirectRule,
      isAdgRedirectCompatibleWithUbo: isAdgRedirectCompatibleWithUbo,
      isUboRedirectCompatibleWithAdg: isUboRedirectCompatibleWithAdg,
      isAbpRedirectCompatibleWithAdg: isAbpRedirectCompatibleWithAdg,
      parseModifiers: parseModifiers,
      getRedirectName: getRedirectName,
      hasValidContentType: hasValidContentType
    };

    function _arrayLikeToArray(arr, len) {
      if (len == null || len > arr.length) len = arr.length;

      for (var i = 0, arr2 = new Array(len); i < len; i++) {
        arr2[i] = arr[i];
      }

      return arr2;
    }

    var arrayLikeToArray = _arrayLikeToArray;

    function _arrayWithoutHoles(arr) {
      if (Array.isArray(arr)) return arrayLikeToArray(arr);
    }

    var arrayWithoutHoles = _arrayWithoutHoles;

    function _iterableToArray(iter) {
      if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
    }

    var iterableToArray = _iterableToArray;

    function _unsupportedIterableToArray(o, minLen) {
      if (!o) return;
      if (typeof o === "string") return arrayLikeToArray(o, minLen);
      var n = Object.prototype.toString.call(o).slice(8, -1);
      if (n === "Object" && o.constructor) n = o.constructor.name;
      if (n === "Map" || n === "Set") return Array.from(o);
      if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
    }

    var unsupportedIterableToArray = _unsupportedIterableToArray;

    function _nonIterableSpread() {
      throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
    }

    var nonIterableSpread = _nonIterableSpread;

    function _toConsumableArray(arr) {
      return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();
    }

    var toConsumableArray = _toConsumableArray;

    function _arrayWithHoles(arr) {
      if (Array.isArray(arr)) return arr;
    }

    var arrayWithHoles = _arrayWithHoles;

    function _nonIterableRest() {
      throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
    }

    var nonIterableRest = _nonIterableRest;

    function _toArray(arr) {
      return arrayWithHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableRest();
    }

    var toArray = _toArray;

    /**
     * AdGuard scriptlet rule
     */

    var ADGUARD_SCRIPTLET_MASK_REG = /#@?%#\/\/scriptlet\(.+\)/; // eslint-disable-next-line no-template-curly-in-string

    var ADGUARD_SCRIPTLET_TEMPLATE = '${domains}#%#//scriptlet(${args})'; // eslint-disable-next-line no-template-curly-in-string

    var ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE = '${domains}#@%#//scriptlet(${args})';
    /**
     * uBlock scriptlet rule mask
     */
    // eslint-disable-next-line no-template-curly-in-string

    var UBO_SCRIPTLET_TEMPLATE = '${domains}##+js(${args})'; // eslint-disable-next-line no-template-curly-in-string

    var UBO_SCRIPTLET_EXCEPTION_TEMPLATE = '${domains}#@#+js(${args})';
    var UBO_ALIAS_NAME_MARKER = 'ubo-';
    var UBO_SCRIPTLET_JS_ENDING = '.js'; // https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#xhr

    var UBO_XHR_TYPE = 'xhr';
    var ADG_XHR_TYPE = 'xmlhttprequest';
    var ADG_SET_CONSTANT_NAME = 'set-constant';
    var ADG_SET_CONSTANT_EMPTY_STRING = '';
    var UBO_SET_CONSTANT_EMPTY_STRING = '\'\'';
    var ADG_PREVENT_FETCH_NAME = 'prevent-fetch';
    var ADG_PREVENT_FETCH_EMPTY_STRING = '';
    var ADG_PREVENT_FETCH_WILDCARD = getWildcardSymbol();
    var UBO_NO_FETCH_IF_WILDCARD = '/^/';
    var ESCAPED_COMMA_SEPARATOR = '\\,';
    var COMMA_SEPARATOR = ',';
    var REMOVE_ATTR_METHOD = 'removeAttr';
    var REMOVE_CLASS_METHOD = 'removeClass';
    var REMOVE_ATTR_ALIASES = scriptletList[REMOVE_ATTR_METHOD].names;
    var REMOVE_CLASS_ALIASES = scriptletList[REMOVE_CLASS_METHOD].names;
    var ADG_REMOVE_ATTR_NAME = REMOVE_ATTR_ALIASES[0];
    var ADG_REMOVE_CLASS_NAME = REMOVE_CLASS_ALIASES[0];
    var REMOVE_ATTR_CLASS_APPLYING = ['asap', 'stay', 'complete'];
    /**
     * Returns array of strings separated by space which not in quotes
     * @param {string} str
     */

    var getSentences = function getSentences(str) {
      var reg = /'.*?'|".*?"|\S+/g;
      return str.match(reg);
    };
    /**
     * Replaces string with data by placeholders
     * @param {string} str
     * @param {Object} data - where keys are placeholders names
     */


    var replacePlaceholders = function replacePlaceholders(str, data) {
      return Object.keys(data).reduce(function (acc, key) {
        var reg = new RegExp("\\$\\{".concat(key, "\\}"), 'g');
        acc = acc.replace(reg, data[key]);
        return acc;
      }, str);
    };

    var splitArgs = function splitArgs(str) {
      var args = [];
      var prevArgStart = 0;

      for (var i = 0; i < str.length; i += 1) {
        // do not split args by escaped comma
        // https://github.com/AdguardTeam/Scriptlets/issues/133
        if (str[i] === COMMA_SEPARATOR && str[i - 1] !== '\\') {
          args.push(str.slice(prevArgStart, i).trim());
          prevArgStart = i + 1;
        }
      } // collect arg after last comma


      args.push(str.slice(prevArgStart, str.length).trim());
      return args;
    };
    /**
     * Validates remove-attr/class scriptlet args
     * @param {string[]} parsedArgs
     * @returns {string[]|Error} valid args OR error for invalid selector
     */


    var validateRemoveAttrClassArgs = function validateRemoveAttrClassArgs(parsedArgs) {
      // remove-attr/class scriptlet might have multiple selectors separated by comma. so we should:
      // 1. check if last arg is 'applying' parameter
      // 2. join 'selector' into one arg
      // 3. combine all args
      // https://github.com/AdguardTeam/Scriptlets/issues/133
      var lastArg = parsedArgs.pop();

      var _parsedArgs = toArray(parsedArgs),
          name = _parsedArgs[0],
          value = _parsedArgs[1],
          restArgs = _parsedArgs.slice(2);

      var applying; // check the last parsed arg for matching possible 'applying' vale

      if (REMOVE_ATTR_CLASS_APPLYING.some(function (el) {
        return lastArg.indexOf(el) > -1;
      })) {
        applying = lastArg;
      } else {
        restArgs.push(lastArg);
      }

      var selector = replaceAll(restArgs.join(', '), ESCAPED_COMMA_SEPARATOR, COMMA_SEPARATOR);

      if (selector.length > 0 && typeof document !== 'undefined') {
        // empty selector is valid for these scriptlets as it applies to all elements,
        // all other selectors should be validated
        // e.g. #%#//scriptlet('ubo-remove-class.js', 'blur', ', html')
        document.querySelectorAll(selector);
      }

      var validArgs = applying ? [name, value, selector, applying] : [name, value, selector];
      return validArgs;
    };
    /**
     * Converts string of UBO scriptlet rule to AdGuard scriptlet rule
     * @param {string} rule - UBO scriptlet rule
     * @returns {string[]} - array with one AdGuard scriptlet rule
     */


    var convertUboScriptletToAdg = function convertUboScriptletToAdg(rule) {
      var domains = getBeforeRegExp(rule, validator.UBO_SCRIPTLET_MASK_REG);
      var mask = rule.match(validator.UBO_SCRIPTLET_MASK_REG)[0];
      var template;

      if (mask.indexOf('@') > -1) {
        template = ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE;
      } else {
        template = ADGUARD_SCRIPTLET_TEMPLATE;
      }

      var argsStr = getStringInBraces(rule);
      var parsedArgs = splitArgs(argsStr);
      var scriptletName = parsedArgs[0].indexOf(UBO_SCRIPTLET_JS_ENDING) > -1 ? "ubo-".concat(parsedArgs[0]) : "ubo-".concat(parsedArgs[0]).concat(UBO_SCRIPTLET_JS_ENDING);

      if (REMOVE_ATTR_ALIASES.indexOf(scriptletName) > -1 || REMOVE_CLASS_ALIASES.indexOf(scriptletName) > -1) {
        parsedArgs = validateRemoveAttrClassArgs(parsedArgs);
      }

      var args = parsedArgs.map(function (arg, index) {
        var outputArg = arg;

        if (index === 0) {
          outputArg = scriptletName;
        } // for example: example.org##+js(abort-current-inline-script, $, popup)


        if (arg === '$') {
          outputArg = '$$';
        }

        return outputArg;
      }).map(function (arg) {
        return wrapInSingleQuotes(arg);
      }).join("".concat(COMMA_SEPARATOR, " "));
      var adgRule = replacePlaceholders(template, {
        domains: domains,
        args: args
      });
      return [adgRule];
    };
    /**
     * Convert string of ABP snippet rule to AdGuard scriptlet rule
     * @param {string} rule - ABP snippet rule
     * @returns {Array} - array of AdGuard scriptlet rules -
     * one or few items depends on Abp-rule
     */

    var convertAbpSnippetToAdg = function convertAbpSnippetToAdg(rule) {
      var SEMICOLON_DIVIDER = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/g;
      var mask = rule.indexOf(validator.ABP_SCRIPTLET_MASK) > -1 ? validator.ABP_SCRIPTLET_MASK : validator.ABP_SCRIPTLET_EXCEPTION_MASK;
      var template = mask === validator.ABP_SCRIPTLET_MASK ? ADGUARD_SCRIPTLET_TEMPLATE : ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE;
      var domains = substringBefore(rule, mask);
      var args = substringAfter(rule, mask);
      return args.split(SEMICOLON_DIVIDER).map(function (args) {
        return getSentences(args).filter(function (arg) {
          return arg;
        }).map(function (arg, index) {
          return index === 0 ? "abp-".concat(arg) : arg;
        }).map(function (arg) {
          return wrapInSingleQuotes(arg);
        }).join("".concat(COMMA_SEPARATOR, " "));
      }).map(function (args) {
        return replacePlaceholders(template, {
          domains: domains,
          args: args
        });
      });
    };
    /**
     * Converts scriptlet rule to AdGuard one
     * @param {string} rule
     * @returns {Array} - array of AdGuard scriptlet rules -
     * one item for Adg and Ubo or few items for Abp
     */

    var convertScriptletToAdg = function convertScriptletToAdg(rule) {
      var result;

      if (validator.isUboScriptletRule(rule)) {
        result = convertUboScriptletToAdg(rule);
      } else if (validator.isAbpSnippetRule(rule)) {
        result = convertAbpSnippetToAdg(rule);
      } else if (validator.isAdgScriptletRule(rule) || validator.isComment(rule)) {
        result = [rule];
      }

      return result;
    };
    /**
     * Converts UBO scriptlet rule to AdGuard one
     * @param {string} rule - AdGuard scriptlet rule
     * @returns {string} - UBO scriptlet rule
     */

    var convertAdgScriptletToUbo = function convertAdgScriptletToUbo(rule) {
      var res;

      if (validator.isAdgScriptletRule(rule)) {
        var _parseRule = parseRule(rule),
            parsedName = _parseRule.name,
            parsedParams = _parseRule.args;

        var preparedParams; // https://github.com/AdguardTeam/FiltersCompiler/issues/102

        if (parsedName === ADG_SET_CONSTANT_NAME && parsedParams[1] === ADG_SET_CONSTANT_EMPTY_STRING) {
          preparedParams = [parsedParams[0], UBO_SET_CONSTANT_EMPTY_STRING];
        } else if (parsedName === ADG_PREVENT_FETCH_NAME // https://github.com/AdguardTeam/Scriptlets/issues/109
        && (parsedParams[0] === ADG_PREVENT_FETCH_WILDCARD || parsedParams[0] === ADG_PREVENT_FETCH_EMPTY_STRING)) {
          preparedParams = [UBO_NO_FETCH_IF_WILDCARD];
        } else if ((parsedName === ADG_REMOVE_ATTR_NAME || parsedName === ADG_REMOVE_CLASS_NAME) && parsedParams[1] && parsedParams[1].indexOf(COMMA_SEPARATOR) > -1) {
          preparedParams = [parsedParams[0], replaceAll(parsedParams[1], COMMA_SEPARATOR, ESCAPED_COMMA_SEPARATOR)];
        } else {
          preparedParams = parsedParams;
        } // object of name and aliases for the Adg-scriptlet


        var adgScriptletObject = Object.keys(scriptletList).map(function (el) {
          return scriptletList[el];
        }).map(function (s) {
          var _s$names = toArray(s.names),
              name = _s$names[0],
              aliases = _s$names.slice(1);

          return {
            name: name,
            aliases: aliases
          };
        }).find(function (el) {
          return el.name === parsedName || el.aliases.indexOf(parsedName) >= 0;
        });
        var aliases = adgScriptletObject.aliases;

        if (aliases.length > 0) {
          var uboAlias = adgScriptletObject.aliases // eslint-disable-next-line no-restricted-properties
          .find(function (alias) {
            return alias.includes(UBO_ALIAS_NAME_MARKER);
          });

          if (uboAlias) {
            var mask = rule.match(ADGUARD_SCRIPTLET_MASK_REG)[0];
            var template;

            if (mask.indexOf('@') > -1) {
              template = UBO_SCRIPTLET_EXCEPTION_TEMPLATE;
            } else {
              template = UBO_SCRIPTLET_TEMPLATE;
            }

            var domains = getBeforeRegExp(rule, ADGUARD_SCRIPTLET_MASK_REG);
            var uboName = uboAlias.replace(UBO_ALIAS_NAME_MARKER, '') // '.js' in the Ubo scriptlet name can be omitted
            // https://github.com/gorhill/uBlock/wiki/Resources-Library#general-purpose-scriptlets
            .replace(UBO_SCRIPTLET_JS_ENDING, '');
            var args = preparedParams.length > 0 ? "".concat(uboName, ", ").concat(preparedParams.join("".concat(COMMA_SEPARATOR, " "))) : uboName;
            var uboRule = replacePlaceholders(template, {
              domains: domains,
              args: args
            });
            res = uboRule;
          }
        }
      }

      return res;
    };
    /**
     * Checks whether the ADG scriptlet exists or UBO/ABP scriptlet is compatible to ADG
     * @param {string} input - can be ADG or UBO or ABP scriptlet rule
     * @returns {boolean}
     */

    var isValidScriptletRule = function isValidScriptletRule(input) {
      if (!input) {
        return false;
      } // ABP 'input' rule may contain more than one snippet


      var rulesArray = convertScriptletToAdg(input); // checking if each of parsed scriptlets is valid
      // if at least one of them is not valid - whole 'input' rule is not valid too

      var isValid = rulesArray.every(function (rule) {
        var parsedRule = parseRule(rule);
        return validator.isValidScriptletName(parsedRule.name);
      });
      return isValid;
    };
    /**
     * Gets index and redirect resource marker from UBO/ADG modifiers array
     * @param {string[]} modifiers
     * @param {Object} redirectsData validator.REDIRECT_RULE_TYPES.(UBO|ADG)
     * @param {string} rule
     * @returns {Object} { index, marker }
     */

    var getMarkerData = function getMarkerData(modifiers, redirectsData, rule) {
      var marker;
      var index = modifiers.findIndex(function (m) {
        return m.indexOf(redirectsData.redirectRuleMarker) > -1;
      });

      if (index > -1) {
        marker = redirectsData.redirectRuleMarker;
      } else {
        index = modifiers.findIndex(function (m) {
          return m.indexOf(redirectsData.redirectMarker) > -1;
        });

        if (index > -1) {
          marker = redirectsData.redirectMarker;
        } else {
          throw new Error("No redirect resource modifier found in rule: ".concat(rule));
        }
      }

      return {
        index: index,
        marker: marker
      };
    };
    /**
     * Converts Ubo redirect rule to Adg one
     * @param {string} rule
     * @returns {string}
     */


    var convertUboRedirectToAdg = function convertUboRedirectToAdg(rule) {
      var firstPartOfRule = substringBefore(rule, '$');
      var uboModifiers = validator.parseModifiers(rule);
      var uboMarkerData = getMarkerData(uboModifiers, validator.REDIRECT_RULE_TYPES.UBO, rule);
      var adgModifiers = uboModifiers.map(function (modifier, index) {
        if (index === uboMarkerData.index) {
          var uboName = substringAfter(modifier, uboMarkerData.marker);
          var adgName = validator.REDIRECT_RULE_TYPES.UBO.compatibility[uboName];
          var adgMarker = uboMarkerData.marker === validator.ADG_UBO_REDIRECT_RULE_MARKER ? validator.REDIRECT_RULE_TYPES.ADG.redirectRuleMarker : validator.REDIRECT_RULE_TYPES.ADG.redirectMarker;
          return "".concat(adgMarker).concat(adgName);
        }

        if (modifier === UBO_XHR_TYPE) {
          return ADG_XHR_TYPE;
        }

        return modifier;
      }).join(COMMA_SEPARATOR);
      return "".concat(firstPartOfRule, "$").concat(adgModifiers);
    };
    /**
     * Converts Abp redirect rule to Adg one
     * @param {string} rule
     * @returns {string}
     */

    var convertAbpRedirectToAdg = function convertAbpRedirectToAdg(rule) {
      var firstPartOfRule = substringBefore(rule, '$');
      var abpModifiers = validator.parseModifiers(rule);
      var adgModifiers = abpModifiers.map(function (modifier) {
        if (modifier.indexOf(validator.REDIRECT_RULE_TYPES.ABP.redirectMarker) > -1) {
          var abpName = substringAfter(modifier, validator.REDIRECT_RULE_TYPES.ABP.redirectMarker);
          var adgName = validator.REDIRECT_RULE_TYPES.ABP.compatibility[abpName];
          return "".concat(validator.REDIRECT_RULE_TYPES.ADG.redirectMarker).concat(adgName);
        }

        return modifier;
      }).join(COMMA_SEPARATOR);
      return "".concat(firstPartOfRule, "$").concat(adgModifiers);
    };
    /**
     * Converts redirect rule to AdGuard one
     * @param {string} rule
     * @returns {string}
     */

    var convertRedirectToAdg = function convertRedirectToAdg(rule) {
      var result;

      if (validator.isUboRedirectCompatibleWithAdg(rule)) {
        result = convertUboRedirectToAdg(rule);
      } else if (validator.isAbpRedirectCompatibleWithAdg(rule)) {
        result = convertAbpRedirectToAdg(rule);
      } else if (validator.isValidAdgRedirectRule(rule)) {
        result = rule;
      }

      return result;
    };
    /**
     * Converts Adg redirect rule to Ubo one
     * 1. Checks if there is Ubo analog for Adg rule
     * 2. Parses the rule and checks if there are any source type modifiers which are required by Ubo
     *    and if there are no one we add it manually to the end.
     *    Source types are chosen according to redirect name
     *    e.g. ||ad.com^$redirect=<name>,important  ->>  ||ad.com^$redirect=<name>,important,script
     * 3. Replaces Adg redirect name by Ubo analog
     * @param {string} rule
     * @returns {string}
     */

    var convertAdgRedirectToUbo = function convertAdgRedirectToUbo(rule) {
      if (!validator.isAdgRedirectCompatibleWithUbo(rule)) {
        throw new Error("Unable to convert for uBO - unsupported redirect in rule: ".concat(rule));
      }

      var basePart = substringBefore(rule, '$');
      var adgModifiers = validator.parseModifiers(rule);
      var adgMarkerData = getMarkerData(adgModifiers, validator.REDIRECT_RULE_TYPES.ADG, rule);
      var adgRedirectName = adgModifiers[adgMarkerData.index].slice(adgMarkerData.marker.length);

      if (!validator.hasValidContentType(rule)) {
        // add missed source types as content type modifiers
        var sourceTypesData = validator.ABSENT_SOURCE_TYPE_REPLACEMENT.find(function (el) {
          return el.NAME === adgRedirectName;
        });

        if (typeof sourceTypesData === 'undefined') {
          // eslint-disable-next-line max-len
          throw new Error("Unable to convert for uBO - no types to add for specific redirect in rule: ".concat(rule));
        }

        var additionModifiers = sourceTypesData.TYPES;
        adgModifiers.push.apply(adgModifiers, toConsumableArray(additionModifiers));
      }

      var uboModifiers = adgModifiers.map(function (el, index) {
        if (index === adgMarkerData.index) {
          var uboMarker = adgMarkerData.marker === validator.ADG_UBO_REDIRECT_RULE_MARKER ? validator.REDIRECT_RULE_TYPES.UBO.redirectRuleMarker : validator.REDIRECT_RULE_TYPES.UBO.redirectMarker; // eslint-disable-next-line max-len

          var uboRedirectName = validator.REDIRECT_RULE_TYPES.ADG.compatibility[adgRedirectName];
          return "".concat(uboMarker).concat(uboRedirectName);
        }

        return el;
      }).join(COMMA_SEPARATOR);
      return "".concat(basePart, "$").concat(uboModifiers);
    };

    /**
     * @redirect google-analytics
     *
     * @description
     * Mocks Google's Analytics and Tag Manager APIs.
     * [Covers obsolete googletagmanager-gtm redirect functionality](https://github.com/AdguardTeam/Scriptlets/issues/127).
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/8cd2a1d263a96421487b39040c1d23eb01169484/src/web_accessible_resources/google-analytics_analytics.js
     *
     * **Example**
     * ```
     * ||google-analytics.com/analytics.js$script,redirect=google-analytics
     * ||googletagmanager.com/gtm.js$script,redirect=googletagmanager-gtm
     * ```
     */

    function GoogleAnalytics(source) {
      // eslint-disable-next-line func-names
      var Tracker = function Tracker() {}; // constructor


      var proto = Tracker.prototype;
      proto.get = noopFunc;
      proto.set = noopFunc;
      proto.send = noopFunc;
      var googleAnalyticsName = window.GoogleAnalyticsObject || 'ga'; // a -- fake arg for 'ga.length < 1' antiadblock checking
      // eslint-disable-next-line no-unused-vars

      function ga(a) {
        var len = arguments.length;

        if (len === 0) {
          return;
        } // eslint-disable-next-line prefer-rest-params


        var lastArg = arguments[len - 1];
        var replacer;

        if (lastArg instanceof Object && lastArg !== null && typeof lastArg.hitCallback === 'function') {
          replacer = lastArg.hitCallback;
        } else if (typeof lastArg === 'function') {
          // https://github.com/AdguardTeam/Scriptlets/issues/98
          replacer = function replacer() {
            lastArg(ga.create());
          };
        }

        try {
          setTimeout(replacer, 1); // eslint-disable-next-line no-empty
        } catch (ex) {}
      }

      ga.create = function () {
        return new Tracker();
      }; // https://github.com/AdguardTeam/Scriptlets/issues/134


      ga.getByName = function () {
        return new Tracker();
      };

      ga.getAll = function () {
        return [new Tracker()];
      };

      ga.remove = noopFunc;
      ga.loaded = true;
      window[googleAnalyticsName] = ga;
      var _window = window,
          dataLayer = _window.dataLayer,
          google_optimize = _window.google_optimize; // eslint-disable-line camelcase

      if (dataLayer instanceof Object === false) {
        return;
      }

      if (dataLayer.hide instanceof Object && typeof dataLayer.hide.end === 'function') {
        dataLayer.hide.end();
      }
      /**
       * checks data object and delays callback
       * @param {Object|Array} data gtag payload
       * @param {string} funcName callback prop name
       * @returns
       */


      var handleCallback = function handleCallback(dataObj, funcName) {
        if (dataObj && typeof dataObj[funcName] === 'function') {
          setTimeout(dataObj[funcName]);
        }
      };

      if (typeof dataLayer.push === 'function') {
        dataLayer.push = function (data) {
          if (data instanceof Object) {
            handleCallback(data, 'eventCallback'); // eslint-disable-next-line no-restricted-syntax, guard-for-in

            for (var key in data) {
              handleCallback(data[key], 'event_callback');
            } // eslint-disable-next-line no-prototype-builtins


            if (!data.hasOwnProperty('eventCallback') && !data.hasOwnProperty('eventCallback')) {
              [].push.call(window.dataLayer, data);
            }
          }

          if (Array.isArray(data)) {
            data.forEach(function (arg) {
              handleCallback(arg, 'callback');
            });
          }

          return noopFunc;
        };
      } // https://github.com/AdguardTeam/Scriptlets/issues/81


      if (google_optimize instanceof Object && typeof google_optimize.get === 'function') {
        // eslint-disable-line camelcase
        var googleOptimizeWrapper = {
          get: noopFunc
        };
        window.google_optimize = googleOptimizeWrapper;
      }

      hit(source);
    }
    GoogleAnalytics.names = ['google-analytics', 'ubo-google-analytics_analytics.js', 'google-analytics_analytics.js', // https://github.com/AdguardTeam/Scriptlets/issues/127
    'googletagmanager-gtm', 'ubo-googletagmanager_gtm.js', 'googletagmanager_gtm.js'];
    GoogleAnalytics.injections = [hit, noopFunc, noopNull, noopArray];

    /* eslint-disable no-underscore-dangle */
    /**
     * @redirect google-analytics-ga
     *
     * @description
     * Mocks old Google Analytics API.
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/a94df7f3b27080ae2dcb3b914ace39c0c294d2f6/src/web_accessible_resources/google-analytics_ga.js
     *
     * **Example**
     * ```
     * ||google-analytics.com/ga.js$script,redirect=google-analytics-ga
     * ```
     */

    function GoogleAnalyticsGa(source) {
      // Gaq constructor
      function Gaq() {}

      Gaq.prototype.Na = noopFunc;
      Gaq.prototype.O = noopFunc;
      Gaq.prototype.Sa = noopFunc;
      Gaq.prototype.Ta = noopFunc;
      Gaq.prototype.Va = noopFunc;
      Gaq.prototype._createAsyncTracker = noopFunc;
      Gaq.prototype._getAsyncTracker = noopFunc;
      Gaq.prototype._getPlugin = noopFunc;

      Gaq.prototype.push = function (data) {
        if (typeof data === 'function') {
          data();
          return;
        }

        if (Array.isArray(data) === false) {
          return;
        } // https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiDomainDirectory#_gat.GA_Tracker_._link
        // https://github.com/uBlockOrigin/uBlock-issues/issues/1807


        if (typeof data[0] === 'string' && /(^|\.)_link$/.test(data[0]) && typeof data[1] === 'string') {
          window.location.assign(data[1]);
        } // https://github.com/gorhill/uBlock/issues/2162


        if (data[0] === '_set' && data[1] === 'hitCallback' && typeof data[2] === 'function') {
          data[2]();
        }
      };

      var gaq = new Gaq();
      var asyncTrackers = window._gaq || [];

      if (Array.isArray(asyncTrackers)) {
        while (asyncTrackers[0]) {
          gaq.push(asyncTrackers.shift());
        }
      } // eslint-disable-next-line no-multi-assign


      window._gaq = gaq.qf = gaq; // Gat constructor

      function Gat() {} // Mock tracker api


      var api = ['_addIgnoredOrganic', '_addIgnoredRef', '_addItem', '_addOrganic', '_addTrans', '_clearIgnoredOrganic', '_clearIgnoredRef', '_clearOrganic', '_cookiePathCopy', '_deleteCustomVar', '_getName', '_setAccount', '_getAccount', '_getClientInfo', '_getDetectFlash', '_getDetectTitle', '_getLinkerUrl', '_getLocalGifPath', '_getServiceMode', '_getVersion', '_getVisitorCustomVar', '_initData', '_link', '_linkByPost', '_setAllowAnchor', '_setAllowHash', '_setAllowLinker', '_setCampContentKey', '_setCampMediumKey', '_setCampNameKey', '_setCampNOKey', '_setCampSourceKey', '_setCampTermKey', '_setCampaignCookieTimeout', '_setCampaignTrack', '_setClientInfo', '_setCookiePath', '_setCookiePersistence', '_setCookieTimeout', '_setCustomVar', '_setDetectFlash', '_setDetectTitle', '_setDomainName', '_setLocalGifPath', '_setLocalRemoteServerMode', '_setLocalServerMode', '_setReferrerOverride', '_setRemoteServerMode', '_setSampleRate', '_setSessionTimeout', '_setSiteSpeedSampleRate', '_setSessionCookieTimeout', '_setVar', '_setVisitorCookieTimeout', '_trackEvent', '_trackPageLoadTime', '_trackPageview', '_trackSocial', '_trackTiming', '_trackTrans', '_visitCode'];
      var tracker = api.reduce(function (res, funcName) {
        res[funcName] = noopFunc;
        return res;
      }, {});

      tracker._getLinkerUrl = function (a) {
        return a;
      }; // https://github.com/AdguardTeam/Scriptlets/issues/154


      tracker._link = function (url) {
        if (typeof url !== 'string') {
          return;
        }

        try {
          window.location.assign(url);
        } catch (e) {
          // log the error only while debugging
          if (source.verbose) {
            // eslint-disable-next-line no-console
            console.log(e);
          }
        }
      };

      Gat.prototype._anonymizeIP = noopFunc;
      Gat.prototype._createTracker = noopFunc;
      Gat.prototype._forceSSL = noopFunc;
      Gat.prototype._getPlugin = noopFunc;

      Gat.prototype._getTracker = function () {
        return tracker;
      };

      Gat.prototype._getTrackerByName = function () {
        return tracker;
      };

      Gat.prototype._getTrackers = noopFunc;
      Gat.prototype.aa = noopFunc;
      Gat.prototype.ab = noopFunc;
      Gat.prototype.hb = noopFunc;
      Gat.prototype.la = noopFunc;
      Gat.prototype.oa = noopFunc;
      Gat.prototype.pa = noopFunc;
      Gat.prototype.u = noopFunc;
      var gat = new Gat();
      window._gat = gat;
      hit(source);
    }
    GoogleAnalyticsGa.names = ['google-analytics-ga', 'ubo-google-analytics_ga.js', 'google-analytics_ga.js'];
    GoogleAnalyticsGa.injections = [hit, noopFunc];

    /* eslint-disable max-len */

    /**
     * @redirect googlesyndication-adsbygoogle
     *
     * @description
     * Mocks Google AdSense API.
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/a94df7f3b27080ae2dcb3b914ace39c0c294d2f6/src/web_accessible_resources/googlesyndication_adsbygoogle.js
     *
     * **Example**
     * ```
     * ||pagead2.googlesyndication.com/pagead/js/adsbygoogle.js$script,redirect=googlesyndication-adsbygoogle
     * ```
     */

    /* eslint-enable max-len */

    function GoogleSyndicationAdsByGoogle(source) {
      window.adsbygoogle = {
        // https://github.com/AdguardTeam/Scriptlets/issues/113
        // length: 0,
        loaded: true,
        // https://github.com/AdguardTeam/Scriptlets/issues/184
        push: function push(arg) {
          if (typeof this.length === 'undefined') {
            this.length = 0;
            this.length += 1;
          }

          if (arg !== null && arg instanceof Object && arg.constructor.name === 'Object') {
            // eslint-disable-next-line no-restricted-syntax
            for (var _i = 0, _Object$keys = Object.keys(arg); _i < _Object$keys.length; _i++) {
              var key = _Object$keys[_i];

              if (typeof arg[key] === 'function') {
                try {
                  arg[key].call();
                } catch (_unused) {
                  /* empty */
                }
              }
            }
          }
        }
      };
      var adElems = document.querySelectorAll('.adsbygoogle');
      var css = 'height:1px!important;max-height:1px!important;max-width:1px!important;width:1px!important;';
      var statusAttrName = 'data-adsbygoogle-status';
      var ASWIFT_IFRAME_MARKER = 'aswift_';
      var GOOGLE_ADS_IFRAME_MARKER = 'google_ads_iframe_';
      var executed = false;

      for (var i = 0; i < adElems.length; i += 1) {
        var adElemChildNodes = adElems[i].childNodes;
        var childNodesQuantity = adElemChildNodes.length; // childNodes of .adsbygoogle can be defined if scriptlet was executed before
        // so we should check that childNodes are exactly defined by us
        // TODO: remake after scriptlets context developing in 1.3

        var areIframesDefined = false;

        if (childNodesQuantity > 0) {
          // it should be only 2 child iframes if scriptlet was executed
          areIframesDefined = childNodesQuantity === 2 // the first of child nodes should be aswift iframe
          && adElemChildNodes[0].nodeName.toLowerCase() === 'iframe' && adElemChildNodes[0].id.indexOf(ASWIFT_IFRAME_MARKER) > -1 // the second of child nodes should be google_ads iframe
          && adElemChildNodes[1].nodeName.toLowerCase() === 'iframe' && adElemChildNodes[1].id.indexOf(GOOGLE_ADS_IFRAME_MARKER) > -1;
        }

        if (!areIframesDefined) {
          // here we do the job if scriptlet has not been executed earlier
          adElems[i].setAttribute(statusAttrName, 'done');
          var aswiftIframe = document.createElement('iframe');
          aswiftIframe.id = "".concat(ASWIFT_IFRAME_MARKER).concat(i);
          aswiftIframe.style = css;
          adElems[i].appendChild(aswiftIframe);
          var innerAswiftIframe = document.createElement('iframe');
          aswiftIframe.contentWindow.document.body.appendChild(innerAswiftIframe);
          var googleadsIframe = document.createElement('iframe');
          googleadsIframe.id = "".concat(GOOGLE_ADS_IFRAME_MARKER).concat(i);
          googleadsIframe.style = css;
          adElems[i].appendChild(googleadsIframe);
          var innerGoogleadsIframe = document.createElement('iframe');
          googleadsIframe.contentWindow.document.body.appendChild(innerGoogleadsIframe);
          executed = true;
        }
      }

      if (executed) {
        hit(source);
      }
    }
    GoogleSyndicationAdsByGoogle.names = ['googlesyndication-adsbygoogle', 'ubo-googlesyndication_adsbygoogle.js', 'googlesyndication_adsbygoogle.js'];
    GoogleSyndicationAdsByGoogle.injections = [hit];

    /**
     * @redirect googletagservices-gpt
     *
     * @description
     * Mocks Google Publisher Tag API.
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/a94df7f3b27080ae2dcb3b914ace39c0c294d2f6/src/web_accessible_resources/googletagservices_gpt.js
     *
     * **Example**
     * ```
     * ||googletagservices.com/tag/js/gpt.js$script,redirect=googletagservices-gpt
     * ```
     */

    function GoogleTagServicesGpt(source) {
      var companionAdsService = {
        addEventListener: noopThis,
        removeEventListener: noopThis,
        enableSyncLoading: noopFunc,
        setRefreshUnfilledSlots: noopFunc,
        getSlots: noopArray
      };
      var contentService = {
        addEventListener: noopThis,
        setContent: noopFunc
      };

      function PassbackSlot() {} // constructor


      PassbackSlot.prototype.display = noopFunc;
      PassbackSlot.prototype.get = noopNull;
      PassbackSlot.prototype.set = noopThis;
      PassbackSlot.prototype.setClickUrl = noopThis;
      PassbackSlot.prototype.setTagForChildDirectedTreatment = noopThis;
      PassbackSlot.prototype.setTargeting = noopThis;
      PassbackSlot.prototype.updateTargetingFromMap = noopThis;

      function SizeMappingBuilder() {} // constructor


      SizeMappingBuilder.prototype.addSize = noopThis;
      SizeMappingBuilder.prototype.build = noopNull;

      function Slot() {} // constructor


      Slot.prototype.addService = noopThis;
      Slot.prototype.clearCategoryExclusions = noopThis;
      Slot.prototype.clearTargeting = noopThis;
      Slot.prototype.defineSizeMapping = noopThis;
      Slot.prototype.get = noopNull;
      Slot.prototype.getAdUnitPath = noopStr;
      Slot.prototype.getAttributeKeys = noopArray;
      Slot.prototype.getCategoryExclusions = noopArray;
      Slot.prototype.getDomId = noopStr;
      Slot.prototype.getSlotElementId = noopStr;
      Slot.prototype.getSlotId = noopThis;
      Slot.prototype.getTargeting = noopArray;
      Slot.prototype.getTargetingKeys = noopArray;
      Slot.prototype.set = noopThis;
      Slot.prototype.setCategoryExclusion = noopThis;
      Slot.prototype.setClickUrl = noopThis;
      Slot.prototype.setCollapseEmptyDiv = noopThis;
      Slot.prototype.setTargeting = noopThis;
      var pubAdsService = {
        addEventListener: noopThis,
        removeEventListener: noopThis,
        clear: noopFunc,
        clearCategoryExclusions: noopThis,
        clearTagForChildDirectedTreatment: noopThis,
        clearTargeting: noopThis,
        collapseEmptyDivs: noopFunc,
        defineOutOfPagePassback: function defineOutOfPagePassback() {
          return new PassbackSlot();
        },
        definePassback: function definePassback() {
          return new PassbackSlot();
        },
        disableInitialLoad: noopFunc,
        display: noopFunc,
        enableAsyncRendering: noopFunc,
        enableLazyLoad: noopFunc,
        enableSingleRequest: noopFunc,
        enableSyncRendering: noopFunc,
        enableVideoAds: noopFunc,
        get: noopNull,
        getAttributeKeys: noopArray,
        getTargeting: noopArray,
        getTargetingKeys: noopArray,
        getSlots: noopArray,
        refresh: noopFunc,
        set: noopThis,
        setCategoryExclusion: noopThis,
        setCentering: noopFunc,
        setCookieOptions: noopThis,
        setForceSafeFrame: noopThis,
        setLocation: noopThis,
        setPublisherProvidedId: noopThis,
        setRequestNonPersonalizedAds: noopThis,
        setSafeFrameConfig: noopThis,
        setTagForChildDirectedTreatment: noopThis,
        setTargeting: noopThis,
        setVideoContent: noopThis,
        updateCorrelator: noopFunc
      };
      var _window = window,
          _window$googletag = _window.googletag,
          googletag = _window$googletag === void 0 ? {} : _window$googletag;
      var _googletag$cmd = googletag.cmd,
          cmd = _googletag$cmd === void 0 ? [] : _googletag$cmd;
      googletag.apiReady = true;
      googletag.cmd = [];

      googletag.cmd.push = function (a) {
        try {
          a(); // eslint-disable-next-line no-empty
        } catch (ex) {}

        return 1;
      };

      googletag.companionAds = function () {
        return companionAdsService;
      };

      googletag.content = function () {
        return contentService;
      };

      googletag.defineOutOfPageSlot = function () {
        return new Slot();
      };

      googletag.defineSlot = function () {
        return new Slot();
      };

      googletag.destroySlots = noopFunc;
      googletag.disablePublisherConsole = noopFunc;
      googletag.display = noopFunc;
      googletag.enableServices = noopFunc;
      googletag.getVersion = noopStr;

      googletag.pubads = function () {
        return pubAdsService;
      };

      googletag.pubadsReady = true;
      googletag.setAdIframeTitle = noopFunc;

      googletag.sizeMapping = function () {
        return new SizeMappingBuilder();
      };

      window.googletag = googletag;

      while (cmd.length !== 0) {
        googletag.cmd.push(cmd.shift());
      }

      hit(source);
    }
    GoogleTagServicesGpt.names = ['googletagservices-gpt', 'ubo-googletagservices_gpt.js', 'googletagservices_gpt.js'];
    GoogleTagServicesGpt.injections = [hit, noopFunc, noopThis, noopNull, noopArray, noopStr];

    /**
     * @redirect scorecardresearch-beacon
     *
     * @description
     * Mocks Scorecard Research API.
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/a94df7f3b27080ae2dcb3b914ace39c0c294d2f6/src/web_accessible_resources/scorecardresearch_beacon.js
     *
     * **Example**
     * ```
     * ||sb.scorecardresearch.com/beacon.js$script,redirect=scorecardresearch-beacon
     * ```
     */

    function ScoreCardResearchBeacon(source) {
      window.COMSCORE = {
        purge: function purge() {
          // eslint-disable-next-line no-underscore-dangle
          window._comscore = [];
        },
        beacon: function beacon() {}
      };
      hit(source);
    }
    ScoreCardResearchBeacon.names = ['scorecardresearch-beacon', 'ubo-scorecardresearch_beacon.js', 'scorecardresearch_beacon.js'];
    ScoreCardResearchBeacon.injections = [hit];

    /**
     * @redirect metrika-yandex-tag
     *
     * @description
     * Mocks Yandex Metrika API.
     * https://yandex.ru/support/metrica/objects/method-reference.html
     *
     * **Example**
     * ```
     * ||mc.yandex.ru/metrika/tag.js$script,redirect=metrika-yandex-tag
     * ```
     */

    function metrikaYandexTag(source) {
      var asyncCallbackFromOptions = function asyncCallbackFromOptions(id, param) {
        var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
        var callback = options.callback;
        var ctx = options.ctx;

        if (typeof callback === 'function') {
          callback = ctx !== undefined ? callback.bind(ctx) : callback;
          setTimeout(function () {
            return callback();
          });
        }
      };
      /**
       * https://yandex.ru/support/metrica/objects/addfileextension.html
       */


      var addFileExtension = noopFunc;
      /**
       * https://yandex.ru/support/metrica/objects/extlink.html
       */

      var extLink = asyncCallbackFromOptions;
      /**
       * https://yandex.ru/support/metrica/objects/file.html
       */

      var file = asyncCallbackFromOptions;
      /**
       * https://yandex.ru/support/metrica/objects/get-client-id.html
       * @param {Function} cb
       */

      var getClientID = function getClientID(id, cb) {
        if (!cb) {
          return;
        }

        setTimeout(cb(null));
      };
      /**
       * https://yandex.ru/support/metrica/objects/hit.html
       */


      var hitFunc = asyncCallbackFromOptions;
      /**
       * https://yandex.ru/support/metrica/objects/notbounce.html
       */

      var notBounce = asyncCallbackFromOptions;
      /**
       * https://yandex.ru/support/metrica/objects/params-method.html
       */

      var params = noopFunc;
      /**
       * https://yandex.ru/support/metrica/objects/reachgoal.html
       * @param {string} target
       * @param {Object} params
       * @param {Function} callback
       * @param {any} ctx
       */

      var reachGoal = function reachGoal(id, target, params, callback, ctx) {
        asyncCallbackFromOptions(null, null, {
          callback: callback,
          ctx: ctx
        });
      };
      /**
       * https://yandex.ru/support/metrica/objects/set-user-id.html
       */


      var setUserID = noopFunc;
      /**
       * https://yandex.ru/support/metrica/objects/user-params.html
       */

      var userParams = noopFunc; // https://github.com/AdguardTeam/Scriptlets/issues/198

      var destruct = noopFunc;
      var api = {
        addFileExtension: addFileExtension,
        extLink: extLink,
        file: file,
        getClientID: getClientID,
        hit: hitFunc,
        notBounce: notBounce,
        params: params,
        reachGoal: reachGoal,
        setUserID: setUserID,
        userParams: userParams,
        destruct: destruct
      };

      function ym(id, funcName) {
        for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
          args[_key - 2] = arguments[_key];
        }

        return api[funcName] && api[funcName].apply(api, [id].concat(args));
      }

      ym.a = [];

      function init(id) {
        // yaCounter object should provide api
        window["yaCounter".concat(id)] = api;
        document.dispatchEvent(new Event("yacounter".concat(id, "inited")));
      }

      if (typeof window.ym === 'undefined') {
        window.ym = ym;
      } else if (window.ym && window.ym.a) {
        // Get id for yaCounter object
        var counters = window.ym.a;
        window.ym = ym;
        counters.forEach(function (params) {
          var id = params[0];
          init(id);
        });
      }

      hit(source);
    }
    metrikaYandexTag.names = ['metrika-yandex-tag'];
    metrikaYandexTag.injections = [hit, noopFunc];

    /**
     * @redirect metrika-yandex-watch
     *
     * @description
     * Mocks the old Yandex Metrika API.
     * https://yandex.ru/support/metrica/objects/_method-reference.html
     *
     * **Example**
     * ```
     * ||mc.yandex.ru/metrika/watch.js$script,redirect=metrika-yandex-watch
     * ```
     */

    function metrikaYandexWatch(source) {
      var cbName = 'yandex_metrika_callbacks';
      /**
       * Gets callback and its context from options and call it in async way
       * @param {Object} options Yandex Metrika API options
       */

      var asyncCallbackFromOptions = function asyncCallbackFromOptions() {
        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var callback = options.callback;
        var ctx = options.ctx;

        if (typeof callback === 'function') {
          callback = ctx !== undefined ? callback.bind(ctx) : callback;
          setTimeout(function () {
            return callback();
          });
        }
      };

      function Metrika() {} // constructor
      // Methods without options


      Metrika.prototype.addFileExtension = noopFunc;
      Metrika.prototype.getClientID = noopFunc;
      Metrika.prototype.setUserID = noopFunc;
      Metrika.prototype.userParams = noopFunc;
      Metrika.prototype.params = noopFunc; // Methods with options
      // The order of arguments should be kept in according to API

      Metrika.prototype.extLink = function (url, options) {
        asyncCallbackFromOptions(options);
      };

      Metrika.prototype.file = function (url, options) {
        asyncCallbackFromOptions(options);
      };

      Metrika.prototype.hit = function (url, options) {
        asyncCallbackFromOptions(options);
      };

      Metrika.prototype.reachGoal = function (target, params, cb, ctx) {
        asyncCallbackFromOptions({
          callback: cb,
          ctx: ctx
        });
      };

      Metrika.prototype.notBounce = asyncCallbackFromOptions;

      if (window.Ya) {
        window.Ya.Metrika = Metrika;
      } else {
        window.Ya = {
          Metrika: Metrika
        };
      }

      if (window[cbName] && Array.isArray(window[cbName])) {
        window[cbName].forEach(function (func) {
          if (typeof func === 'function') {
            func();
          }
        });
      }

      hit(source);
    }
    metrikaYandexWatch.names = ['metrika-yandex-watch'];
    metrikaYandexWatch.injections = [hit, noopFunc];

    /**
     * @redirect amazon-apstag
     *
     * @description
     * Mocks Amazon's apstag.js
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/f842ab6d3c1cf0394f95d27092bf59627262da40/src/web_accessible_resources/amazon_apstag.js
     *
     * **Example**
     * ```
     * ||amazon-adsystem.com/aax2/apstag.js$script,redirect=amazon-apstag
     * ```
     */

    function AmazonApstag(source) {
      var apstagWrapper = {
        fetchBids: function fetchBids(a, b) {
          if (typeof b === 'function') {
            b([]);
          }
        },
        init: noopFunc,
        setDisplayBids: noopFunc,
        targetingKeys: noopFunc
      };
      window.apstag = apstagWrapper;
      hit(source);
    }
    AmazonApstag.names = ['amazon-apstag', 'ubo-amazon_apstag.js', 'amazon_apstag.js'];
    AmazonApstag.injections = [hit, noopFunc];

    /* eslint-disable func-names */
    /**
     * @redirect matomo
     *
     * @description
     * Mocks the piwik.js file of Matomo (formerly Piwik).
     *
     * **Example**
     * ```
     * ||example.org/piwik.js$script,redirect=matomo
     * ```
     */

    function Matomo(source) {
      var Tracker = function Tracker() {};

      Tracker.prototype.setDoNotTrack = noopFunc;
      Tracker.prototype.setDomains = noopFunc;
      Tracker.prototype.setCustomDimension = noopFunc;
      Tracker.prototype.trackPageView = noopFunc;

      var AsyncTracker = function AsyncTracker() {};

      AsyncTracker.prototype.addListener = noopFunc;
      var matomoWrapper = {
        getTracker: function getTracker() {
          return new Tracker();
        },
        getAsyncTracker: function getAsyncTracker() {
          return new AsyncTracker();
        }
      };
      window.Piwik = matomoWrapper;
      hit(source);
    }
    Matomo.names = ['matomo'];
    Matomo.injections = [hit, noopFunc];

    /* eslint-disable func-names */
    /**
     * @redirect fingerprintjs2
     *
     * @description
     * Mocks FingerprintJS v2
     * https://github.com/fingerprintjs
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/master/src/web_accessible_resources/fingerprint2.js
     *
     * **Example**
     * ```
     * ||the-japan-news.com/modules/js/lib/fgp/fingerprint2.js$script,redirect=fingerprintjs2
     * ```
     */

    function Fingerprintjs2(source) {
      var browserId = '';

      for (var i = 0; i < 8; i += 1) {
        browserId += (Math.random() * 0x10000 + 0x1000).toString(16).slice(-4);
      }

      var Fingerprint2 = function Fingerprint2() {};

      Fingerprint2.get = function (options, callback) {
        if (!callback) {
          callback = options;
        }

        setTimeout(function () {
          if (callback) {
            callback(browserId, []);
          }
        }, 1);
      };

      Fingerprint2.prototype = {
        get: Fingerprint2.get
      };
      window.Fingerprint2 = Fingerprint2;
      hit(source);
    }
    Fingerprintjs2.names = ['fingerprintjs2', // redirect aliases are needed for conversion:
    // prefixed for us
    'ubo-fingerprint2.js', // original ubo name
    'fingerprint2.js'];
    Fingerprintjs2.injections = [hit];

    /* eslint-disable func-names */
    /**
     * @redirect fingerprintjs3
     *
     * @description
     * Mocks FingerprintJS v3
     * https://github.com/fingerprintjs
     *
     * Related UBO redirect resource:
     * https://github.com/gorhill/uBlock/blob/master/src/web_accessible_resources/fingerprint3.js
     *
     * **Example**
     * ```
     * ||sephora.com/js/ufe/isomorphic/thirdparty/fp.min.js$script,redirect=fingerprintjs3
     * ```
     */

    function Fingerprintjs3(source) {
      var visitorId = function () {
        var id = '';

        for (var i = 0; i < 8; i += 1) {
          id += (Math.random() * 0x10000 + 0x1000).toString(16).slice(-4);
        }

        return id;
      }();

      var FingerprintJS = function FingerprintJS() {};

      FingerprintJS.prototype = {
        load: function load() {
          // eslint-disable-next-line compat/compat
          return Promise.resolve(new FingerprintJS());
        },
        get: function get() {
          // eslint-disable-next-line compat/compat
          return Promise.resolve({
            visitorId: visitorId
          });
        },
        hashComponents: noopStr
      };
      window.FingerprintJS = new FingerprintJS();
      hit(source);
    }
    Fingerprintjs3.names = ['fingerprintjs3', // redirect aliases are needed for conversion:
    // prefixed for us
    'ubo-fingerprint3.js', // original ubo name
    'fingerprint3.js'];
    Fingerprintjs3.injections = [hit, noopStr];

    /* eslint-disable func-names */
    /**
     * @redirect gemius
     *
     * @description
     * Mocks Gemius Analytics.
     * https://flowplayer.com/developers/plugins/gemius
     *
     * **Example**
     * ```
     * ||gapt.hit.gemius.pl/gplayer.js$script,redirect=gemius
     * ```
     */

    function Gemius(source) {
      var GemiusPlayer = function GemiusPlayer() {};

      GemiusPlayer.prototype = {
        setVideoObject: noopFunc,
        newProgram: noopFunc,
        programEvent: noopFunc,
        newAd: noopFunc,
        adEvent: noopFunc
      };
      window.GemiusPlayer = GemiusPlayer;
      hit(source);
    }
    Gemius.names = ['gemius'];
    Gemius.injections = [hit, noopFunc];

    /**
     * @redirect ati-smarttag
     *
     * @description
     * Mocks AT Internat SmartTag.
     * https://developers.atinternet-solutions.com/as2-tagging-en/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en/
     *
     * **Example**
     * ```
     * ||bloctel.gouv.fr/assets/scripts/smarttag.js$script,redirect=ati-smarttag
     * ```
     */

    function ATInternetSmartTag(source) {
      var setNoopFuncWrapper = {
        set: noopFunc
      };
      var sendNoopFuncWrapper = {
        send: noopFunc
      };
      var ecommerceWrapper = {
        displayCart: {
          products: setNoopFuncWrapper,
          cart: setNoopFuncWrapper
        },
        updateCart: {
          cart: setNoopFuncWrapper
        },
        displayProduct: {
          products: setNoopFuncWrapper
        },
        displayPageProduct: {
          products: setNoopFuncWrapper
        },
        addProduct: {
          products: setNoopFuncWrapper
        },
        removeProduct: {
          products: setNoopFuncWrapper
        }
      }; // eslint-disable-next-line new-cap, func-names

      var tag = function tag() {};

      tag.prototype = {
        setConfig: noopFunc,
        setParam: noopFunc,
        dispatch: noopFunc,
        customVars: setNoopFuncWrapper,
        publisher: setNoopFuncWrapper,
        order: setNoopFuncWrapper,
        click: sendNoopFuncWrapper,
        clickListener: sendNoopFuncWrapper,
        internalSearch: {
          set: noopFunc,
          send: noopFunc
        },
        ecommerce: ecommerceWrapper,
        identifiedVisitor: {
          unset: noopFunc
        },
        page: {
          set: noopFunc,
          send: noopFunc
        },
        selfPromotion: {
          add: noopFunc,
          send: noopFunc
        },
        privacy: {
          setVisitorMode: noopFunc,
          getVisitorMode: noopFunc,
          hit: noopFunc
        },
        richMedia: {
          add: noopFunc,
          send: noopFunc,
          remove: noopFunc,
          removeAll: noopFunc
        }
      };
      var smartTagWrapper = {
        Tracker: {
          Tag: function Tag() {
            return new tag(); // eslint-disable-line new-cap
          }
        }
      };
      window.ATInternet = smartTagWrapper;
      hit(source);
    }
    ATInternetSmartTag.names = ['ati-smarttag'];
    ATInternetSmartTag.injections = [hit, noopFunc];

    /* eslint-disable consistent-return, no-eval */
    /**
     * @redirect prevent-bab2
     *
     * @description
     * Prevents BlockAdblock script from detecting an ad blocker.
     *
     * Related UBO redirect:
     * https://github.com/gorhill/uBlock/blob/master/src/web_accessible_resources/nobab2.js
     *
     * See [redirect description](../wiki/about-redirects.md#prevent-bab2).
     *
     * **Syntax**
     * ```
     * /blockadblock.$script,redirect=prevent-bab2
     * ```
     */

    function preventBab2(source) {
      // eslint-disable-next-line compat/compat
      var script = document.currentScript;

      if (script === null) {
        return;
      }

      var url = script.src;

      if (typeof url !== 'string') {
        return;
      }

      var domainsStr = ['adclixx\\.net', 'adnetasia\\.com', 'adtrackers\\.net', 'bannertrack\\.net'].join('|');
      var matchStr = "^https?://[\\w-]+\\.(".concat(domainsStr, ")/.");
      var domainsRegex = new RegExp(matchStr);

      if (domainsRegex.test(url) === false) {
        return;
      }

      window.nH7eXzOsG = 858;
      hit(source);
    }
    preventBab2.names = ['prevent-bab2', // aliases are needed for matching the related scriptlet converted into our syntax
    'nobab2.js'];
    preventBab2.injections = [hit];

    /* eslint-disable func-names, no-underscore-dangle */
    /**
     * @redirect google-ima3
     *
     * @description
     * Mocks the IMA SDK of Google.
     *
     * **Example**
     * ```
     * ||imasdk.googleapis.com/js/sdkloader/ima3.js$script,redirect=google-ima3
     * ```
     */

    function GoogleIma3(source) {
      var _this = this;

      var VERSION = '3.453.0';
      var ima = {};

      var AdDisplayContainer = function AdDisplayContainer() {};

      AdDisplayContainer.prototype.destroy = noopFunc;
      AdDisplayContainer.prototype.initialize = noopFunc;

      var ImaSdkSettings = function ImaSdkSettings() {};

      ImaSdkSettings.CompanionBackfillMode = {
        ALWAYS: 'always',
        ON_MASTER_AD: 'on_master_ad'
      };
      ImaSdkSettings.VpaidMode = {
        DISABLED: 0,
        ENABLED: 1,
        INSECURE: 2
      };
      ImaSdkSettings.prototype = {
        c: true,
        f: {},
        i: false,
        l: '',
        p: '',
        r: 0,
        t: '',
        v: '',
        getCompanionBackfill: noopFunc,
        getDisableCustomPlaybackForIOS10Plus: function getDisableCustomPlaybackForIOS10Plus() {
          return _this.i;
        },
        getDisabledFlashAds: function getDisabledFlashAds() {
          return true;
        },
        getFeatureFlags: function getFeatureFlags() {
          return _this.f;
        },
        getLocale: function getLocale() {
          return _this.l;
        },
        getNumRedirects: function getNumRedirects() {
          return _this.r;
        },
        getPlayerType: function getPlayerType() {
          return _this.t;
        },
        getPlayerVersion: function getPlayerVersion() {
          return _this.v;
        },
        getPpid: function getPpid() {
          return _this.p;
        },
        getVpaidMode: function getVpaidMode() {
          return _this.C;
        },
        isCookiesEnabled: function isCookiesEnabled() {
          return _this.c;
        },
        isVpaidAdapter: function isVpaidAdapter() {
          return _this.M;
        },
        setCompanionBackfill: noopFunc,
        setAutoPlayAdBreaks: function setAutoPlayAdBreaks(a) {
          _this.K = a;
        },
        setCookiesEnabled: function setCookiesEnabled(c) {
          _this.c = !!c;
        },
        setDisableCustomPlaybackForIOS10Plus: function setDisableCustomPlaybackForIOS10Plus(i) {
          _this.i = !!i;
        },
        setDisableFlashAds: noopFunc,
        setFeatureFlags: function setFeatureFlags(f) {
          _this.f = !!f;
        },
        setIsVpaidAdapter: function setIsVpaidAdapter(a) {
          _this.M = a;
        },
        setLocale: function setLocale(l) {
          _this.l = !!l;
        },
        setNumRedirects: function setNumRedirects(r) {
          _this.r = !!r;
        },
        setPageCorrelator: function setPageCorrelator(a) {
          _this.R = a;
        },
        setPlayerType: function setPlayerType(t) {
          _this.t = !!t;
        },
        setPlayerVersion: function setPlayerVersion(v) {
          _this.v = !!v;
        },
        setPpid: function setPpid(p) {
          _this.p = !!p;
        },
        setVpaidMode: function setVpaidMode(a) {
          _this.C = a;
        },
        setSessionId: noopFunc,
        setStreamCorrelator: noopFunc,
        setVpaidAllowed: noopFunc,
        CompanionBackfillMode: {
          ALWAYS: 'always',
          ON_MASTER_AD: 'on_master_ad'
        },
        VpaidMode: {
          DISABLED: 0,
          ENABLED: 1,
          INSECURE: 2
        }
      };
      var managerLoaded = false;

      var EventHandler = function EventHandler() {};

      EventHandler.prototype = {
        listeners: new Map(),
        _dispatch: function _dispatch(e) {
          var listeners = this.listeners.get(e.type) || []; // eslint-disable-next-line no-restricted-syntax

          for (var _i = 0, _Array$from = Array.from(listeners); _i < _Array$from.length; _i++) {
            var listener = _Array$from[_i];

            try {
              listener(e);
            } catch (r) {
              // eslint-disable-next-line no-console
              console.error(r);
            }
          }
        },
        addEventListener: function addEventListener(t, c) {
          if (!this.listeners.has(t)) {
            this.listeners.set(t, new Set());
          }

          this.listeners.get(t).add(c);
        },
        removeEventListener: function removeEventListener(t, c) {
          var _this$listeners$get;

          (_this$listeners$get = this.listeners.get(t)) === null || _this$listeners$get === void 0 ? void 0 : _this$listeners$get.delete(c);
        }
      };
      var AdsManager = EventHandler;
      /* eslint-disable no-use-before-define */

      AdsManager.prototype.volume = 1;
      AdsManager.prototype.collapse = noopFunc;
      AdsManager.prototype.configureAdsManager = noopFunc;
      AdsManager.prototype.destroy = noopFunc;
      AdsManager.prototype.discardAdBreak = noopFunc;
      AdsManager.prototype.expand = noopFunc;
      AdsManager.prototype.focus = noopFunc;

      AdsManager.prototype.getAdSkippableState = function () {
        return false;
      };

      AdsManager.prototype.getCuePoints = function () {
        return [0];
      };

      AdsManager.prototype.getCurrentAd = function () {
        return currentAd;
      };

      AdsManager.prototype.getCurrentAdCuePoints = function () {
        return [];
      };

      AdsManager.prototype.getRemainingTime = function () {
        return 0;
      };

      AdsManager.prototype.getVolume = function () {
        return _this.volume;
      };

      AdsManager.prototype.init = noopFunc;

      AdsManager.prototype.isCustomClickTrackingUsed = function () {
        return false;
      };

      AdsManager.prototype.isCustomPlaybackUsed = function () {
        return false;
      };

      AdsManager.prototype.pause = noopFunc;
      AdsManager.prototype.requestNextAdBreak = noopFunc;
      AdsManager.prototype.resize = noopFunc;
      AdsManager.prototype.resume = noopFunc;

      AdsManager.prototype.setVolume = function (v) {
        _this.volume = v;
      };

      AdsManager.prototype.skip = noopFunc;

      AdsManager.prototype.start = function () {
        // eslint-disable-next-line no-restricted-syntax
        for (var _i2 = 0, _arr = [AdEvent.Type.LOADED, AdEvent.Type.STARTED, AdEvent.Type.AD_BUFFERING, AdEvent.Type.FIRST_QUARTILE, AdEvent.Type.MIDPOINT, AdEvent.Type.THIRD_QUARTILE, AdEvent.Type.COMPLETE, AdEvent.Type.ALL_ADS_COMPLETED]; _i2 < _arr.length; _i2++) {
          var type = _arr[_i2];

          try {
            _this._dispatch(new ima.AdEvent(type));
          } catch (e) {
            // eslint-disable-next-line no-console
            console.error(e);
          }
        }
      };

      AdsManager.prototype.stop = noopFunc;
      AdsManager.prototype.updateAdsRenderingSettings = noopFunc;
      /* eslint-enable no-use-before-define */

      var manager = Object.create(AdsManager);

      var AdsManagerLoadedEvent = function AdsManagerLoadedEvent() {};

      AdsManagerLoadedEvent.prototype = {
        constructor: function constructor(type) {
          _this.type = type;
        },
        getAdsManager: function getAdsManager() {
          return manager;
        },
        getUserRequestContext: noopFunc
      };
      AdsManagerLoadedEvent.Type = {
        ADS_MANAGER_LOADED: 'adsManagerLoaded'
      };
      var AdsLoader = EventHandler;
      AdsLoader.prototype.settings = new ImaSdkSettings();
      AdsLoader.prototype.contentComplete = noopFunc;
      AdsLoader.prototype.destroy = noopFunc;

      AdsLoader.prototype.getSettings = function () {
        return this.settings;
      };

      AdsLoader.prototype.getVersion = function () {
        return VERSION;
      };

      AdsLoader.prototype.requestAds = function () {
        var _this2 = this;

        if (!managerLoaded) {
          managerLoaded = true;
          requestAnimationFrame(function () {
            var ADS_MANAGER_LOADED = AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED;

            _this2._dispatch(new ima.AdsManagerLoadedEvent(ADS_MANAGER_LOADED));
          });
        }
      };

      var AdsRenderingSettings = noopFunc;

      var AdsRequest = function AdsRequest() {};

      AdsRequest.prototype = {
        setAdWillAutoPlay: noopFunc,
        setAdWillPlayMuted: noopFunc,
        setContinuousPlayback: noopFunc
      };

      var AdPodInfo = function AdPodInfo() {};

      AdPodInfo.prototype = {
        getAdPosition: function getAdPosition() {
          return 1;
        },
        getIsBumper: function getIsBumper() {
          return false;
        },
        getMaxDuration: function getMaxDuration() {
          return -1;
        },
        getPodIndex: function getPodIndex() {
          return 1;
        },
        getTimeOffset: function getTimeOffset() {
          return 0;
        },
        getTotalAds: function getTotalAds() {
          return 1;
        }
      };

      var Ad = function Ad() {};

      Ad.prototype = {
        pi: new AdPodInfo(),
        getAdId: function getAdId() {
          return '';
        },
        getAdPodInfo: function getAdPodInfo() {
          return _this.pi;
        },
        getAdSystem: function getAdSystem() {
          return '';
        },
        getAdvertiserName: function getAdvertiserName() {
          return '';
        },
        getApiFramework: function getApiFramework() {
          return null;
        },
        getCompanionAds: function getCompanionAds() {
          return [];
        },
        getContentType: function getContentType() {
          return '';
        },
        getCreativeAdId: function getCreativeAdId() {
          return '';
        },
        getDealId: function getDealId() {
          return '';
        },
        getDescription: function getDescription() {
          return '';
        },
        getDuration: function getDuration() {
          return 8.5;
        },
        getHeight: function getHeight() {
          return 0;
        },
        getMediaUrl: function getMediaUrl() {
          return null;
        },
        getMinSuggestedDuration: function getMinSuggestedDuration() {
          return -2;
        },
        getSkipTimeOffset: function getSkipTimeOffset() {
          return -1;
        },
        getSurveyUrl: function getSurveyUrl() {
          return null;
        },
        getTitle: function getTitle() {
          return '';
        },
        getTraffickingParametersString: function getTraffickingParametersString() {
          return '';
        },
        getUiElements: function getUiElements() {
          return [''];
        },
        getUniversalAdIdRegistry: function getUniversalAdIdRegistry() {
          return 'unknown';
        },
        getUniversalAdIds: function getUniversalAdIds() {
          return [''];
        },
        getUniversalAdIdValue: function getUniversalAdIdValue() {
          return 'unknown';
        },
        getVastMediaBitrate: function getVastMediaBitrate() {
          return 0;
        },
        getVastMediaHeight: function getVastMediaHeight() {
          return 0;
        },
        getVastMediaWidth: function getVastMediaWidth() {
          return 0;
        },
        getWidth: function getWidth() {
          return 0;
        },
        getWrapperAdIds: function getWrapperAdIds() {
          return [''];
        },
        getWrapperAdSystems: function getWrapperAdSystems() {
          return [''];
        },
        getWrapperCreativeIds: function getWrapperCreativeIds() {
          return [''];
        },
        isLinear: function isLinear() {
          return true;
        }
      };

      var CompanionAd = function CompanionAd() {};

      CompanionAd.prototype = {
        getAdSlotId: function getAdSlotId() {
          return '';
        },
        getContent: function getContent() {
          return '';
        },
        getContentType: function getContentType() {
          return '';
        },
        getHeight: function getHeight() {
          return 1;
        },
        getWidth: function getWidth() {
          return 1;
        }
      };

      var AdError = function AdError() {};

      AdError.prototype = {
        getErrorCode: function getErrorCode() {
          return 0;
        },
        getInnerError: noopFunc,
        getMessage: function getMessage() {
          return '';
        },
        getType: function getType() {
          return 1;
        },
        getVastErrorCode: function getVastErrorCode() {
          return 0;
        },
        toString: function toString() {
          return '';
        }
      };
      AdError.ErrorCode = {};
      AdError.Type = {};

      var isEngadget = function isEngadget() {
        try {
          // eslint-disable-next-line no-restricted-syntax
          for (var _i3 = 0, _Object$values = Object.values(window.vidible._getContexts()); _i3 < _Object$values.length; _i3++) {
            var _ctx$getPlayer, _ctx$getPlayer$div;

            var ctx = _Object$values[_i3];

            // eslint-disable-next-line no-restricted-properties
            if ((_ctx$getPlayer = ctx.getPlayer()) !== null && _ctx$getPlayer !== void 0 && (_ctx$getPlayer$div = _ctx$getPlayer.div) !== null && _ctx$getPlayer$div !== void 0 && _ctx$getPlayer$div.innerHTML.includes('www.engadget.com')) {
              return true;
            }
          }
        } catch (e) {} // eslint-disable-line no-empty


        return false;
      };

      var currentAd = isEngadget() ? undefined : new Ad();

      var AdEvent = function AdEvent() {};

      AdEvent.prototype = {
        constructor: function constructor(type) {
          _this.type = type;
        },
        getAd: function getAd() {
          return currentAd;
        },
        getAdData: function getAdData() {}
      };
      AdEvent.Type = {
        AD_BREAK_READY: 'adBreakReady',
        AD_BUFFERING: 'adBuffering',
        AD_CAN_PLAY: 'adCanPlay',
        AD_METADATA: 'adMetadata',
        AD_PROGRESS: 'adProgress',
        ALL_ADS_COMPLETED: 'allAdsCompleted',
        CLICK: 'click',
        COMPLETE: 'complete',
        CONTENT_PAUSE_REQUESTED: 'contentPauseRequested',
        CONTENT_RESUME_REQUESTED: 'contentResumeRequested',
        DURATION_CHANGE: 'durationChange',
        EXPANDED_CHANGED: 'expandedChanged',
        FIRST_QUARTILE: 'firstQuartile',
        IMPRESSION: 'impression',
        INTERACTION: 'interaction',
        LINEAR_CHANGE: 'linearChange',
        LINEAR_CHANGED: 'linearChanged',
        LOADED: 'loaded',
        LOG: 'log',
        MIDPOINT: 'midpoint',
        PAUSED: 'pause',
        RESUMED: 'resume',
        SKIPPABLE_STATE_CHANGED: 'skippableStateChanged',
        SKIPPED: 'skip',
        STARTED: 'start',
        THIRD_QUARTILE: 'thirdQuartile',
        USER_CLOSE: 'userClose',
        VIDEO_CLICKED: 'videoClicked',
        VIDEO_ICON_CLICKED: 'videoIconClicked',
        VIEWABLE_IMPRESSION: 'viewable_impression',
        VOLUME_CHANGED: 'volumeChange',
        VOLUME_MUTED: 'mute'
      };

      var AdErrorEvent = function AdErrorEvent() {};

      AdErrorEvent.prototype = {
        getError: noopFunc,
        getUserRequestContext: function getUserRequestContext() {}
      };
      AdErrorEvent.Type = {
        AD_ERROR: 'adError'
      };

      var CustomContentLoadedEvent = function CustomContentLoadedEvent() {};

      CustomContentLoadedEvent.Type = {
        CUSTOM_CONTENT_LOADED: 'deprecated-event'
      };

      var CompanionAdSelectionSettings = function CompanionAdSelectionSettings() {};

      CompanionAdSelectionSettings.CreativeType = {
        ALL: 'All',
        FLASH: 'Flash',
        IMAGE: 'Image'
      };
      CompanionAdSelectionSettings.ResourceType = {
        ALL: 'All',
        HTML: 'Html',
        IFRAME: 'IFrame',
        STATIC: 'Static'
      };
      CompanionAdSelectionSettings.SizeCriteria = {
        IGNORE: 'IgnoreSize',
        SELECT_EXACT_MATCH: 'SelectExactMatch',
        SELECT_NEAR_MATCH: 'SelectNearMatch'
      };

      var AdCuePoints = function AdCuePoints() {};

      AdCuePoints.prototype = {
        getCuePoints: function getCuePoints() {
          return [];
        },
        getAdIdRegistry: function getAdIdRegistry() {
          return '';
        },
        getAdIsValue: function getAdIsValue() {
          return '';
        }
      };
      var AdProgressData = noopFunc;

      var UniversalAdIdInfo = function UniversalAdIdInfo() {};

      Object.assign(ima, {
        AdCuePoints: AdCuePoints,
        AdDisplayContainer: AdDisplayContainer,
        AdError: AdError,
        AdErrorEvent: AdErrorEvent,
        AdEvent: AdEvent,
        AdPodInfo: AdPodInfo,
        AdProgressData: AdProgressData,
        AdsLoader: AdsLoader,
        AdsManager: manager,
        AdsManagerLoadedEvent: AdsManagerLoadedEvent,
        AdsRenderingSettings: AdsRenderingSettings,
        AdsRequest: AdsRequest,
        CompanionAd: CompanionAd,
        CompanionAdSelectionSettings: CompanionAdSelectionSettings,
        CustomContentLoadedEvent: CustomContentLoadedEvent,
        gptProxyInstance: {},
        ImaSdkSettings: ImaSdkSettings,
        OmidAccessMode: {
          DOMAIN: 'domain',
          FULL: 'full',
          LIMITED: 'limited'
        },
        settings: new ImaSdkSettings(),
        UiElements: {
          AD_ATTRIBUTION: 'adAttribution',
          COUNTDOWN: 'countdown'
        },
        UniversalAdIdInfo: UniversalAdIdInfo,
        VERSION: VERSION,
        ViewMode: {
          FULLSCREEN: 'fullscreen',
          NORMAL: 'normal'
        }
      });

      if (!window.google) {
        window.google = {};
      }

      window.google.ima = ima;
      hit(source);
    }
    GoogleIma3.names = ['google-ima3'];
    GoogleIma3.injections = [hit, noopFunc];

    /* eslint-disable func-names, no-underscore-dangle */
    /**
     * @redirect didomi-loader
     *
     * @description
     * Mocks Didomi's CMP loader script.
     * https://developers.didomi.io/
     *
     * **Example**
     * ```
     * ||sdk.privacy-center.org/fbf86806f86e/loader.js$script,redirect=didomi-loader
     * ```
     */

    function DidomiLoader(source) {
      function UserConsentStatusForVendorSubscribe() {}

      UserConsentStatusForVendorSubscribe.prototype.filter = function () {
        return new UserConsentStatusForVendorSubscribe();
      };

      UserConsentStatusForVendorSubscribe.prototype.subscribe = noopFunc;

      function UserConsentStatusForVendor() {}

      UserConsentStatusForVendor.prototype.first = function () {
        return new UserConsentStatusForVendorSubscribe();
      };

      UserConsentStatusForVendor.prototype.filter = function () {
        return new UserConsentStatusForVendorSubscribe();
      };

      UserConsentStatusForVendor.prototype.subscribe = noopFunc;
      var DidomiWrapper = {
        isConsentRequired: falseFunc,
        getUserConsentStatusForPurpose: trueFunc,
        getUserConsentStatus: trueFunc,
        getUserStatus: noopFunc,
        getRequiredPurposes: noopArray,
        getUserConsentStatusForVendor: trueFunc,
        Purposes: {
          Cookies: 'cookies'
        },
        notice: {
          configure: noopFunc,
          hide: noopFunc,
          isVisible: falseFunc,
          show: noopFunc,
          showDataProcessing: trueFunc
        },
        isUserConsentStatusPartial: falseFunc,
        on: function on() {
          return {
            actions: {},
            emitter: {},
            services: {},
            store: {}
          };
        },
        shouldConsentBeCollected: falseFunc,
        getUserConsentStatusForAll: noopFunc,
        getObservableOnUserConsentStatusForVendor: function getObservableOnUserConsentStatusForVendor() {
          return new UserConsentStatusForVendor();
        }
      };
      window.Didomi = DidomiWrapper;
      var didomiStateWrapper = {
        didomiExperimentId: '',
        didomiExperimentUserGroup: '',
        didomiGDPRApplies: 1,
        didomiIABConsent: '',
        didomiPurposesConsent: '',
        didomiPurposesConsentDenied: '',
        didomiPurposesConsentUnknown: '',
        didomiVendorsConsent: '',
        didomiVendorsConsentDenied: '',
        didomiVendorsConsentUnknown: '',
        didomiVendorsRawConsent: '',
        didomiVendorsRawConsentDenied: '',
        didomiVendorsRawConsentUnknown: ''
      };
      window.didomiState = didomiStateWrapper;
      var tcData = {
        eventStatus: 'tcloaded',
        gdprApplies: false,
        listenerId: noopFunc,
        vendor: {
          consents: []
        },
        purpose: {
          consents: []
        }
      };

      var __tcfapiWrapper = function __tcfapiWrapper() {
        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        // eslint-disable-next-line no-restricted-syntax
        for (var _i = 0, _args = args; _i < _args.length; _i++) {
          var arg = _args[_i];

          if (typeof arg === 'function') {
            try {
              setTimeout(arg(tcData, true));
            } catch (ex) {
              /* empty */
            }
          }
        }
      };

      window.__tcfapi = __tcfapiWrapper;
      var didomiEventListenersWrapper = {
        stub: true,
        push: noopFunc
      };
      window.didomiEventListeners = didomiEventListenersWrapper;
      var didomiOnReadyWrapper = {
        stub: true,
        push: function push(arg) {
          if (typeof arg !== 'function') {
            return;
          }

          if (document.readyState !== 'complete') {
            window.addEventListener('load', function () {
              setTimeout(arg(window.Didomi));
            });
          } else {
            setTimeout(arg(window.Didomi));
          }
        }
      };
      window.didomiOnReady = window.didomiOnReady || didomiOnReadyWrapper;

      if (Array.isArray(window.didomiOnReady)) {
        window.didomiOnReady.forEach(function (arg) {
          if (typeof arg === 'function') {
            try {
              setTimeout(arg(window.Didomi));
            } catch (e) {
              /* empty */
            }
          }
        });
      }

      hit(source);
    }
    DidomiLoader.names = ['didomi-loader'];
    DidomiLoader.injections = [hit, noopFunc, noopArray, trueFunc, falseFunc];

    /* eslint-disable func-names */
    /**
     * @redirect prebid
     *
     * @description
     * Mocks the prebid.js header bidding suit.
     * https://docs.prebid.org/
     *
     * **Example**
     * ```
     * ||tmgrup.com.tr/bd/hb/prebid.js$script,redirect=prebid
     * ```
     */

    function Prebid(source) {
      var pushFunction = function pushFunction(arg) {
        if (typeof arg === 'function') {
          try {
            arg.call();
          } catch (ex) {
            /* empty */
          }
        }
      };

      var pbjsWrapper = {
        addAdUnits: function addAdUnits() {},
        adServers: {
          dfp: {
            // https://docs.prebid.org/dev-docs/publisher-api-reference/adServers.dfp.buildVideoUrl.html
            // returns ad URL
            buildVideoUrl: noopStr
          }
        },
        adUnits: [],
        aliasBidder: function aliasBidder() {},
        cmd: [],
        enableAnalytics: function enableAnalytics() {},
        getHighestCpmBids: noopArray,
        libLoaded: true,
        que: [],
        requestBids: function requestBids(arg) {
          if (arg instanceof Object && arg.bidsBackHandler) {
            try {
              arg.bidsBackHandler.call(); // https://docs.prebid.org/dev-docs/publisher-api-reference/requestBids.html
            } catch (ex) {
              /* empty */
            }
          }
        },
        removeAdUnit: function removeAdUnit() {},
        setBidderConfig: function setBidderConfig() {},
        setConfig: function setConfig() {},
        setTargetingForGPTAsync: function setTargetingForGPTAsync() {}
      };
      pbjsWrapper.cmd.push = pushFunction;
      pbjsWrapper.que.push = pushFunction;
      window.pbjs = pbjsWrapper;
      hit(source);
    }
    Prebid.names = ['prebid'];
    Prebid.injections = [hit, noopFunc, noopStr, noopArray];

    /* eslint-disable func-names */
    /**
     * @redirect prebid-ads
     *
     * @description
     * Sets predefined constants on a page:
     * - `canRunAds`: `true`
     * - `isAdBlockActive`: `false`
     *
     * **Example**
     * ```
     * ||playerdrive.me/assets/js/prebid-ads.js$script,redirect=prebid-ads
     * ```
     */

    function prebidAds(source) {
      window.canRunAds = true;
      window.isAdBlockActive = false;
      hit(source);
    }
    prebidAds.names = ['prebid-ads', 'ubo-prebid-ads.js', 'prebid-ads.js'];
    prebidAds.injections = [hit];

    /* eslint-disable func-names */
    /**
     * @redirect naver-wcslog
     *
     * @description
     * Mocks wcslog.js of Naver Analytics.
     *
     * **Example**
     * ```
     * ||wcs.naver.net/wcslog.js$script,redirect=naver-wcslog
     * ```
     */

    function NaverWcslog(source) {
      window.wcs_add = {};
      window.wcs_do = noopFunc;
      window.wcs = {
        inflow: noopFunc
      };
      hit(source);
    }
    NaverWcslog.names = ['naver-wcslog'];
    NaverWcslog.injections = [hit, noopFunc];

    var redirectsList = /*#__PURE__*/Object.freeze({
        __proto__: null,
        noeval: noeval,
        GoogleAnalytics: GoogleAnalytics,
        GoogleAnalyticsGa: GoogleAnalyticsGa,
        GoogleSyndicationAdsByGoogle: GoogleSyndicationAdsByGoogle,
        GoogleTagServicesGpt: GoogleTagServicesGpt,
        ScoreCardResearchBeacon: ScoreCardResearchBeacon,
        metrikaYandexTag: metrikaYandexTag,
        metrikaYandexWatch: metrikaYandexWatch,
        preventFab: preventFab,
        preventBab: preventBab,
        setPopadsDummy: setPopadsDummy,
        preventPopadsNet: preventPopadsNet,
        AmazonApstag: AmazonApstag,
        Matomo: Matomo,
        Fingerprintjs2: Fingerprintjs2,
        Fingerprintjs3: Fingerprintjs3,
        Gemius: Gemius,
        ATInternetSmartTag: ATInternetSmartTag,
        preventBab2: preventBab2,
        GoogleIma3: GoogleIma3,
        DidomiLoader: DidomiLoader,
        Prebid: Prebid,
        prebidAds: prebidAds,
        NaverWcslog: NaverWcslog
    });

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

    var classCallCheck = _classCallCheck;

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

    function _createClass(Constructor, protoProps, staticProps) {
      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
      if (staticProps) _defineProperties(Constructor, staticProps);
      return Constructor;
    }

    var createClass = _createClass;

    function isNothing(subject) {
      return typeof subject === 'undefined' || subject === null;
    }

    function isObject(subject) {
      return typeof subject === 'object' && subject !== null;
    }

    function toArray$1(sequence) {
      if (Array.isArray(sequence)) return sequence;else if (isNothing(sequence)) return [];
      return [sequence];
    }

    function extend(target, source) {
      var index, length, key, sourceKeys;

      if (source) {
        sourceKeys = Object.keys(source);

        for (index = 0, length = sourceKeys.length; index < length; index += 1) {
          key = sourceKeys[index];
          target[key] = source[key];
        }
      }

      return target;
    }

    function repeat(string, count) {
      var result = '',
          cycle;

      for (cycle = 0; cycle < count; cycle += 1) {
        result += string;
      }

      return result;
    }

    function isNegativeZero(number) {
      return number === 0 && Number.NEGATIVE_INFINITY === 1 / number;
    }

    var isNothing_1 = isNothing;
    var isObject_1 = isObject;
    var toArray_1 = toArray$1;
    var repeat_1 = repeat;
    var isNegativeZero_1 = isNegativeZero;
    var extend_1 = extend;
    var common = {
      isNothing: isNothing_1,
      isObject: isObject_1,
      toArray: toArray_1,
      repeat: repeat_1,
      isNegativeZero: isNegativeZero_1,
      extend: extend_1
    };

    // YAML error class. http://stackoverflow.com/questions/8458984

    function YAMLException(reason, mark) {
      // Super constructor
      Error.call(this);
      this.name = 'YAMLException';
      this.reason = reason;
      this.mark = mark;
      this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : ''); // Include stack trace in error object

      if (Error.captureStackTrace) {
        // Chrome and NodeJS
        Error.captureStackTrace(this, this.constructor);
      } else {
        // FF, IE 10+ and Safari 6+. Fallback for others
        this.stack = new Error().stack || '';
      }
    } // Inherit from Error


    YAMLException.prototype = Object.create(Error.prototype);
    YAMLException.prototype.constructor = YAMLException;

    YAMLException.prototype.toString = function toString(compact) {
      var result = this.name + ': ';
      result += this.reason || '(unknown reason)';

      if (!compact && this.mark) {
        result += ' ' + this.mark.toString();
      }

      return result;
    };

    var exception = YAMLException;

    function Mark(name, buffer, position, line, column) {
      this.name = name;
      this.buffer = buffer;
      this.position = position;
      this.line = line;
      this.column = column;
    }

    Mark.prototype.getSnippet = function getSnippet(indent, maxLength) {
      var head, start, tail, end, snippet;
      if (!this.buffer) return null;
      indent = indent || 4;
      maxLength = maxLength || 75;
      head = '';
      start = this.position;

      while (start > 0 && "\0\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(start - 1)) === -1) {
        start -= 1;

        if (this.position - start > maxLength / 2 - 1) {
          head = ' ... ';
          start += 5;
          break;
        }
      }

      tail = '';
      end = this.position;

      while (end < this.buffer.length && "\0\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(end)) === -1) {
        end += 1;

        if (end - this.position > maxLength / 2 - 1) {
          tail = ' ... ';
          end -= 5;
          break;
        }
      }

      snippet = this.buffer.slice(start, end);
      return common.repeat(' ', indent) + head + snippet + tail + '\n' + common.repeat(' ', indent + this.position - start + head.length) + '^';
    };

    Mark.prototype.toString = function toString(compact) {
      var snippet,
          where = '';

      if (this.name) {
        where += 'in "' + this.name + '" ';
      }

      where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1);

      if (!compact) {
        snippet = this.getSnippet();

        if (snippet) {
          where += ':\n' + snippet;
        }
      }

      return where;
    };

    var mark = Mark;

    var TYPE_CONSTRUCTOR_OPTIONS = ['kind', 'resolve', 'construct', 'instanceOf', 'predicate', 'represent', 'defaultStyle', 'styleAliases'];
    var YAML_NODE_KINDS = ['scalar', 'sequence', 'mapping'];

    function compileStyleAliases(map) {
      var result = {};

      if (map !== null) {
        Object.keys(map).forEach(function (style) {
          map[style].forEach(function (alias) {
            result[String(alias)] = style;
          });
        });
      }

      return result;
    }

    function Type(tag, options) {
      options = options || {};
      Object.keys(options).forEach(function (name) {
        if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) {
          throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.');
        }
      }); // TODO: Add tag format check.

      this.tag = tag;
      this.kind = options['kind'] || null;

      this.resolve = options['resolve'] || function () {
        return true;
      };

      this.construct = options['construct'] || function (data) {
        return data;
      };

      this.instanceOf = options['instanceOf'] || null;
      this.predicate = options['predicate'] || null;
      this.represent = options['represent'] || null;
      this.defaultStyle = options['defaultStyle'] || null;
      this.styleAliases = compileStyleAliases(options['styleAliases'] || null);

      if (YAML_NODE_KINDS.indexOf(this.kind) === -1) {
        throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.');
      }
    }

    var type = Type;

    /*eslint-disable max-len*/


    function compileList(schema, name, result) {
      var exclude = [];
      schema.include.forEach(function (includedSchema) {
        result = compileList(includedSchema, name, result);
      });
      schema[name].forEach(function (currentType) {
        result.forEach(function (previousType, previousIndex) {
          if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) {
            exclude.push(previousIndex);
          }
        });
        result.push(currentType);
      });
      return result.filter(function (type, index) {
        return exclude.indexOf(index) === -1;
      });
    }

    function compileMap()
    /* lists... */
    {
      var result = {
        scalar: {},
        sequence: {},
        mapping: {},
        fallback: {}
      },
          index,
          length;

      function collectType(type) {
        result[type.kind][type.tag] = result['fallback'][type.tag] = type;
      }

      for (index = 0, length = arguments.length; index < length; index += 1) {
        arguments[index].forEach(collectType);
      }

      return result;
    }

    function Schema(definition) {
      this.include = definition.include || [];
      this.implicit = definition.implicit || [];
      this.explicit = definition.explicit || [];
      this.implicit.forEach(function (type) {
        if (type.loadKind && type.loadKind !== 'scalar') {
          throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.');
        }
      });
      this.compiledImplicit = compileList(this, 'implicit', []);
      this.compiledExplicit = compileList(this, 'explicit', []);
      this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit);
    }

    Schema.DEFAULT = null;

    Schema.create = function createSchema() {
      var schemas, types;

      switch (arguments.length) {
        case 1:
          schemas = Schema.DEFAULT;
          types = arguments[0];
          break;

        case 2:
          schemas = arguments[0];
          types = arguments[1];
          break;

        default:
          throw new exception('Wrong number of arguments for Schema.create function');
      }

      schemas = common.toArray(schemas);
      types = common.toArray(types);

      if (!schemas.every(function (schema) {
        return schema instanceof Schema;
      })) {
        throw new exception('Specified list of super schemas (or a single Schema object) contains a non-Schema object.');
      }

      if (!types.every(function (type$1) {
        return type$1 instanceof type;
      })) {
        throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.');
      }

      return new Schema({
        include: schemas,
        explicit: types
      });
    };

    var schema = Schema;

    var str = new type('tag:yaml.org,2002:str', {
      kind: 'scalar',
      construct: function construct(data) {
        return data !== null ? data : '';
      }
    });

    var seq = new type('tag:yaml.org,2002:seq', {
      kind: 'sequence',
      construct: function construct(data) {
        return data !== null ? data : [];
      }
    });

    var map = new type('tag:yaml.org,2002:map', {
      kind: 'mapping',
      construct: function construct(data) {
        return data !== null ? data : {};
      }
    });

    var failsafe = new schema({
      explicit: [str, seq, map]
    });

    function resolveYamlNull(data) {
      if (data === null) return true;
      var max = data.length;
      return max === 1 && data === '~' || max === 4 && (data === 'null' || data === 'Null' || data === 'NULL');
    }

    function constructYamlNull() {
      return null;
    }

    function isNull(object) {
      return object === null;
    }

    var _null = new type('tag:yaml.org,2002:null', {
      kind: 'scalar',
      resolve: resolveYamlNull,
      construct: constructYamlNull,
      predicate: isNull,
      represent: {
        canonical: function canonical() {
          return '~';
        },
        lowercase: function lowercase() {
          return 'null';
        },
        uppercase: function uppercase() {
          return 'NULL';
        },
        camelcase: function camelcase() {
          return 'Null';
        }
      },
      defaultStyle: 'lowercase'
    });

    function resolveYamlBoolean(data) {
      if (data === null) return false;
      var max = data.length;
      return max === 4 && (data === 'true' || data === 'True' || data === 'TRUE') || max === 5 && (data === 'false' || data === 'False' || data === 'FALSE');
    }

    function constructYamlBoolean(data) {
      return data === 'true' || data === 'True' || data === 'TRUE';
    }

    function isBoolean(object) {
      return Object.prototype.toString.call(object) === '[object Boolean]';
    }

    var bool = new type('tag:yaml.org,2002:bool', {
      kind: 'scalar',
      resolve: resolveYamlBoolean,
      construct: constructYamlBoolean,
      predicate: isBoolean,
      represent: {
        lowercase: function lowercase(object) {
          return object ? 'true' : 'false';
        },
        uppercase: function uppercase(object) {
          return object ? 'TRUE' : 'FALSE';
        },
        camelcase: function camelcase(object) {
          return object ? 'True' : 'False';
        }
      },
      defaultStyle: 'lowercase'
    });

    function isHexCode(c) {
      return 0x30
      /* 0 */
      <= c && c <= 0x39
      /* 9 */
      || 0x41
      /* A */
      <= c && c <= 0x46
      /* F */
      || 0x61
      /* a */
      <= c && c <= 0x66
      /* f */
      ;
    }

    function isOctCode(c) {
      return 0x30
      /* 0 */
      <= c && c <= 0x37
      /* 7 */
      ;
    }

    function isDecCode(c) {
      return 0x30
      /* 0 */
      <= c && c <= 0x39
      /* 9 */
      ;
    }

    function resolveYamlInteger(data) {
      if (data === null) return false;
      var max = data.length,
          index = 0,
          hasDigits = false,
          ch;
      if (!max) return false;
      ch = data[index]; // sign

      if (ch === '-' || ch === '+') {
        ch = data[++index];
      }

      if (ch === '0') {
        // 0
        if (index + 1 === max) return true;
        ch = data[++index]; // base 2, base 8, base 16

        if (ch === 'b') {
          // base 2
          index++;

          for (; index < max; index++) {
            ch = data[index];
            if (ch === '_') continue;
            if (ch !== '0' && ch !== '1') return false;
            hasDigits = true;
          }

          return hasDigits && ch !== '_';
        }

        if (ch === 'x') {
          // base 16
          index++;

          for (; index < max; index++) {
            ch = data[index];
            if (ch === '_') continue;
            if (!isHexCode(data.charCodeAt(index))) return false;
            hasDigits = true;
          }

          return hasDigits && ch !== '_';
        } // base 8


        for (; index < max; index++) {
          ch = data[index];
          if (ch === '_') continue;
          if (!isOctCode(data.charCodeAt(index))) return false;
          hasDigits = true;
        }

        return hasDigits && ch !== '_';
      } // base 10 (except 0) or base 60
      // value should not start with `_`;


      if (ch === '_') return false;

      for (; index < max; index++) {
        ch = data[index];
        if (ch === '_') continue;
        if (ch === ':') break;

        if (!isDecCode(data.charCodeAt(index))) {
          return false;
        }

        hasDigits = true;
      } // Should have digits and should not end with `_`


      if (!hasDigits || ch === '_') return false; // if !base60 - done;

      if (ch !== ':') return true; // base60 almost not used, no needs to optimize

      return /^(:[0-5]?[0-9])+$/.test(data.slice(index));
    }

    function constructYamlInteger(data) {
      var value = data,
          sign = 1,
          ch,
          base,
          digits = [];

      if (value.indexOf('_') !== -1) {
        value = value.replace(/_/g, '');
      }

      ch = value[0];

      if (ch === '-' || ch === '+') {
        if (ch === '-') sign = -1;
        value = value.slice(1);
        ch = value[0];
      }

      if (value === '0') return 0;

      if (ch === '0') {
        if (value[1] === 'b') return sign * parseInt(value.slice(2), 2);
        if (value[1] === 'x') return sign * parseInt(value, 16);
        return sign * parseInt(value, 8);
      }

      if (value.indexOf(':') !== -1) {
        value.split(':').forEach(function (v) {
          digits.unshift(parseInt(v, 10));
        });
        value = 0;
        base = 1;
        digits.forEach(function (d) {
          value += d * base;
          base *= 60;
        });
        return sign * value;
      }

      return sign * parseInt(value, 10);
    }

    function isInteger(object) {
      return Object.prototype.toString.call(object) === '[object Number]' && object % 1 === 0 && !common.isNegativeZero(object);
    }

    var int = new type('tag:yaml.org,2002:int', {
      kind: 'scalar',
      resolve: resolveYamlInteger,
      construct: constructYamlInteger,
      predicate: isInteger,
      represent: {
        binary: function binary(obj) {
          return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1);
        },
        octal: function octal(obj) {
          return obj >= 0 ? '0' + obj.toString(8) : '-0' + obj.toString(8).slice(1);
        },
        decimal: function decimal(obj) {
          return obj.toString(10);
        },

        /* eslint-disable max-len */
        hexadecimal: function hexadecimal(obj) {
          return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1);
        }
      },
      defaultStyle: 'decimal',
      styleAliases: {
        binary: [2, 'bin'],
        octal: [8, 'oct'],
        decimal: [10, 'dec'],
        hexadecimal: [16, 'hex']
      }
    });

    var YAML_FLOAT_PATTERN = new RegExp( // 2.5e4, 2.5 and integers
    '^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + // .2e4, .2
    // special case, seems not from spec
    '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + // 20:59
    '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + // .inf
    '|[-+]?\\.(?:inf|Inf|INF)' + // .nan
    '|\\.(?:nan|NaN|NAN))$');

    function resolveYamlFloat(data) {
      if (data === null) return false;

      if (!YAML_FLOAT_PATTERN.test(data) || // Quick hack to not allow integers end with `_`
      // Probably should update regexp & check speed
      data[data.length - 1] === '_') {
        return false;
      }

      return true;
    }

    function constructYamlFloat(data) {
      var value, sign, base, digits;
      value = data.replace(/_/g, '').toLowerCase();
      sign = value[0] === '-' ? -1 : 1;
      digits = [];

      if ('+-'.indexOf(value[0]) >= 0) {
        value = value.slice(1);
      }

      if (value === '.inf') {
        return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
      } else if (value === '.nan') {
        return NaN;
      } else if (value.indexOf(':') >= 0) {
        value.split(':').forEach(function (v) {
          digits.unshift(parseFloat(v, 10));
        });
        value = 0.0;
        base = 1;
        digits.forEach(function (d) {
          value += d * base;
          base *= 60;
        });
        return sign * value;
      }

      return sign * parseFloat(value, 10);
    }

    var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/;

    function representYamlFloat(object, style) {
      var res;

      if (isNaN(object)) {
        switch (style) {
          case 'lowercase':
            return '.nan';

          case 'uppercase':
            return '.NAN';

          case 'camelcase':
            return '.NaN';
        }
      } else if (Number.POSITIVE_INFINITY === object) {
        switch (style) {
          case 'lowercase':
            return '.inf';

          case 'uppercase':
            return '.INF';

          case 'camelcase':
            return '.Inf';
        }
      } else if (Number.NEGATIVE_INFINITY === object) {
        switch (style) {
          case 'lowercase':
            return '-.inf';

          case 'uppercase':
            return '-.INF';

          case 'camelcase':
            return '-.Inf';
        }
      } else if (common.isNegativeZero(object)) {
        return '-0.0';
      }

      res = object.toString(10); // JS stringifier can build scientific format without dots: 5e-100,
      // while YAML requres dot: 5.e-100. Fix it with simple hack

      return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res;
    }

    function isFloat(object) {
      return Object.prototype.toString.call(object) === '[object Number]' && (object % 1 !== 0 || common.isNegativeZero(object));
    }

    var float = new type('tag:yaml.org,2002:float', {
      kind: 'scalar',
      resolve: resolveYamlFloat,
      construct: constructYamlFloat,
      predicate: isFloat,
      represent: representYamlFloat,
      defaultStyle: 'lowercase'
    });

    var json = new schema({
      include: [failsafe],
      implicit: [_null, bool, int, float]
    });

    var core = new schema({
      include: [json]
    });

    var YAML_DATE_REGEXP = new RegExp('^([0-9][0-9][0-9][0-9])' + // [1] year
    '-([0-9][0-9])' + // [2] month
    '-([0-9][0-9])$'); // [3] day

    var YAML_TIMESTAMP_REGEXP = new RegExp('^([0-9][0-9][0-9][0-9])' + // [1] year
    '-([0-9][0-9]?)' + // [2] month
    '-([0-9][0-9]?)' + // [3] day
    '(?:[Tt]|[ \\t]+)' + // ...
    '([0-9][0-9]?)' + // [4] hour
    ':([0-9][0-9])' + // [5] minute
    ':([0-9][0-9])' + // [6] second
    '(?:\\.([0-9]*))?' + // [7] fraction
    '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour
    '(?::([0-9][0-9]))?))?$'); // [11] tz_minute

    function resolveYamlTimestamp(data) {
      if (data === null) return false;
      if (YAML_DATE_REGEXP.exec(data) !== null) return true;
      if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true;
      return false;
    }

    function constructYamlTimestamp(data) {
      var match,
          year,
          month,
          day,
          hour,
          minute,
          second,
          fraction = 0,
          delta = null,
          tz_hour,
          tz_minute,
          date;
      match = YAML_DATE_REGEXP.exec(data);
      if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data);
      if (match === null) throw new Error('Date resolve error'); // match: [1] year [2] month [3] day

      year = +match[1];
      month = +match[2] - 1; // JS month starts with 0

      day = +match[3];

      if (!match[4]) {
        // no hour
        return new Date(Date.UTC(year, month, day));
      } // match: [4] hour [5] minute [6] second [7] fraction


      hour = +match[4];
      minute = +match[5];
      second = +match[6];

      if (match[7]) {
        fraction = match[7].slice(0, 3);

        while (fraction.length < 3) {
          // milli-seconds
          fraction += '0';
        }

        fraction = +fraction;
      } // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute


      if (match[9]) {
        tz_hour = +match[10];
        tz_minute = +(match[11] || 0);
        delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds

        if (match[9] === '-') delta = -delta;
      }

      date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
      if (delta) date.setTime(date.getTime() - delta);
      return date;
    }

    function representYamlTimestamp(object
    /*, style*/
    ) {
      return object.toISOString();
    }

    var timestamp = new type('tag:yaml.org,2002:timestamp', {
      kind: 'scalar',
      resolve: resolveYamlTimestamp,
      construct: constructYamlTimestamp,
      instanceOf: Date,
      represent: representYamlTimestamp
    });

    function resolveYamlMerge(data) {
      return data === '<<' || data === null;
    }

    var merge = new type('tag:yaml.org,2002:merge', {
      kind: 'scalar',
      resolve: resolveYamlMerge
    });

    function commonjsRequire (target) {
    	throw new Error('Could not dynamically require "' + target + '". Please configure the dynamicRequireTargets option of @rollup/plugin-commonjs appropriately for this require call to behave properly.');
    }

    /*eslint-disable no-bitwise*/


    var NodeBuffer;

    try {
      // A trick for browserified version, to not include `Buffer` shim
      var _require = commonjsRequire;
      NodeBuffer = _require('buffer').Buffer;
    } catch (__) {} // [ 64, 65, 66 ] -> [ padding, CR, LF ]


    var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r';

    function resolveYamlBinary(data) {
      if (data === null) return false;
      var code,
          idx,
          bitlen = 0,
          max = data.length,
          map = BASE64_MAP; // Convert one by one.

      for (idx = 0; idx < max; idx++) {
        code = map.indexOf(data.charAt(idx)); // Skip CR/LF

        if (code > 64) continue; // Fail on illegal characters

        if (code < 0) return false;
        bitlen += 6;
      } // If there are any bits left, source was corrupted


      return bitlen % 8 === 0;
    }

    function constructYamlBinary(data) {
      var idx,
          tailbits,
          input = data.replace(/[\r\n=]/g, ''),
          // remove CR/LF & padding to simplify scan
      max = input.length,
          map = BASE64_MAP,
          bits = 0,
          result = []; // Collect by 6*4 bits (3 bytes)

      for (idx = 0; idx < max; idx++) {
        if (idx % 4 === 0 && idx) {
          result.push(bits >> 16 & 0xFF);
          result.push(bits >> 8 & 0xFF);
          result.push(bits & 0xFF);
        }

        bits = bits << 6 | map.indexOf(input.charAt(idx));
      } // Dump tail


      tailbits = max % 4 * 6;

      if (tailbits === 0) {
        result.push(bits >> 16 & 0xFF);
        result.push(bits >> 8 & 0xFF);
        result.push(bits & 0xFF);
      } else if (tailbits === 18) {
        result.push(bits >> 10 & 0xFF);
        result.push(bits >> 2 & 0xFF);
      } else if (tailbits === 12) {
        result.push(bits >> 4 & 0xFF);
      } // Wrap into Buffer for NodeJS and leave Array for browser


      if (NodeBuffer) {
        // Support node 6.+ Buffer API when available
        return NodeBuffer.from ? NodeBuffer.from(result) : new NodeBuffer(result);
      }

      return result;
    }

    function representYamlBinary(object
    /*, style*/
    ) {
      var result = '',
          bits = 0,
          idx,
          tail,
          max = object.length,
          map = BASE64_MAP; // Convert every three bytes to 4 ASCII characters.

      for (idx = 0; idx < max; idx++) {
        if (idx % 3 === 0 && idx) {
          result += map[bits >> 18 & 0x3F];
          result += map[bits >> 12 & 0x3F];
          result += map[bits >> 6 & 0x3F];
          result += map[bits & 0x3F];
        }

        bits = (bits << 8) + object[idx];
      } // Dump tail


      tail = max % 3;

      if (tail === 0) {
        result += map[bits >> 18 & 0x3F];
        result += map[bits >> 12 & 0x3F];
        result += map[bits >> 6 & 0x3F];
        result += map[bits & 0x3F];
      } else if (tail === 2) {
        result += map[bits >> 10 & 0x3F];
        result += map[bits >> 4 & 0x3F];
        result += map[bits << 2 & 0x3F];
        result += map[64];
      } else if (tail === 1) {
        result += map[bits >> 2 & 0x3F];
        result += map[bits << 4 & 0x3F];
        result += map[64];
        result += map[64];
      }

      return result;
    }

    function isBinary(object) {
      return NodeBuffer && NodeBuffer.isBuffer(object);
    }

    var binary = new type('tag:yaml.org,2002:binary', {
      kind: 'scalar',
      resolve: resolveYamlBinary,
      construct: constructYamlBinary,
      predicate: isBinary,
      represent: representYamlBinary
    });

    var _hasOwnProperty = Object.prototype.hasOwnProperty;
    var _toString = Object.prototype.toString;

    function resolveYamlOmap(data) {
      if (data === null) return true;
      var objectKeys = [],
          index,
          length,
          pair,
          pairKey,
          pairHasKey,
          object = data;

      for (index = 0, length = object.length; index < length; index += 1) {
        pair = object[index];
        pairHasKey = false;
        if (_toString.call(pair) !== '[object Object]') return false;

        for (pairKey in pair) {
          if (_hasOwnProperty.call(pair, pairKey)) {
            if (!pairHasKey) pairHasKey = true;else return false;
          }
        }

        if (!pairHasKey) return false;
        if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey);else return false;
      }

      return true;
    }

    function constructYamlOmap(data) {
      return data !== null ? data : [];
    }

    var omap = new type('tag:yaml.org,2002:omap', {
      kind: 'sequence',
      resolve: resolveYamlOmap,
      construct: constructYamlOmap
    });

    var _toString$1 = Object.prototype.toString;

    function resolveYamlPairs(data) {
      if (data === null) return true;
      var index,
          length,
          pair,
          keys,
          result,
          object = data;
      result = new Array(object.length);

      for (index = 0, length = object.length; index < length; index += 1) {
        pair = object[index];
        if (_toString$1.call(pair) !== '[object Object]') return false;
        keys = Object.keys(pair);
        if (keys.length !== 1) return false;
        result[index] = [keys[0], pair[keys[0]]];
      }

      return true;
    }

    function constructYamlPairs(data) {
      if (data === null) return [];
      var index,
          length,
          pair,
          keys,
          result,
          object = data;
      result = new Array(object.length);

      for (index = 0, length = object.length; index < length; index += 1) {
        pair = object[index];
        keys = Object.keys(pair);
        result[index] = [keys[0], pair[keys[0]]];
      }

      return result;
    }

    var pairs = new type('tag:yaml.org,2002:pairs', {
      kind: 'sequence',
      resolve: resolveYamlPairs,
      construct: constructYamlPairs
    });

    var _hasOwnProperty$1 = Object.prototype.hasOwnProperty;

    function resolveYamlSet(data) {
      if (data === null) return true;
      var key,
          object = data;

      for (key in object) {
        if (_hasOwnProperty$1.call(object, key)) {
          if (object[key] !== null) return false;
        }
      }

      return true;
    }

    function constructYamlSet(data) {
      return data !== null ? data : {};
    }

    var set = new type('tag:yaml.org,2002:set', {
      kind: 'mapping',
      resolve: resolveYamlSet,
      construct: constructYamlSet
    });

    var default_safe = new schema({
      include: [core],
      implicit: [timestamp, merge],
      explicit: [binary, omap, pairs, set]
    });

    function resolveJavascriptUndefined() {
      return true;
    }

    function constructJavascriptUndefined() {
      /*eslint-disable no-undefined*/
      return undefined;
    }

    function representJavascriptUndefined() {
      return '';
    }

    function isUndefined(object) {
      return typeof object === 'undefined';
    }

    var _undefined = new type('tag:yaml.org,2002:js/undefined', {
      kind: 'scalar',
      resolve: resolveJavascriptUndefined,
      construct: constructJavascriptUndefined,
      predicate: isUndefined,
      represent: representJavascriptUndefined
    });

    function resolveJavascriptRegExp(data) {
      if (data === null) return false;
      if (data.length === 0) return false;
      var regexp = data,
          tail = /\/([gim]*)$/.exec(data),
          modifiers = ''; // if regexp starts with '/' it can have modifiers and must be properly closed
      // `/foo/gim` - modifiers tail can be maximum 3 chars

      if (regexp[0] === '/') {
        if (tail) modifiers = tail[1];
        if (modifiers.length > 3) return false; // if expression starts with /, is should be properly terminated

        if (regexp[regexp.length - modifiers.length - 1] !== '/') return false;
      }

      return true;
    }

    function constructJavascriptRegExp(data) {
      var regexp = data,
          tail = /\/([gim]*)$/.exec(data),
          modifiers = ''; // `/foo/gim` - tail can be maximum 4 chars

      if (regexp[0] === '/') {
        if (tail) modifiers = tail[1];
        regexp = regexp.slice(1, regexp.length - modifiers.length - 1);
      }

      return new RegExp(regexp, modifiers);
    }

    function representJavascriptRegExp(object
    /*, style*/
    ) {
      var result = '/' + object.source + '/';
      if (object.global) result += 'g';
      if (object.multiline) result += 'm';
      if (object.ignoreCase) result += 'i';
      return result;
    }

    function isRegExp(object) {
      return Object.prototype.toString.call(object) === '[object RegExp]';
    }

    var regexp = new type('tag:yaml.org,2002:js/regexp', {
      kind: 'scalar',
      resolve: resolveJavascriptRegExp,
      construct: constructJavascriptRegExp,
      predicate: isRegExp,
      represent: representJavascriptRegExp
    });

    var esprima; // Browserified version does not have esprima
    //
    // 1. For node.js just require module as deps
    // 2. For browser try to require mudule via external AMD system.
    //    If not found - try to fallback to window.esprima. If not
    //    found too - then fail to parse.
    //

    try {
      // workaround to exclude package from browserify list.
      var _require$1 = commonjsRequire;
      esprima = _require$1('esprima');
    } catch (_) {
      /* eslint-disable no-redeclare */

      /* global window */
      if (typeof window !== 'undefined') esprima = window.esprima;
    }

    function resolveJavascriptFunction(data) {
      if (data === null) return false;

      try {
        var source = '(' + data + ')',
            ast = esprima.parse(source, {
          range: true
        });

        if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression') {
          return false;
        }

        return true;
      } catch (err) {
        return false;
      }
    }

    function constructJavascriptFunction(data) {
      /*jslint evil:true*/
      var source = '(' + data + ')',
          ast = esprima.parse(source, {
        range: true
      }),
          params = [],
          body;

      if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression') {
        throw new Error('Failed to resolve function');
      }

      ast.body[0].expression.params.forEach(function (param) {
        params.push(param.name);
      });
      body = ast.body[0].expression.body.range; // Esprima's ranges include the first '{' and the last '}' characters on
      // function expressions. So cut them out.

      if (ast.body[0].expression.body.type === 'BlockStatement') {
        /*eslint-disable no-new-func*/
        return new Function(params, source.slice(body[0] + 1, body[1] - 1));
      } // ES6 arrow functions can omit the BlockStatement. In that case, just return
      // the body.

      /*eslint-disable no-new-func*/


      return new Function(params, 'return ' + source.slice(body[0], body[1]));
    }

    function representJavascriptFunction(object
    /*, style*/
    ) {
      return object.toString();
    }

    function isFunction(object) {
      return Object.prototype.toString.call(object) === '[object Function]';
    }

    var _function = new type('tag:yaml.org,2002:js/function', {
      kind: 'scalar',
      resolve: resolveJavascriptFunction,
      construct: constructJavascriptFunction,
      predicate: isFunction,
      represent: representJavascriptFunction
    });

    var default_full = schema.DEFAULT = new schema({
      include: [default_safe],
      explicit: [_undefined, regexp, _function]
    });

    /*eslint-disable max-len,no-use-before-define*/


    var _hasOwnProperty$2 = Object.prototype.hasOwnProperty;
    var CONTEXT_FLOW_IN = 1;
    var CONTEXT_FLOW_OUT = 2;
    var CONTEXT_BLOCK_IN = 3;
    var CONTEXT_BLOCK_OUT = 4;
    var CHOMPING_CLIP = 1;
    var CHOMPING_STRIP = 2;
    var CHOMPING_KEEP = 3;
    var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/;
    var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/;
    var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/;
    var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i;
    var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;

    function _class(obj) {
      return Object.prototype.toString.call(obj);
    }

    function is_EOL(c) {
      return c === 0x0A
      /* LF */
      || c === 0x0D
      /* CR */
      ;
    }

    function is_WHITE_SPACE(c) {
      return c === 0x09
      /* Tab */
      || c === 0x20
      /* Space */
      ;
    }

    function is_WS_OR_EOL(c) {
      return c === 0x09
      /* Tab */
      || c === 0x20
      /* Space */
      || c === 0x0A
      /* LF */
      || c === 0x0D
      /* CR */
      ;
    }

    function is_FLOW_INDICATOR(c) {
      return c === 0x2C
      /* , */
      || c === 0x5B
      /* [ */
      || c === 0x5D
      /* ] */
      || c === 0x7B
      /* { */
      || c === 0x7D
      /* } */
      ;
    }

    function fromHexCode(c) {
      var lc;

      if (0x30
      /* 0 */
      <= c && c <= 0x39
      /* 9 */
      ) {
        return c - 0x30;
      }
      /*eslint-disable no-bitwise*/


      lc = c | 0x20;

      if (0x61
      /* a */
      <= lc && lc <= 0x66
      /* f */
      ) {
        return lc - 0x61 + 10;
      }

      return -1;
    }

    function escapedHexLen(c) {
      if (c === 0x78
      /* x */
      ) {
          return 2;
        }

      if (c === 0x75
      /* u */
      ) {
          return 4;
        }

      if (c === 0x55
      /* U */
      ) {
          return 8;
        }

      return 0;
    }

    function fromDecimalCode(c) {
      if (0x30
      /* 0 */
      <= c && c <= 0x39
      /* 9 */
      ) {
        return c - 0x30;
      }

      return -1;
    }

    function simpleEscapeSequence(c) {
      /* eslint-disable indent */
      return c === 0x30
      /* 0 */
      ? '\x00' : c === 0x61
      /* a */
      ? '\x07' : c === 0x62
      /* b */
      ? '\x08' : c === 0x74
      /* t */
      ? '\x09' : c === 0x09
      /* Tab */
      ? '\x09' : c === 0x6E
      /* n */
      ? '\x0A' : c === 0x76
      /* v */
      ? '\x0B' : c === 0x66
      /* f */
      ? '\x0C' : c === 0x72
      /* r */
      ? '\x0D' : c === 0x65
      /* e */
      ? '\x1B' : c === 0x20
      /* Space */
      ? ' ' : c === 0x22
      /* " */
      ? '\x22' : c === 0x2F
      /* / */
      ? '/' : c === 0x5C
      /* \ */
      ? '\x5C' : c === 0x4E
      /* N */
      ? '\x85' : c === 0x5F
      /* _ */
      ? '\xA0' : c === 0x4C
      /* L */
      ? "\u2028" : c === 0x50
      /* P */
      ? "\u2029" : '';
    }

    function charFromCodepoint(c) {
      if (c <= 0xFFFF) {
        return String.fromCharCode(c);
      } // Encode UTF-16 surrogate pair
      // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF


      return String.fromCharCode((c - 0x010000 >> 10) + 0xD800, (c - 0x010000 & 0x03FF) + 0xDC00);
    }

    var simpleEscapeCheck = new Array(256); // integer, for fast access

    var simpleEscapeMap = new Array(256);

    for (var i = 0; i < 256; i++) {
      simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0;
      simpleEscapeMap[i] = simpleEscapeSequence(i);
    }

    function State(input, options) {
      this.input = input;
      this.filename = options['filename'] || null;
      this.schema = options['schema'] || default_full;
      this.onWarning = options['onWarning'] || null;
      this.legacy = options['legacy'] || false;
      this.json = options['json'] || false;
      this.listener = options['listener'] || null;
      this.implicitTypes = this.schema.compiledImplicit;
      this.typeMap = this.schema.compiledTypeMap;
      this.length = input.length;
      this.position = 0;
      this.line = 0;
      this.lineStart = 0;
      this.lineIndent = 0;
      this.documents = [];
      /*
      this.version;
      this.checkLineBreaks;
      this.tagMap;
      this.anchorMap;
      this.tag;
      this.anchor;
      this.kind;
      this.result;*/
    }

    function generateError(state, message) {
      return new exception(message, new mark(state.filename, state.input, state.position, state.line, state.position - state.lineStart));
    }

    function throwError(state, message) {
      throw generateError(state, message);
    }

    function throwWarning(state, message) {
      if (state.onWarning) {
        state.onWarning.call(null, generateError(state, message));
      }
    }

    var directiveHandlers = {
      YAML: function handleYamlDirective(state, name, args) {
        var match, major, minor;

        if (state.version !== null) {
          throwError(state, 'duplication of %YAML directive');
        }

        if (args.length !== 1) {
          throwError(state, 'YAML directive accepts exactly one argument');
        }

        match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]);

        if (match === null) {
          throwError(state, 'ill-formed argument of the YAML directive');
        }

        major = parseInt(match[1], 10);
        minor = parseInt(match[2], 10);

        if (major !== 1) {
          throwError(state, 'unacceptable YAML version of the document');
        }

        state.version = args[0];
        state.checkLineBreaks = minor < 2;

        if (minor !== 1 && minor !== 2) {
          throwWarning(state, 'unsupported YAML version of the document');
        }
      },
      TAG: function handleTagDirective(state, name, args) {
        var handle, prefix;

        if (args.length !== 2) {
          throwError(state, 'TAG directive accepts exactly two arguments');
        }

        handle = args[0];
        prefix = args[1];

        if (!PATTERN_TAG_HANDLE.test(handle)) {
          throwError(state, 'ill-formed tag handle (first argument) of the TAG directive');
        }

        if (_hasOwnProperty$2.call(state.tagMap, handle)) {
          throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle');
        }

        if (!PATTERN_TAG_URI.test(prefix)) {
          throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive');
        }

        state.tagMap[handle] = prefix;
      }
    };

    function captureSegment(state, start, end, checkJson) {
      var _position, _length, _character, _result;

      if (start < end) {
        _result = state.input.slice(start, end);

        if (checkJson) {
          for (_position = 0, _length = _result.length; _position < _length; _position += 1) {
            _character = _result.charCodeAt(_position);

            if (!(_character === 0x09 || 0x20 <= _character && _character <= 0x10FFFF)) {
              throwError(state, 'expected valid JSON character');
            }
          }
        } else if (PATTERN_NON_PRINTABLE.test(_result)) {
          throwError(state, 'the stream contains non-printable characters');
        }

        state.result += _result;
      }
    }

    function mergeMappings(state, destination, source, overridableKeys) {
      var sourceKeys, key, index, quantity;

      if (!common.isObject(source)) {
        throwError(state, 'cannot merge mappings; the provided source object is unacceptable');
      }

      sourceKeys = Object.keys(source);

      for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
        key = sourceKeys[index];

        if (!_hasOwnProperty$2.call(destination, key)) {
          destination[key] = source[key];
          overridableKeys[key] = true;
        }
      }
    }

    function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startPos) {
      var index, quantity; // The output is a plain object here, so keys can only be strings.
      // We need to convert keyNode to a string, but doing so can hang the process
      // (deeply nested arrays that explode exponentially using aliases).

      if (Array.isArray(keyNode)) {
        keyNode = Array.prototype.slice.call(keyNode);

        for (index = 0, quantity = keyNode.length; index < quantity; index += 1) {
          if (Array.isArray(keyNode[index])) {
            throwError(state, 'nested arrays are not supported inside keys');
          }

          if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') {
            keyNode[index] = '[object Object]';
          }
        }
      } // Avoid code execution in load() via toString property
      // (still use its own toString for arrays, timestamps,
      // and whatever user schema extensions happen to have @@toStringTag)


      if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') {
        keyNode = '[object Object]';
      }

      keyNode = String(keyNode);

      if (_result === null) {
        _result = {};
      }

      if (keyTag === 'tag:yaml.org,2002:merge') {
        if (Array.isArray(valueNode)) {
          for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
            mergeMappings(state, _result, valueNode[index], overridableKeys);
          }
        } else {
          mergeMappings(state, _result, valueNode, overridableKeys);
        }
      } else {
        if (!state.json && !_hasOwnProperty$2.call(overridableKeys, keyNode) && _hasOwnProperty$2.call(_result, keyNode)) {
          state.line = startLine || state.line;
          state.position = startPos || state.position;
          throwError(state, 'duplicated mapping key');
        }

        _result[keyNode] = valueNode;
        delete overridableKeys[keyNode];
      }

      return _result;
    }

    function readLineBreak(state) {
      var ch;
      ch = state.input.charCodeAt(state.position);

      if (ch === 0x0A
      /* LF */
      ) {
          state.position++;
        } else if (ch === 0x0D
      /* CR */
      ) {
          state.position++;

          if (state.input.charCodeAt(state.position) === 0x0A
          /* LF */
          ) {
              state.position++;
            }
        } else {
        throwError(state, 'a line break is expected');
      }

      state.line += 1;
      state.lineStart = state.position;
    }

    function skipSeparationSpace(state, allowComments, checkIndent) {
      var lineBreaks = 0,
          ch = state.input.charCodeAt(state.position);

      while (ch !== 0) {
        while (is_WHITE_SPACE(ch)) {
          ch = state.input.charCodeAt(++state.position);
        }

        if (allowComments && ch === 0x23
        /* # */
        ) {
            do {
              ch = state.input.charCodeAt(++state.position);
            } while (ch !== 0x0A
            /* LF */
            && ch !== 0x0D
            /* CR */
            && ch !== 0);
          }

        if (is_EOL(ch)) {
          readLineBreak(state);
          ch = state.input.charCodeAt(state.position);
          lineBreaks++;
          state.lineIndent = 0;

          while (ch === 0x20
          /* Space */
          ) {
            state.lineIndent++;
            ch = state.input.charCodeAt(++state.position);
          }
        } else {
          break;
        }
      }

      if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) {
        throwWarning(state, 'deficient indentation');
      }

      return lineBreaks;
    }

    function testDocumentSeparator(state) {
      var _position = state.position,
          ch;
      ch = state.input.charCodeAt(_position); // Condition state.position === state.lineStart is tested
      // in parent on each call, for efficiency. No needs to test here again.

      if ((ch === 0x2D
      /* - */
      || ch === 0x2E
      /* . */
      ) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) {
        _position += 3;
        ch = state.input.charCodeAt(_position);

        if (ch === 0 || is_WS_OR_EOL(ch)) {
          return true;
        }
      }

      return false;
    }

    function writeFoldedLines(state, count) {
      if (count === 1) {
        state.result += ' ';
      } else if (count > 1) {
        state.result += common.repeat('\n', count - 1);
      }
    }

    function readPlainScalar(state, nodeIndent, withinFlowCollection) {
      var preceding,
          following,
          captureStart,
          captureEnd,
          hasPendingContent,
          _line,
          _lineStart,
          _lineIndent,
          _kind = state.kind,
          _result = state.result,
          ch;

      ch = state.input.charCodeAt(state.position);

      if (is_WS_OR_EOL(ch) || is_FLOW_INDICATOR(ch) || ch === 0x23
      /* # */
      || ch === 0x26
      /* & */
      || ch === 0x2A
      /* * */
      || ch === 0x21
      /* ! */
      || ch === 0x7C
      /* | */
      || ch === 0x3E
      /* > */
      || ch === 0x27
      /* ' */
      || ch === 0x22
      /* " */
      || ch === 0x25
      /* % */
      || ch === 0x40
      /* @ */
      || ch === 0x60
      /* ` */
      ) {
          return false;
        }

      if (ch === 0x3F
      /* ? */
      || ch === 0x2D
      /* - */
      ) {
          following = state.input.charCodeAt(state.position + 1);

          if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) {
            return false;
          }
        }

      state.kind = 'scalar';
      state.result = '';
      captureStart = captureEnd = state.position;
      hasPendingContent = false;

      while (ch !== 0) {
        if (ch === 0x3A
        /* : */
        ) {
            following = state.input.charCodeAt(state.position + 1);

            if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) {
              break;
            }
          } else if (ch === 0x23
        /* # */
        ) {
            preceding = state.input.charCodeAt(state.position - 1);

            if (is_WS_OR_EOL(preceding)) {
              break;
            }
          } else if (state.position === state.lineStart && testDocumentSeparator(state) || withinFlowCollection && is_FLOW_INDICATOR(ch)) {
          break;
        } else if (is_EOL(ch)) {
          _line = state.line;
          _lineStart = state.lineStart;
          _lineIndent = state.lineIndent;
          skipSeparationSpace(state, false, -1);

          if (state.lineIndent >= nodeIndent) {
            hasPendingContent = true;
            ch = state.input.charCodeAt(state.position);
            continue;
          } else {
            state.position = captureEnd;
            state.line = _line;
            state.lineStart = _lineStart;
            state.lineIndent = _lineIndent;
            break;
          }
        }

        if (hasPendingContent) {
          captureSegment(state, captureStart, captureEnd, false);
          writeFoldedLines(state, state.line - _line);
          captureStart = captureEnd = state.position;
          hasPendingContent = false;
        }

        if (!is_WHITE_SPACE(ch)) {
          captureEnd = state.position + 1;
        }

        ch = state.input.charCodeAt(++state.position);
      }

      captureSegment(state, captureStart, captureEnd, false);

      if (state.result) {
        return true;
      }

      state.kind = _kind;
      state.result = _result;
      return false;
    }

    function readSingleQuotedScalar(state, nodeIndent) {
      var ch, captureStart, captureEnd;
      ch = state.input.charCodeAt(state.position);

      if (ch !== 0x27
      /* ' */
      ) {
          return false;
        }

      state.kind = 'scalar';
      state.result = '';
      state.position++;
      captureStart = captureEnd = state.position;

      while ((ch = state.input.charCodeAt(state.position)) !== 0) {
        if (ch === 0x27
        /* ' */
        ) {
            captureSegment(state, captureStart, state.position, true);
            ch = state.input.charCodeAt(++state.position);

            if (ch === 0x27
            /* ' */
            ) {
                captureStart = state.position;
                state.position++;
                captureEnd = state.position;
              } else {
              return true;
            }
          } else if (is_EOL(ch)) {
          captureSegment(state, captureStart, captureEnd, true);
          writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
          captureStart = captureEnd = state.position;
        } else if (state.position === state.lineStart && testDocumentSeparator(state)) {
          throwError(state, 'unexpected end of the document within a single quoted scalar');
        } else {
          state.position++;
          captureEnd = state.position;
        }
      }

      throwError(state, 'unexpected end of the stream within a single quoted scalar');
    }

    function readDoubleQuotedScalar(state, nodeIndent) {
      var captureStart, captureEnd, hexLength, hexResult, tmp, ch;
      ch = state.input.charCodeAt(state.position);

      if (ch !== 0x22
      /* " */
      ) {
          return false;
        }

      state.kind = 'scalar';
      state.result = '';
      state.position++;
      captureStart = captureEnd = state.position;

      while ((ch = state.input.charCodeAt(state.position)) !== 0) {
        if (ch === 0x22
        /* " */
        ) {
            captureSegment(state, captureStart, state.position, true);
            state.position++;
            return true;
          } else if (ch === 0x5C
        /* \ */
        ) {
            captureSegment(state, captureStart, state.position, true);
            ch = state.input.charCodeAt(++state.position);

            if (is_EOL(ch)) {
              skipSeparationSpace(state, false, nodeIndent); // TODO: rework to inline fn with no type cast?
            } else if (ch < 256 && simpleEscapeCheck[ch]) {
              state.result += simpleEscapeMap[ch];
              state.position++;
            } else if ((tmp = escapedHexLen(ch)) > 0) {
              hexLength = tmp;
              hexResult = 0;

              for (; hexLength > 0; hexLength--) {
                ch = state.input.charCodeAt(++state.position);

                if ((tmp = fromHexCode(ch)) >= 0) {
                  hexResult = (hexResult << 4) + tmp;
                } else {
                  throwError(state, 'expected hexadecimal character');
                }
              }

              state.result += charFromCodepoint(hexResult);
              state.position++;
            } else {
              throwError(state, 'unknown escape sequence');
            }

            captureStart = captureEnd = state.position;
          } else if (is_EOL(ch)) {
          captureSegment(state, captureStart, captureEnd, true);
          writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
          captureStart = captureEnd = state.position;
        } else if (state.position === state.lineStart && testDocumentSeparator(state)) {
          throwError(state, 'unexpected end of the document within a double quoted scalar');
        } else {
          state.position++;
          captureEnd = state.position;
        }
      }

      throwError(state, 'unexpected end of the stream within a double quoted scalar');
    }

    function readFlowCollection(state, nodeIndent) {
      var readNext = true,
          _line,
          _tag = state.tag,
          _result,
          _anchor = state.anchor,
          following,
          terminator,
          isPair,
          isExplicitPair,
          isMapping,
          overridableKeys = {},
          keyNode,
          keyTag,
          valueNode,
          ch;

      ch = state.input.charCodeAt(state.position);

      if (ch === 0x5B
      /* [ */
      ) {
          terminator = 0x5D;
          /* ] */

          isMapping = false;
          _result = [];
        } else if (ch === 0x7B
      /* { */
      ) {
          terminator = 0x7D;
          /* } */

          isMapping = true;
          _result = {};
        } else {
        return false;
      }

      if (state.anchor !== null) {
        state.anchorMap[state.anchor] = _result;
      }

      ch = state.input.charCodeAt(++state.position);

      while (ch !== 0) {
        skipSeparationSpace(state, true, nodeIndent);
        ch = state.input.charCodeAt(state.position);

        if (ch === terminator) {
          state.position++;
          state.tag = _tag;
          state.anchor = _anchor;
          state.kind = isMapping ? 'mapping' : 'sequence';
          state.result = _result;
          return true;
        } else if (!readNext) {
          throwError(state, 'missed comma between flow collection entries');
        }

        keyTag = keyNode = valueNode = null;
        isPair = isExplicitPair = false;

        if (ch === 0x3F
        /* ? */
        ) {
            following = state.input.charCodeAt(state.position + 1);

            if (is_WS_OR_EOL(following)) {
              isPair = isExplicitPair = true;
              state.position++;
              skipSeparationSpace(state, true, nodeIndent);
            }
          }

        _line = state.line;
        composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
        keyTag = state.tag;
        keyNode = state.result;
        skipSeparationSpace(state, true, nodeIndent);
        ch = state.input.charCodeAt(state.position);

        if ((isExplicitPair || state.line === _line) && ch === 0x3A
        /* : */
        ) {
            isPair = true;
            ch = state.input.charCodeAt(++state.position);
            skipSeparationSpace(state, true, nodeIndent);
            composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
            valueNode = state.result;
          }

        if (isMapping) {
          storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode);
        } else if (isPair) {
          _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode));
        } else {
          _result.push(keyNode);
        }

        skipSeparationSpace(state, true, nodeIndent);
        ch = state.input.charCodeAt(state.position);

        if (ch === 0x2C
        /* , */
        ) {
            readNext = true;
            ch = state.input.charCodeAt(++state.position);
          } else {
          readNext = false;
        }
      }

      throwError(state, 'unexpected end of the stream within a flow collection');
    }

    function readBlockScalar(state, nodeIndent) {
      var captureStart,
          folding,
          chomping = CHOMPING_CLIP,
          didReadContent = false,
          detectedIndent = false,
          textIndent = nodeIndent,
          emptyLines = 0,
          atMoreIndented = false,
          tmp,
          ch;
      ch = state.input.charCodeAt(state.position);

      if (ch === 0x7C
      /* | */
      ) {
          folding = false;
        } else if (ch === 0x3E
      /* > */
      ) {
          folding = true;
        } else {
        return false;
      }

      state.kind = 'scalar';
      state.result = '';

      while (ch !== 0) {
        ch = state.input.charCodeAt(++state.position);

        if (ch === 0x2B
        /* + */
        || ch === 0x2D
        /* - */
        ) {
            if (CHOMPING_CLIP === chomping) {
              chomping = ch === 0x2B
              /* + */
              ? CHOMPING_KEEP : CHOMPING_STRIP;
            } else {
              throwError(state, 'repeat of a chomping mode identifier');
            }
          } else if ((tmp = fromDecimalCode(ch)) >= 0) {
          if (tmp === 0) {
            throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one');
          } else if (!detectedIndent) {
            textIndent = nodeIndent + tmp - 1;
            detectedIndent = true;
          } else {
            throwError(state, 'repeat of an indentation width identifier');
          }
        } else {
          break;
        }
      }

      if (is_WHITE_SPACE(ch)) {
        do {
          ch = state.input.charCodeAt(++state.position);
        } while (is_WHITE_SPACE(ch));

        if (ch === 0x23
        /* # */
        ) {
            do {
              ch = state.input.charCodeAt(++state.position);
            } while (!is_EOL(ch) && ch !== 0);
          }
      }

      while (ch !== 0) {
        readLineBreak(state);
        state.lineIndent = 0;
        ch = state.input.charCodeAt(state.position);

        while ((!detectedIndent || state.lineIndent < textIndent) && ch === 0x20
        /* Space */
        ) {
          state.lineIndent++;
          ch = state.input.charCodeAt(++state.position);
        }

        if (!detectedIndent && state.lineIndent > textIndent) {
          textIndent = state.lineIndent;
        }

        if (is_EOL(ch)) {
          emptyLines++;
          continue;
        } // End of the scalar.


        if (state.lineIndent < textIndent) {
          // Perform the chomping.
          if (chomping === CHOMPING_KEEP) {
            state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines);
          } else if (chomping === CHOMPING_CLIP) {
            if (didReadContent) {
              // i.e. only if the scalar is not empty.
              state.result += '\n';
            }
          } // Break this `while` cycle and go to the funciton's epilogue.


          break;
        } // Folded style: use fancy rules to handle line breaks.


        if (folding) {
          // Lines starting with white space characters (more-indented lines) are not folded.
          if (is_WHITE_SPACE(ch)) {
            atMoreIndented = true; // except for the first content line (cf. Example 8.1)

            state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); // End of more-indented block.
          } else if (atMoreIndented) {
            atMoreIndented = false;
            state.result += common.repeat('\n', emptyLines + 1); // Just one line break - perceive as the same line.
          } else if (emptyLines === 0) {
            if (didReadContent) {
              // i.e. only if we have already read some scalar content.
              state.result += ' ';
            } // Several line breaks - perceive as different lines.

          } else {
            state.result += common.repeat('\n', emptyLines);
          } // Literal style: just add exact number of line breaks between content lines.

        } else {
          // Keep all line breaks except the header line break.
          state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines);
        }

        didReadContent = true;
        detectedIndent = true;
        emptyLines = 0;
        captureStart = state.position;

        while (!is_EOL(ch) && ch !== 0) {
          ch = state.input.charCodeAt(++state.position);
        }

        captureSegment(state, captureStart, state.position, false);
      }

      return true;
    }

    function readBlockSequence(state, nodeIndent) {
      var _line,
          _tag = state.tag,
          _anchor = state.anchor,
          _result = [],
          following,
          detected = false,
          ch;

      if (state.anchor !== null) {
        state.anchorMap[state.anchor] = _result;
      }

      ch = state.input.charCodeAt(state.position);

      while (ch !== 0) {
        if (ch !== 0x2D
        /* - */
        ) {
            break;
          }

        following = state.input.charCodeAt(state.position + 1);

        if (!is_WS_OR_EOL(following)) {
          break;
        }

        detected = true;
        state.position++;

        if (skipSeparationSpace(state, true, -1)) {
          if (state.lineIndent <= nodeIndent) {
            _result.push(null);

            ch = state.input.charCodeAt(state.position);
            continue;
          }
        }

        _line = state.line;
        composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true);

        _result.push(state.result);

        skipSeparationSpace(state, true, -1);
        ch = state.input.charCodeAt(state.position);

        if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) {
          throwError(state, 'bad indentation of a sequence entry');
        } else if (state.lineIndent < nodeIndent) {
          break;
        }
      }

      if (detected) {
        state.tag = _tag;
        state.anchor = _anchor;
        state.kind = 'sequence';
        state.result = _result;
        return true;
      }

      return false;
    }

    function readBlockMapping(state, nodeIndent, flowIndent) {
      var following,
          allowCompact,
          _line,
          _pos,
          _tag = state.tag,
          _anchor = state.anchor,
          _result = {},
          overridableKeys = {},
          keyTag = null,
          keyNode = null,
          valueNode = null,
          atExplicitKey = false,
          detected = false,
          ch;

      if (state.anchor !== null) {
        state.anchorMap[state.anchor] = _result;
      }

      ch = state.input.charCodeAt(state.position);

      while (ch !== 0) {
        following = state.input.charCodeAt(state.position + 1);
        _line = state.line; // Save the current line.

        _pos = state.position; //
        // Explicit notation case. There are two separate blocks:
        // first for the key (denoted by "?") and second for the value (denoted by ":")
        //

        if ((ch === 0x3F
        /* ? */
        || ch === 0x3A
        /* : */
        ) && is_WS_OR_EOL(following)) {
          if (ch === 0x3F
          /* ? */
          ) {
              if (atExplicitKey) {
                storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
                keyTag = keyNode = valueNode = null;
              }

              detected = true;
              atExplicitKey = true;
              allowCompact = true;
            } else if (atExplicitKey) {
            // i.e. 0x3A/* : */ === character after the explicit key.
            atExplicitKey = false;
            allowCompact = true;
          } else {
            throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line');
          }

          state.position += 1;
          ch = following; //
          // Implicit notation case. Flow-style node as the key first, then ":", and the value.
          //
        } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {
          if (state.line === _line) {
            ch = state.input.charCodeAt(state.position);

            while (is_WHITE_SPACE(ch)) {
              ch = state.input.charCodeAt(++state.position);
            }

            if (ch === 0x3A
            /* : */
            ) {
                ch = state.input.charCodeAt(++state.position);

                if (!is_WS_OR_EOL(ch)) {
                  throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping');
                }

                if (atExplicitKey) {
                  storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
                  keyTag = keyNode = valueNode = null;
                }

                detected = true;
                atExplicitKey = false;
                allowCompact = false;
                keyTag = state.tag;
                keyNode = state.result;
              } else if (detected) {
              throwError(state, 'can not read an implicit mapping pair; a colon is missed');
            } else {
              state.tag = _tag;
              state.anchor = _anchor;
              return true; // Keep the result of `composeNode`.
            }
          } else if (detected) {
            throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key');
          } else {
            state.tag = _tag;
            state.anchor = _anchor;
            return true; // Keep the result of `composeNode`.
          }
        } else {
            break; // Reading is done. Go to the epilogue.
          } //
        // Common reading code for both explicit and implicit notations.
        //


        if (state.line === _line || state.lineIndent > nodeIndent) {
          if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {
            if (atExplicitKey) {
              keyNode = state.result;
            } else {
              valueNode = state.result;
            }
          }

          if (!atExplicitKey) {
            storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _pos);
            keyTag = keyNode = valueNode = null;
          }

          skipSeparationSpace(state, true, -1);
          ch = state.input.charCodeAt(state.position);
        }

        if (state.lineIndent > nodeIndent && ch !== 0) {
          throwError(state, 'bad indentation of a mapping entry');
        } else if (state.lineIndent < nodeIndent) {
          break;
        }
      } //
      // Epilogue.
      //
      // Special case: last mapping's node contains only the key in explicit notation.


      if (atExplicitKey) {
        storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
      } // Expose the resulting mapping.


      if (detected) {
        state.tag = _tag;
        state.anchor = _anchor;
        state.kind = 'mapping';
        state.result = _result;
      }

      return detected;
    }

    function readTagProperty(state) {
      var _position,
          isVerbatim = false,
          isNamed = false,
          tagHandle,
          tagName,
          ch;

      ch = state.input.charCodeAt(state.position);
      if (ch !== 0x21
      /* ! */
      ) return false;

      if (state.tag !== null) {
        throwError(state, 'duplication of a tag property');
      }

      ch = state.input.charCodeAt(++state.position);

      if (ch === 0x3C
      /* < */
      ) {
          isVerbatim = true;
          ch = state.input.charCodeAt(++state.position);
        } else if (ch === 0x21
      /* ! */
      ) {
          isNamed = true;
          tagHandle = '!!';
          ch = state.input.charCodeAt(++state.position);
        } else {
        tagHandle = '!';
      }

      _position = state.position;

      if (isVerbatim) {
        do {
          ch = state.input.charCodeAt(++state.position);
        } while (ch !== 0 && ch !== 0x3E
        /* > */
        );

        if (state.position < state.length) {
          tagName = state.input.slice(_position, state.position);
          ch = state.input.charCodeAt(++state.position);
        } else {
          throwError(state, 'unexpected end of the stream within a verbatim tag');
        }
      } else {
        while (ch !== 0 && !is_WS_OR_EOL(ch)) {
          if (ch === 0x21
          /* ! */
          ) {
              if (!isNamed) {
                tagHandle = state.input.slice(_position - 1, state.position + 1);

                if (!PATTERN_TAG_HANDLE.test(tagHandle)) {
                  throwError(state, 'named tag handle cannot contain such characters');
                }

                isNamed = true;
                _position = state.position + 1;
              } else {
                throwError(state, 'tag suffix cannot contain exclamation marks');
              }
            }

          ch = state.input.charCodeAt(++state.position);
        }

        tagName = state.input.slice(_position, state.position);

        if (PATTERN_FLOW_INDICATORS.test(tagName)) {
          throwError(state, 'tag suffix cannot contain flow indicator characters');
        }
      }

      if (tagName && !PATTERN_TAG_URI.test(tagName)) {
        throwError(state, 'tag name cannot contain such characters: ' + tagName);
      }

      if (isVerbatim) {
        state.tag = tagName;
      } else if (_hasOwnProperty$2.call(state.tagMap, tagHandle)) {
        state.tag = state.tagMap[tagHandle] + tagName;
      } else if (tagHandle === '!') {
        state.tag = '!' + tagName;
      } else if (tagHandle === '!!') {
        state.tag = 'tag:yaml.org,2002:' + tagName;
      } else {
        throwError(state, 'undeclared tag handle "' + tagHandle + '"');
      }

      return true;
    }

    function readAnchorProperty(state) {
      var _position, ch;

      ch = state.input.charCodeAt(state.position);
      if (ch !== 0x26
      /* & */
      ) return false;

      if (state.anchor !== null) {
        throwError(state, 'duplication of an anchor property');
      }

      ch = state.input.charCodeAt(++state.position);
      _position = state.position;

      while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
        ch = state.input.charCodeAt(++state.position);
      }

      if (state.position === _position) {
        throwError(state, 'name of an anchor node must contain at least one character');
      }

      state.anchor = state.input.slice(_position, state.position);
      return true;
    }

    function readAlias(state) {
      var _position, alias, ch;

      ch = state.input.charCodeAt(state.position);
      if (ch !== 0x2A
      /* * */
      ) return false;
      ch = state.input.charCodeAt(++state.position);
      _position = state.position;

      while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
        ch = state.input.charCodeAt(++state.position);
      }

      if (state.position === _position) {
        throwError(state, 'name of an alias node must contain at least one character');
      }

      alias = state.input.slice(_position, state.position);

      if (!_hasOwnProperty$2.call(state.anchorMap, alias)) {
        throwError(state, 'unidentified alias "' + alias + '"');
      }

      state.result = state.anchorMap[alias];
      skipSeparationSpace(state, true, -1);
      return true;
    }

    function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) {
      var allowBlockStyles,
          allowBlockScalars,
          allowBlockCollections,
          indentStatus = 1,
          // 1: this>parent, 0: this=parent, -1: this<parent
      atNewLine = false,
          hasContent = false,
          typeIndex,
          typeQuantity,
          type,
          flowIndent,
          blockIndent;

      if (state.listener !== null) {
        state.listener('open', state);
      }

      state.tag = null;
      state.anchor = null;
      state.kind = null;
      state.result = null;
      allowBlockStyles = allowBlockScalars = allowBlockCollections = CONTEXT_BLOCK_OUT === nodeContext || CONTEXT_BLOCK_IN === nodeContext;

      if (allowToSeek) {
        if (skipSeparationSpace(state, true, -1)) {
          atNewLine = true;

          if (state.lineIndent > parentIndent) {
            indentStatus = 1;
          } else if (state.lineIndent === parentIndent) {
            indentStatus = 0;
          } else if (state.lineIndent < parentIndent) {
            indentStatus = -1;
          }
        }
      }

      if (indentStatus === 1) {
        while (readTagProperty(state) || readAnchorProperty(state)) {
          if (skipSeparationSpace(state, true, -1)) {
            atNewLine = true;
            allowBlockCollections = allowBlockStyles;

            if (state.lineIndent > parentIndent) {
              indentStatus = 1;
            } else if (state.lineIndent === parentIndent) {
              indentStatus = 0;
            } else if (state.lineIndent < parentIndent) {
              indentStatus = -1;
            }
          } else {
            allowBlockCollections = false;
          }
        }
      }

      if (allowBlockCollections) {
        allowBlockCollections = atNewLine || allowCompact;
      }

      if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) {
        if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {
          flowIndent = parentIndent;
        } else {
          flowIndent = parentIndent + 1;
        }

        blockIndent = state.position - state.lineStart;

        if (indentStatus === 1) {
          if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) {
            hasContent = true;
          } else {
            if (allowBlockScalars && readBlockScalar(state, flowIndent) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) {
              hasContent = true;
            } else if (readAlias(state)) {
              hasContent = true;

              if (state.tag !== null || state.anchor !== null) {
                throwError(state, 'alias node should not have any properties');
              }
            } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {
              hasContent = true;

              if (state.tag === null) {
                state.tag = '?';
              }
            }

            if (state.anchor !== null) {
              state.anchorMap[state.anchor] = state.result;
            }
          }
        } else if (indentStatus === 0) {
          // Special case: block sequences are allowed to have same indentation level as the parent.
          // http://www.yaml.org/spec/1.2/spec.html#id2799784
          hasContent = allowBlockCollections && readBlockSequence(state, blockIndent);
        }
      }

      if (state.tag !== null && state.tag !== '!') {
        if (state.tag === '?') {
          // Implicit resolving is not allowed for non-scalar types, and '?'
          // non-specific tag is only automatically assigned to plain scalars.
          //
          // We only need to check kind conformity in case user explicitly assigns '?'
          // tag, for example like this: "!<?> [0]"
          //
          if (state.result !== null && state.kind !== 'scalar') {
            throwError(state, 'unacceptable node kind for !<?> tag; it should be "scalar", not "' + state.kind + '"');
          }

          for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {
            type = state.implicitTypes[typeIndex];

            if (type.resolve(state.result)) {
              // `state.result` updated in resolver if matched
              state.result = type.construct(state.result);
              state.tag = type.tag;

              if (state.anchor !== null) {
                state.anchorMap[state.anchor] = state.result;
              }

              break;
            }
          }
        } else if (_hasOwnProperty$2.call(state.typeMap[state.kind || 'fallback'], state.tag)) {
          type = state.typeMap[state.kind || 'fallback'][state.tag];

          if (state.result !== null && type.kind !== state.kind) {
            throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"');
          }

          if (!type.resolve(state.result)) {
            // `state.result` updated in resolver if matched
            throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag');
          } else {
            state.result = type.construct(state.result);

            if (state.anchor !== null) {
              state.anchorMap[state.anchor] = state.result;
            }
          }
        } else {
          throwError(state, 'unknown tag !<' + state.tag + '>');
        }
      }

      if (state.listener !== null) {
        state.listener('close', state);
      }

      return state.tag !== null || state.anchor !== null || hasContent;
    }

    function readDocument(state) {
      var documentStart = state.position,
          _position,
          directiveName,
          directiveArgs,
          hasDirectives = false,
          ch;

      state.version = null;
      state.checkLineBreaks = state.legacy;
      state.tagMap = {};
      state.anchorMap = {};

      while ((ch = state.input.charCodeAt(state.position)) !== 0) {
        skipSeparationSpace(state, true, -1);
        ch = state.input.charCodeAt(state.position);

        if (state.lineIndent > 0 || ch !== 0x25
        /* % */
        ) {
            break;
          }

        hasDirectives = true;
        ch = state.input.charCodeAt(++state.position);
        _position = state.position;

        while (ch !== 0 && !is_WS_OR_EOL(ch)) {
          ch = state.input.charCodeAt(++state.position);
        }

        directiveName = state.input.slice(_position, state.position);
        directiveArgs = [];

        if (directiveName.length < 1) {
          throwError(state, 'directive name must not be less than one character in length');
        }

        while (ch !== 0) {
          while (is_WHITE_SPACE(ch)) {
            ch = state.input.charCodeAt(++state.position);
          }

          if (ch === 0x23
          /* # */
          ) {
              do {
                ch = state.input.charCodeAt(++state.position);
              } while (ch !== 0 && !is_EOL(ch));

              break;
            }

          if (is_EOL(ch)) break;
          _position = state.position;

          while (ch !== 0 && !is_WS_OR_EOL(ch)) {
            ch = state.input.charCodeAt(++state.position);
          }

          directiveArgs.push(state.input.slice(_position, state.position));
        }

        if (ch !== 0) readLineBreak(state);

        if (_hasOwnProperty$2.call(directiveHandlers, directiveName)) {
          directiveHandlers[directiveName](state, directiveName, directiveArgs);
        } else {
          throwWarning(state, 'unknown document directive "' + directiveName + '"');
        }
      }

      skipSeparationSpace(state, true, -1);

      if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 0x2D
      /* - */
      && state.input.charCodeAt(state.position + 1) === 0x2D
      /* - */
      && state.input.charCodeAt(state.position + 2) === 0x2D
      /* - */
      ) {
          state.position += 3;
          skipSeparationSpace(state, true, -1);
        } else if (hasDirectives) {
        throwError(state, 'directives end mark is expected');
      }

      composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true);
      skipSeparationSpace(state, true, -1);

      if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {
        throwWarning(state, 'non-ASCII line breaks are interpreted as content');
      }

      state.documents.push(state.result);

      if (state.position === state.lineStart && testDocumentSeparator(state)) {
        if (state.input.charCodeAt(state.position) === 0x2E
        /* . */
        ) {
            state.position += 3;
            skipSeparationSpace(state, true, -1);
          }

        return;
      }

      if (state.position < state.length - 1) {
        throwError(state, 'end of the stream or a document separator is expected');
      } else {
        return;
      }
    }

    function loadDocuments(input, options) {
      input = String(input);
      options = options || {};

      if (input.length !== 0) {
        // Add tailing `\n` if not exists
        if (input.charCodeAt(input.length - 1) !== 0x0A
        /* LF */
        && input.charCodeAt(input.length - 1) !== 0x0D
        /* CR */
        ) {
            input += '\n';
          } // Strip BOM


        if (input.charCodeAt(0) === 0xFEFF) {
          input = input.slice(1);
        }
      }

      var state = new State(input, options);
      var nullpos = input.indexOf('\0');

      if (nullpos !== -1) {
        state.position = nullpos;
        throwError(state, 'null byte is not allowed in input');
      } // Use 0 as string terminator. That significantly simplifies bounds check.


      state.input += '\0';

      while (state.input.charCodeAt(state.position) === 0x20
      /* Space */
      ) {
        state.lineIndent += 1;
        state.position += 1;
      }

      while (state.position < state.length - 1) {
        readDocument(state);
      }

      return state.documents;
    }

    function loadAll(input, iterator, options) {
      if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') {
        options = iterator;
        iterator = null;
      }

      var documents = loadDocuments(input, options);

      if (typeof iterator !== 'function') {
        return documents;
      }

      for (var index = 0, length = documents.length; index < length; index += 1) {
        iterator(documents[index]);
      }
    }

    function load(input, options) {
      var documents = loadDocuments(input, options);

      if (documents.length === 0) {
        /*eslint-disable no-undefined*/
        return undefined;
      } else if (documents.length === 1) {
        return documents[0];
      }

      throw new exception('expected a single document in the stream, but found more');
    }

    function safeLoadAll(input, iterator, options) {
      if (typeof iterator === 'object' && iterator !== null && typeof options === 'undefined') {
        options = iterator;
        iterator = null;
      }

      return loadAll(input, iterator, common.extend({
        schema: default_safe
      }, options));
    }

    function safeLoad(input, options) {
      return load(input, common.extend({
        schema: default_safe
      }, options));
    }

    var loadAll_1 = loadAll;
    var load_1 = load;
    var safeLoadAll_1 = safeLoadAll;
    var safeLoad_1 = safeLoad;
    var loader = {
      loadAll: loadAll_1,
      load: load_1,
      safeLoadAll: safeLoadAll_1,
      safeLoad: safeLoad_1
    };

    /*eslint-disable no-use-before-define*/


    var _toString$2 = Object.prototype.toString;
    var _hasOwnProperty$3 = Object.prototype.hasOwnProperty;
    var CHAR_TAB = 0x09;
    /* Tab */

    var CHAR_LINE_FEED = 0x0A;
    /* LF */

    var CHAR_CARRIAGE_RETURN = 0x0D;
    /* CR */

    var CHAR_SPACE = 0x20;
    /* Space */

    var CHAR_EXCLAMATION = 0x21;
    /* ! */

    var CHAR_DOUBLE_QUOTE = 0x22;
    /* " */

    var CHAR_SHARP = 0x23;
    /* # */

    var CHAR_PERCENT = 0x25;
    /* % */

    var CHAR_AMPERSAND = 0x26;
    /* & */

    var CHAR_SINGLE_QUOTE = 0x27;
    /* ' */

    var CHAR_ASTERISK = 0x2A;
    /* * */

    var CHAR_COMMA = 0x2C;
    /* , */

    var CHAR_MINUS = 0x2D;
    /* - */

    var CHAR_COLON = 0x3A;
    /* : */

    var CHAR_EQUALS = 0x3D;
    /* = */

    var CHAR_GREATER_THAN = 0x3E;
    /* > */

    var CHAR_QUESTION = 0x3F;
    /* ? */

    var CHAR_COMMERCIAL_AT = 0x40;
    /* @ */

    var CHAR_LEFT_SQUARE_BRACKET = 0x5B;
    /* [ */

    var CHAR_RIGHT_SQUARE_BRACKET = 0x5D;
    /* ] */

    var CHAR_GRAVE_ACCENT = 0x60;
    /* ` */

    var CHAR_LEFT_CURLY_BRACKET = 0x7B;
    /* { */

    var CHAR_VERTICAL_LINE = 0x7C;
    /* | */

    var CHAR_RIGHT_CURLY_BRACKET = 0x7D;
    /* } */

    var ESCAPE_SEQUENCES = {};
    ESCAPE_SEQUENCES[0x00] = '\\0';
    ESCAPE_SEQUENCES[0x07] = '\\a';
    ESCAPE_SEQUENCES[0x08] = '\\b';
    ESCAPE_SEQUENCES[0x09] = '\\t';
    ESCAPE_SEQUENCES[0x0A] = '\\n';
    ESCAPE_SEQUENCES[0x0B] = '\\v';
    ESCAPE_SEQUENCES[0x0C] = '\\f';
    ESCAPE_SEQUENCES[0x0D] = '\\r';
    ESCAPE_SEQUENCES[0x1B] = '\\e';
    ESCAPE_SEQUENCES[0x22] = '\\"';
    ESCAPE_SEQUENCES[0x5C] = '\\\\';
    ESCAPE_SEQUENCES[0x85] = '\\N';
    ESCAPE_SEQUENCES[0xA0] = '\\_';
    ESCAPE_SEQUENCES[0x2028] = '\\L';
    ESCAPE_SEQUENCES[0x2029] = '\\P';
    var DEPRECATED_BOOLEANS_SYNTAX = ['y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'];

    function compileStyleMap(schema, map) {
      var result, keys, index, length, tag, style, type;
      if (map === null) return {};
      result = {};
      keys = Object.keys(map);

      for (index = 0, length = keys.length; index < length; index += 1) {
        tag = keys[index];
        style = String(map[tag]);

        if (tag.slice(0, 2) === '!!') {
          tag = 'tag:yaml.org,2002:' + tag.slice(2);
        }

        type = schema.compiledTypeMap['fallback'][tag];

        if (type && _hasOwnProperty$3.call(type.styleAliases, style)) {
          style = type.styleAliases[style];
        }

        result[tag] = style;
      }

      return result;
    }

    function encodeHex(character) {
      var string, handle, length;
      string = character.toString(16).toUpperCase();

      if (character <= 0xFF) {
        handle = 'x';
        length = 2;
      } else if (character <= 0xFFFF) {
        handle = 'u';
        length = 4;
      } else if (character <= 0xFFFFFFFF) {
        handle = 'U';
        length = 8;
      } else {
        throw new exception('code point within a string may not be greater than 0xFFFFFFFF');
      }

      return '\\' + handle + common.repeat('0', length - string.length) + string;
    }

    function State$1(options) {
      this.schema = options['schema'] || default_full;
      this.indent = Math.max(1, options['indent'] || 2);
      this.noArrayIndent = options['noArrayIndent'] || false;
      this.skipInvalid = options['skipInvalid'] || false;
      this.flowLevel = common.isNothing(options['flowLevel']) ? -1 : options['flowLevel'];
      this.styleMap = compileStyleMap(this.schema, options['styles'] || null);
      this.sortKeys = options['sortKeys'] || false;
      this.lineWidth = options['lineWidth'] || 80;
      this.noRefs = options['noRefs'] || false;
      this.noCompatMode = options['noCompatMode'] || false;
      this.condenseFlow = options['condenseFlow'] || false;
      this.implicitTypes = this.schema.compiledImplicit;
      this.explicitTypes = this.schema.compiledExplicit;
      this.tag = null;
      this.result = '';
      this.duplicates = [];
      this.usedDuplicates = null;
    } // Indents every line in a string. Empty lines (\n only) are not indented.


    function indentString(string, spaces) {
      var ind = common.repeat(' ', spaces),
          position = 0,
          next = -1,
          result = '',
          line,
          length = string.length;

      while (position < length) {
        next = string.indexOf('\n', position);

        if (next === -1) {
          line = string.slice(position);
          position = length;
        } else {
          line = string.slice(position, next + 1);
          position = next + 1;
        }

        if (line.length && line !== '\n') result += ind;
        result += line;
      }

      return result;
    }

    function generateNextLine(state, level) {
      return '\n' + common.repeat(' ', state.indent * level);
    }

    function testImplicitResolving(state, str) {
      var index, length, type;

      for (index = 0, length = state.implicitTypes.length; index < length; index += 1) {
        type = state.implicitTypes[index];

        if (type.resolve(str)) {
          return true;
        }
      }

      return false;
    } // [33] s-white ::= s-space | s-tab


    function isWhitespace(c) {
      return c === CHAR_SPACE || c === CHAR_TAB;
    } // Returns true if the character can be printed without escaping.
    // From YAML 1.2: "any allowed characters known to be non-printable
    // should also be escaped. [However,] This isn’t mandatory"
    // Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029.


    function isPrintable(c) {
      return 0x00020 <= c && c <= 0x00007E || 0x000A1 <= c && c <= 0x00D7FF && c !== 0x2028 && c !== 0x2029 || 0x0E000 <= c && c <= 0x00FFFD && c !== 0xFEFF
      /* BOM */
      || 0x10000 <= c && c <= 0x10FFFF;
    } // [34] ns-char ::= nb-char - s-white
    // [27] nb-char ::= c-printable - b-char - c-byte-order-mark
    // [26] b-char  ::= b-line-feed | b-carriage-return
    // [24] b-line-feed       ::=     #xA    /* LF */
    // [25] b-carriage-return ::=     #xD    /* CR */
    // [3]  c-byte-order-mark ::=     #xFEFF


    function isNsChar(c) {
      return isPrintable(c) && !isWhitespace(c) // byte-order-mark
      && c !== 0xFEFF // b-char
      && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED;
    } // Simplified test for values allowed after the first character in plain style.


    function isPlainSafe(c, prev) {
      // Uses a subset of nb-char - c-flow-indicator - ":" - "#"
      // where nb-char ::= c-printable - b-char - c-byte-order-mark.
      return isPrintable(c) && c !== 0xFEFF // - c-flow-indicator
      && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET // - ":" - "#"
      // /* An ns-char preceding */ "#"
      && c !== CHAR_COLON && (c !== CHAR_SHARP || prev && isNsChar(prev));
    } // Simplified test for values allowed as the first character in plain style.


    function isPlainSafeFirst(c) {
      // Uses a subset of ns-char - c-indicator
      // where ns-char = nb-char - s-white.
      return isPrintable(c) && c !== 0xFEFF && !isWhitespace(c) // - s-white
      // - (c-indicator ::=
      // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”
      && c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"”
      && c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE // | “%” | “@” | “`”)
      && c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT;
    } // Determines whether block indentation indicator is required.


    function needIndentIndicator(string) {
      var leadingSpaceRe = /^\n* /;
      return leadingSpaceRe.test(string);
    }

    var STYLE_PLAIN = 1,
        STYLE_SINGLE = 2,
        STYLE_LITERAL = 3,
        STYLE_FOLDED = 4,
        STYLE_DOUBLE = 5; // Determines which scalar styles are possible and returns the preferred style.
    // lineWidth = -1 => no limit.
    // Pre-conditions: str.length > 0.
    // Post-conditions:
    //    STYLE_PLAIN or STYLE_SINGLE => no \n are in the string.
    //    STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1).
    //    STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1).

    function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) {
      var i;
      var char, prev_char;
      var hasLineBreak = false;
      var hasFoldableLine = false; // only checked if shouldTrackWidth

      var shouldTrackWidth = lineWidth !== -1;
      var previousLineBreak = -1; // count the first line correctly

      var plain = isPlainSafeFirst(string.charCodeAt(0)) && !isWhitespace(string.charCodeAt(string.length - 1));

      if (singleLineOnly) {
        // Case: no block styles.
        // Check for disallowed characters to rule out plain and single.
        for (i = 0; i < string.length; i++) {
          char = string.charCodeAt(i);

          if (!isPrintable(char)) {
            return STYLE_DOUBLE;
          }

          prev_char = i > 0 ? string.charCodeAt(i - 1) : null;
          plain = plain && isPlainSafe(char, prev_char);
        }
      } else {
        // Case: block styles permitted.
        for (i = 0; i < string.length; i++) {
          char = string.charCodeAt(i);

          if (char === CHAR_LINE_FEED) {
            hasLineBreak = true; // Check if any line can be folded.

            if (shouldTrackWidth) {
              hasFoldableLine = hasFoldableLine || // Foldable line = too long, and not more-indented.
              i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' ';
              previousLineBreak = i;
            }
          } else if (!isPrintable(char)) {
            return STYLE_DOUBLE;
          }

          prev_char = i > 0 ? string.charCodeAt(i - 1) : null;
          plain = plain && isPlainSafe(char, prev_char);
        } // in case the end is missing a \n


        hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' ';
      } // Although every style can represent \n without escaping, prefer block styles
      // for multiline, since they're more readable and they don't add empty lines.
      // Also prefer folding a super-long line.


      if (!hasLineBreak && !hasFoldableLine) {
        // Strings interpretable as another type have to be quoted;
        // e.g. the string 'true' vs. the boolean true.
        return plain && !testAmbiguousType(string) ? STYLE_PLAIN : STYLE_SINGLE;
      } // Edge case: block indentation indicator can only have one digit.


      if (indentPerLevel > 9 && needIndentIndicator(string)) {
        return STYLE_DOUBLE;
      } // At this point we know block styles are valid.
      // Prefer literal style unless we want to fold.


      return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL;
    } // Note: line breaking/folding is implemented for only the folded style.
    // NB. We drop the last trailing newline (if any) of a returned block scalar
    //  since the dumper adds its own newline. This always works:
    //    • No ending newline => unaffected; already using strip "-" chomping.
    //    • Ending newline    => removed then restored.
    //  Importantly, this keeps the "+" chomp indicator from gaining an extra line.


    function writeScalar(state, string, level, iskey) {
      state.dump = function () {
        if (string.length === 0) {
          return "''";
        }

        if (!state.noCompatMode && DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) {
          return "'" + string + "'";
        }

        var indent = state.indent * Math.max(1, level); // no 0-indent scalars
        // As indentation gets deeper, let the width decrease monotonically
        // to the lower bound min(state.lineWidth, 40).
        // Note that this implies
        //  state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound.
        //  state.lineWidth > 40 + state.indent: width decreases until the lower bound.
        // This behaves better than a constant minimum width which disallows narrower options,
        // or an indent threshold which causes the width to suddenly increase.

        var lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); // Without knowing if keys are implicit/explicit, assume implicit for safety.

        var singleLineOnly = iskey // No block styles in flow mode.
        || state.flowLevel > -1 && level >= state.flowLevel;

        function testAmbiguity(string) {
          return testImplicitResolving(state, string);
        }

        switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) {
          case STYLE_PLAIN:
            return string;

          case STYLE_SINGLE:
            return "'" + string.replace(/'/g, "''") + "'";

          case STYLE_LITERAL:
            return '|' + blockHeader(string, state.indent) + dropEndingNewline(indentString(string, indent));

          case STYLE_FOLDED:
            return '>' + blockHeader(string, state.indent) + dropEndingNewline(indentString(foldString(string, lineWidth), indent));

          case STYLE_DOUBLE:
            return '"' + escapeString(string) + '"';

          default:
            throw new exception('impossible error: invalid scalar style');
        }
      }();
    } // Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9.


    function blockHeader(string, indentPerLevel) {
      var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; // note the special case: the string '\n' counts as a "trailing" empty line.

      var clip = string[string.length - 1] === '\n';
      var keep = clip && (string[string.length - 2] === '\n' || string === '\n');
      var chomp = keep ? '+' : clip ? '' : '-';
      return indentIndicator + chomp + '\n';
    } // (See the note for writeScalar.)


    function dropEndingNewline(string) {
      return string[string.length - 1] === '\n' ? string.slice(0, -1) : string;
    } // Note: a long line without a suitable break point will exceed the width limit.
    // Pre-conditions: every char in str isPrintable, str.length > 0, width > 0.


    function foldString(string, width) {
      // In folded style, $k$ consecutive newlines output as $k+1$ newlines—
      // unless they're before or after a more-indented line, or at the very
      // beginning or end, in which case $k$ maps to $k$.
      // Therefore, parse each chunk as newline(s) followed by a content line.
      var lineRe = /(\n+)([^\n]*)/g; // first line (possibly an empty line)

      var result = function () {
        var nextLF = string.indexOf('\n');
        nextLF = nextLF !== -1 ? nextLF : string.length;
        lineRe.lastIndex = nextLF;
        return foldLine(string.slice(0, nextLF), width);
      }(); // If we haven't reached the first content line yet, don't add an extra \n.


      var prevMoreIndented = string[0] === '\n' || string[0] === ' ';
      var moreIndented; // rest of the lines

      var match;

      while (match = lineRe.exec(string)) {
        var prefix = match[1],
            line = match[2];
        moreIndented = line[0] === ' ';
        result += prefix + (!prevMoreIndented && !moreIndented && line !== '' ? '\n' : '') + foldLine(line, width);
        prevMoreIndented = moreIndented;
      }

      return result;
    } // Greedy line breaking.
    // Picks the longest line under the limit each time,
    // otherwise settles for the shortest line over the limit.
    // NB. More-indented lines *cannot* be folded, as that would add an extra \n.


    function foldLine(line, width) {
      if (line === '' || line[0] === ' ') return line; // Since a more-indented line adds a \n, breaks can't be followed by a space.

      var breakRe = / [^ ]/g; // note: the match index will always be <= length-2.

      var match; // start is an inclusive index. end, curr, and next are exclusive.

      var start = 0,
          end,
          curr = 0,
          next = 0;
      var result = ''; // Invariants: 0 <= start <= length-1.
      //   0 <= curr <= next <= max(0, length-2). curr - start <= width.
      // Inside the loop:
      //   A match implies length >= 2, so curr and next are <= length-2.

      while (match = breakRe.exec(line)) {
        next = match.index; // maintain invariant: curr - start <= width

        if (next - start > width) {
          end = curr > start ? curr : next; // derive end <= length-2

          result += '\n' + line.slice(start, end); // skip the space that was output as \n

          start = end + 1; // derive start <= length-1
        }

        curr = next;
      } // By the invariants, start <= length-1, so there is something left over.
      // It is either the whole string or a part starting from non-whitespace.


      result += '\n'; // Insert a break if the remainder is too long and there is a break available.

      if (line.length - start > width && curr > start) {
        result += line.slice(start, curr) + '\n' + line.slice(curr + 1);
      } else {
        result += line.slice(start);
      }

      return result.slice(1); // drop extra \n joiner
    } // Escapes a double-quoted string.


    function escapeString(string) {
      var result = '';
      var char, nextChar;
      var escapeSeq;

      for (var i = 0; i < string.length; i++) {
        char = string.charCodeAt(i); // Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates").

        if (char >= 0xD800 && char <= 0xDBFF
        /* high surrogate */
        ) {
            nextChar = string.charCodeAt(i + 1);

            if (nextChar >= 0xDC00 && nextChar <= 0xDFFF
            /* low surrogate */
            ) {
                // Combine the surrogate pair and store it escaped.
                result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000); // Advance index one extra since we already used that char here.

                i++;
                continue;
              }
          }

        escapeSeq = ESCAPE_SEQUENCES[char];
        result += !escapeSeq && isPrintable(char) ? string[i] : escapeSeq || encodeHex(char);
      }

      return result;
    }

    function writeFlowSequence(state, level, object) {
      var _result = '',
          _tag = state.tag,
          index,
          length;

      for (index = 0, length = object.length; index < length; index += 1) {
        // Write only valid elements.
        if (writeNode(state, level, object[index], false, false)) {
          if (index !== 0) _result += ',' + (!state.condenseFlow ? ' ' : '');
          _result += state.dump;
        }
      }

      state.tag = _tag;
      state.dump = '[' + _result + ']';
    }

    function writeBlockSequence(state, level, object, compact) {
      var _result = '',
          _tag = state.tag,
          index,
          length;

      for (index = 0, length = object.length; index < length; index += 1) {
        // Write only valid elements.
        if (writeNode(state, level + 1, object[index], true, true)) {
          if (!compact || index !== 0) {
            _result += generateNextLine(state, level);
          }

          if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
            _result += '-';
          } else {
            _result += '- ';
          }

          _result += state.dump;
        }
      }

      state.tag = _tag;
      state.dump = _result || '[]'; // Empty sequence if no valid values.
    }

    function writeFlowMapping(state, level, object) {
      var _result = '',
          _tag = state.tag,
          objectKeyList = Object.keys(object),
          index,
          length,
          objectKey,
          objectValue,
          pairBuffer;

      for (index = 0, length = objectKeyList.length; index < length; index += 1) {
        pairBuffer = '';
        if (index !== 0) pairBuffer += ', ';
        if (state.condenseFlow) pairBuffer += '"';
        objectKey = objectKeyList[index];
        objectValue = object[objectKey];

        if (!writeNode(state, level, objectKey, false, false)) {
          continue; // Skip this pair because of invalid key;
        }

        if (state.dump.length > 1024) pairBuffer += '? ';
        pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' ');

        if (!writeNode(state, level, objectValue, false, false)) {
          continue; // Skip this pair because of invalid value.
        }

        pairBuffer += state.dump; // Both key and value are valid.

        _result += pairBuffer;
      }

      state.tag = _tag;
      state.dump = '{' + _result + '}';
    }

    function writeBlockMapping(state, level, object, compact) {
      var _result = '',
          _tag = state.tag,
          objectKeyList = Object.keys(object),
          index,
          length,
          objectKey,
          objectValue,
          explicitPair,
          pairBuffer; // Allow sorting keys so that the output file is deterministic

      if (state.sortKeys === true) {
        // Default sorting
        objectKeyList.sort();
      } else if (typeof state.sortKeys === 'function') {
        // Custom sort function
        objectKeyList.sort(state.sortKeys);
      } else if (state.sortKeys) {
        // Something is wrong
        throw new exception('sortKeys must be a boolean or a function');
      }

      for (index = 0, length = objectKeyList.length; index < length; index += 1) {
        pairBuffer = '';

        if (!compact || index !== 0) {
          pairBuffer += generateNextLine(state, level);
        }

        objectKey = objectKeyList[index];
        objectValue = object[objectKey];

        if (!writeNode(state, level + 1, objectKey, true, true, true)) {
          continue; // Skip this pair because of invalid key.
        }

        explicitPair = state.tag !== null && state.tag !== '?' || state.dump && state.dump.length > 1024;

        if (explicitPair) {
          if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
            pairBuffer += '?';
          } else {
            pairBuffer += '? ';
          }
        }

        pairBuffer += state.dump;

        if (explicitPair) {
          pairBuffer += generateNextLine(state, level);
        }

        if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {
          continue; // Skip this pair because of invalid value.
        }

        if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
          pairBuffer += ':';
        } else {
          pairBuffer += ': ';
        }

        pairBuffer += state.dump; // Both key and value are valid.

        _result += pairBuffer;
      }

      state.tag = _tag;
      state.dump = _result || '{}'; // Empty mapping if no valid pairs.
    }

    function detectType(state, object, explicit) {
      var _result, typeList, index, length, type, style;

      typeList = explicit ? state.explicitTypes : state.implicitTypes;

      for (index = 0, length = typeList.length; index < length; index += 1) {
        type = typeList[index];

        if ((type.instanceOf || type.predicate) && (!type.instanceOf || typeof object === 'object' && object instanceof type.instanceOf) && (!type.predicate || type.predicate(object))) {
          state.tag = explicit ? type.tag : '?';

          if (type.represent) {
            style = state.styleMap[type.tag] || type.defaultStyle;

            if (_toString$2.call(type.represent) === '[object Function]') {
              _result = type.represent(object, style);
            } else if (_hasOwnProperty$3.call(type.represent, style)) {
              _result = type.represent[style](object, style);
            } else {
              throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
            }

            state.dump = _result;
          }

          return true;
        }
      }

      return false;
    } // Serializes `object` and writes it to global `result`.
    // Returns true on success, or false on invalid object.
    //


    function writeNode(state, level, object, block, compact, iskey) {
      state.tag = null;
      state.dump = object;

      if (!detectType(state, object, false)) {
        detectType(state, object, true);
      }

      var type = _toString$2.call(state.dump);

      if (block) {
        block = state.flowLevel < 0 || state.flowLevel > level;
      }

      var objectOrArray = type === '[object Object]' || type === '[object Array]',
          duplicateIndex,
          duplicate;

      if (objectOrArray) {
        duplicateIndex = state.duplicates.indexOf(object);
        duplicate = duplicateIndex !== -1;
      }

      if (state.tag !== null && state.tag !== '?' || duplicate || state.indent !== 2 && level > 0) {
        compact = false;
      }

      if (duplicate && state.usedDuplicates[duplicateIndex]) {
        state.dump = '*ref_' + duplicateIndex;
      } else {
        if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {
          state.usedDuplicates[duplicateIndex] = true;
        }

        if (type === '[object Object]') {
          if (block && Object.keys(state.dump).length !== 0) {
            writeBlockMapping(state, level, state.dump, compact);

            if (duplicate) {
              state.dump = '&ref_' + duplicateIndex + state.dump;
            }
          } else {
            writeFlowMapping(state, level, state.dump);

            if (duplicate) {
              state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
            }
          }
        } else if (type === '[object Array]') {
          var arrayLevel = state.noArrayIndent && level > 0 ? level - 1 : level;

          if (block && state.dump.length !== 0) {
            writeBlockSequence(state, arrayLevel, state.dump, compact);

            if (duplicate) {
              state.dump = '&ref_' + duplicateIndex + state.dump;
            }
          } else {
            writeFlowSequence(state, arrayLevel, state.dump);

            if (duplicate) {
              state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
            }
          }
        } else if (type === '[object String]') {
          if (state.tag !== '?') {
            writeScalar(state, state.dump, level, iskey);
          }
        } else {
          if (state.skipInvalid) return false;
          throw new exception('unacceptable kind of an object to dump ' + type);
        }

        if (state.tag !== null && state.tag !== '?') {
          state.dump = '!<' + state.tag + '> ' + state.dump;
        }
      }

      return true;
    }

    function getDuplicateReferences(object, state) {
      var objects = [],
          duplicatesIndexes = [],
          index,
          length;
      inspectNode(object, objects, duplicatesIndexes);

      for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) {
        state.duplicates.push(objects[duplicatesIndexes[index]]);
      }

      state.usedDuplicates = new Array(length);
    }

    function inspectNode(object, objects, duplicatesIndexes) {
      var objectKeyList, index, length;

      if (object !== null && typeof object === 'object') {
        index = objects.indexOf(object);

        if (index !== -1) {
          if (duplicatesIndexes.indexOf(index) === -1) {
            duplicatesIndexes.push(index);
          }
        } else {
          objects.push(object);

          if (Array.isArray(object)) {
            for (index = 0, length = object.length; index < length; index += 1) {
              inspectNode(object[index], objects, duplicatesIndexes);
            }
          } else {
            objectKeyList = Object.keys(object);

            for (index = 0, length = objectKeyList.length; index < length; index += 1) {
              inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes);
            }
          }
        }
      }
    }

    function dump(input, options) {
      options = options || {};
      var state = new State$1(options);
      if (!state.noRefs) getDuplicateReferences(input, state);
      if (writeNode(state, 0, input, true, true)) return state.dump + '\n';
      return '';
    }

    function safeDump(input, options) {
      return dump(input, common.extend({
        schema: default_safe
      }, options));
    }

    var dump_1 = dump;
    var safeDump_1 = safeDump;
    var dumper = {
      dump: dump_1,
      safeDump: safeDump_1
    };

    function deprecated(name) {
      return function () {
        throw new Error('Function ' + name + ' is deprecated and cannot be used.');
      };
    }

    var Type$1 = type;
    var Schema$1 = schema;
    var FAILSAFE_SCHEMA = failsafe;
    var JSON_SCHEMA = json;
    var CORE_SCHEMA = core;
    var DEFAULT_SAFE_SCHEMA = default_safe;
    var DEFAULT_FULL_SCHEMA = default_full;
    var load$1 = loader.load;
    var loadAll$1 = loader.loadAll;
    var safeLoad$1 = loader.safeLoad;
    var safeLoadAll$1 = loader.safeLoadAll;
    var dump$1 = dumper.dump;
    var safeDump$1 = dumper.safeDump;
    var YAMLException$1 = exception; // Deprecated schema names from JS-YAML 2.0.x

    var MINIMAL_SCHEMA = failsafe;
    var SAFE_SCHEMA = default_safe;
    var DEFAULT_SCHEMA = default_full; // Deprecated functions from JS-YAML 1.x.x

    var scan = deprecated('scan');
    var parse = deprecated('parse');
    var compose = deprecated('compose');
    var addConstructor = deprecated('addConstructor');
    var jsYaml = {
      Type: Type$1,
      Schema: Schema$1,
      FAILSAFE_SCHEMA: FAILSAFE_SCHEMA,
      JSON_SCHEMA: JSON_SCHEMA,
      CORE_SCHEMA: CORE_SCHEMA,
      DEFAULT_SAFE_SCHEMA: DEFAULT_SAFE_SCHEMA,
      DEFAULT_FULL_SCHEMA: DEFAULT_FULL_SCHEMA,
      load: load$1,
      loadAll: loadAll$1,
      safeLoad: safeLoad$1,
      safeLoadAll: safeLoadAll$1,
      dump: dump$1,
      safeDump: safeDump$1,
      YAMLException: YAMLException$1,
      MINIMAL_SCHEMA: MINIMAL_SCHEMA,
      SAFE_SCHEMA: SAFE_SCHEMA,
      DEFAULT_SCHEMA: DEFAULT_SCHEMA,
      scan: scan,
      parse: parse,
      compose: compose,
      addConstructor: addConstructor
    };

    var jsYaml$1 = jsYaml;

    function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

    function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
    /**
     * Redirect - object used to redirect some requests
     * e.g.
     * {
     *      title: 1x1-transparent.gif
     *      comment: http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever
     *      contentType: image/gif;base64
     *      content: R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
     * }
     * @typedef {Object} Redirect
     * @property {string} title
     * @property {string} comment
     * @property {string} content
     * @property {string} contentType
     * @property {boolean} [isBlocking]
     * @property {string} [sha]
     */

    var Redirects = /*#__PURE__*/function () {
      /**
       * Converts rawYaml into JS object with sources titles used as keys
       * @param rawYaml
       * @returns {Object<Redirect>} - return object with titles in the keys and RedirectSources
       * in the values
       */
      function Redirects(rawYaml) {
        classCallCheck(this, Redirects);

        try {
          var arrOfRedirects = jsYaml$1.safeLoad(rawYaml);
          this.redirects = arrOfRedirects.reduce(function (acc, redirect) {
            return _objectSpread(_objectSpread({}, acc), {}, defineProperty({}, redirect.title, redirect));
          }, {});
        } catch (e) {
          // eslint-disable-next-line no-console
          console.log("Was unable to load YAML into JS due to: ".concat(e.message));
          throw e;
        }
      }
      /**
       * Returns redirect source object
       * @param {string} title
       * @return {Redirect}
       */


      createClass(Redirects, [{
        key: "getRedirect",
        value: function getRedirect(title) {
          var _this = this;

          if (Object.prototype.hasOwnProperty.call(this.redirects, title)) {
            return this.redirects[title];
          } // look title among aliases


          var values = Object.keys(this.redirects).map(function (key) {
            return _this.redirects[key];
          });
          return values.find(function (redirect) {
            var aliases = redirect.aliases;

            if (!aliases) {
              return false;
            }

            return aliases.indexOf(title) > -1;
          });
        }
      }]);

      return Redirects;
    }();

    /**
     * Finds redirect resource by it's name
     * @param {string} name - redirect name
     */

    var getRedirectByName = function getRedirectByName(name) {
      var redirects = Object.keys(redirectsList).map(function (key) {
        return redirectsList[key];
      });
      return redirects.find(function (r) {
        return r.names && r.names.indexOf(name) > -1;
      });
    };
    /**
     * @typedef {Object} Source - redirect properties
     * @property {string} name redirect name
     * @property {Array<string>} args Arguments for redirect function
     * @property {'extension'|'test'} [engine] -
     * Defines the final form of redirect string presentation
     * @property {boolean} [verbose] flag to enable printing to console debug information
     */

    /**
     * Returns redirect code by param
     * @param {Source} source
     * @returns {string} redirect code
     */


    var getRedirectCode = function getRedirectCode(source) {
      var redirect = getRedirectByName(source.name);
      var result = attachDependencies(redirect);
      result = addCall(redirect, result); // redirect code for different sources is checked in tests
      // so it should be just a code without any source and props passed

      result = source.engine === 'test' ? wrapInNonameFunc(result) : passSourceAndProps(source, result);
      return result;
    };

    var redirectsCjs = {
      Redirects: Redirects,
      getCode: getRedirectCode,
      isAdgRedirectRule: validator.isAdgRedirectRule,
      isValidAdgRedirectRule: validator.isValidAdgRedirectRule,
      isAdgRedirectCompatibleWithUbo: validator.isAdgRedirectCompatibleWithUbo,
      isUboRedirectCompatibleWithAdg: validator.isUboRedirectCompatibleWithAdg,
      isAbpRedirectCompatibleWithAdg: validator.isAbpRedirectCompatibleWithAdg,
      convertUboRedirectToAdg: convertUboRedirectToAdg,
      convertAbpRedirectToAdg: convertAbpRedirectToAdg,
      convertRedirectToAdg: convertRedirectToAdg,
      convertAdgRedirectToUbo: convertAdgRedirectToUbo
    };

    /**
     * @typedef {Object} Source - scriptlet properties
     * @property {string} name Scriptlet name
     * @property {Array<string>} args Arguments for scriptlet function
     * @property {'extension'|'corelibs'|'test'} engine -
     * Defines the final form of scriptlet string presentation
     * @property {string} [version]
     * @property {boolean} [verbose] flag to enable printing to console debug information
     * @property {string} [ruleText] Source rule text is used for debugging purposes
     * @property {string} [domainName] domain name where scriptlet is applied; for debugging purposes
     */

    /**
     * Returns scriptlet code by param
     * @param {Source} source
     * @returns {string} scriptlet code
     */

    function getScriptletCode(source) {
      if (!validator.isValidScriptletName(source.name)) {
        return null;
      }

      var scriptlet = validator.getScriptletByName(source.name);
      var result = attachDependencies(scriptlet);
      result = addCall(scriptlet, result);
      result = source.engine === 'corelibs' || source.engine === 'test' ? wrapInNonameFunc(result) : passSourceAndProps(source, result);
      return result;
    }
    /**
     * Scriptlets variable
     *
     * @returns {Object} object with methods:
     * `invoke` method receives one argument with `Source` type
     * `validate` method receives one argument with `String` type
     */


    var scriptletsObject = function () {
      return {
        invoke: getScriptletCode,
        isValidScriptletName: validator.isValidScriptletName,
        isValidScriptletRule: isValidScriptletRule,
        isAdgScriptletRule: validator.isAdgScriptletRule,
        isUboScriptletRule: validator.isUboScriptletRule,
        isAbpSnippetRule: validator.isAbpSnippetRule,
        convertUboToAdg: convertUboScriptletToAdg,
        convertAbpToAdg: convertAbpSnippetToAdg,
        convertScriptletToAdg: convertScriptletToAdg,
        convertAdgToUbo: convertAdgScriptletToUbo,
        redirects: redirectsCjs
      };
    }();

    /**
     * Add module exports to be used as node package
     */

    module.exports = scriptletsObject;

})));

/**
 * -------------------------------------------
 * |                                         |
 * |  If you want to add your own scriptlet  |
 * |  please put your code below             |
 * |                                         |
 * -------------------------------------------
 */


/***/ }),

/***/ 4346:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {

(function (global, factory) {
     true ? factory(exports) :
    0;
})(this, (function (exports) { 'use strict';

    var extendStatics = function(d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    function __extends(d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    }
    var __assign = function() {
        __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
        return __assign.apply(this, arguments);
    };
    function __awaiter(thisArg, _arguments, P, generator) {
        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
        return new (P || (P = Promise))(function (resolve, reject) {
            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
            step((generator = generator.apply(thisArg, _arguments || [])).next());
        });
    }
    function __generator(thisArg, body) {
        var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
        return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
        function verb(n) { return function (v) { return step([n, v]); }; }
        function step(op) {
            if (f) throw new TypeError("Generator is already executing.");
            while (_) try {
                if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
                if (y = 0, t) op = [op[0] & 2, t.value];
                switch (op[0]) {
                    case 0: case 1: t = op; break;
                    case 4: _.label++; return { value: op[1], done: false };
                    case 5: _.label++; y = op[1]; op = [0]; continue;
                    case 7: op = _.ops.pop(); _.trys.pop(); continue;
                    default:
                        if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                        if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                        if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                        if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                        if (t[2]) _.ops.pop();
                        _.trys.pop(); continue;
                }
                op = body.call(thisArg, _);
            } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
            if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
        }
    }
    function __spreadArray(to, from, pack) {
        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
            if (ar || !(i in from)) {
                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
                ar[i] = from[i];
            }
        }
        return to.concat(ar || Array.prototype.slice.call(from));
    }

    /**
     * Compatibility types are used to configure engine for better support of different libraries
     * For example:
     *  extension doesnt support $app modifier. So if we set in configuration CompatibilityTypes.extension,
     *  engine would ignore rules with $app modifier
     */
    exports.CompatibilityTypes = void 0;
    (function (CompatibilityTypes) {
        CompatibilityTypes[CompatibilityTypes["extension"] = 1] = "extension";
        CompatibilityTypes[CompatibilityTypes["corelibs"] = 2] = "corelibs";
    })(exports.CompatibilityTypes || (exports.CompatibilityTypes = {}));
    /**
     * Application configuration class
     */
    var Configuration = /** @class */ (function () {
        function Configuration(inputConfig) {
            this.defaultConfig = {
                engine: null,
                version: null,
                verbose: false,
                compatibility: null,
            };
            /**
             * {'extension'|'corelibs'} engine application type
             */
            this.engine = null;
            /**
             * {string} version
             */
            this.version = null;
            /**
             * {boolean} verbose flag
             */
            this.verbose = false;
            /**
             * compatibility flag
             */
            this.compatibility = exports.CompatibilityTypes.extension;
            var config = __assign(__assign({}, this.defaultConfig), inputConfig);
            this.engine = config.engine;
            this.version = config.version;
            this.verbose = config.verbose;
            this.compatibility = config.compatibility;
        }
        return Configuration;
    }());
    exports.config = new Configuration();
    /**
     * Checks config is compatible with input level
     * @param compatibilityLevel
     * @private
     */
    function isCompatibleWith(compatibilityLevel) {
        if (exports.config.compatibility === null) {
            return false;
        }
        return (exports.config.compatibility & compatibilityLevel) === compatibilityLevel;
    }
    var setConfiguration = function (outerConfig) {
        exports.config = new Configuration(outerConfig);
    };

    var DEFAULT_CHARSET = 'utf-8';
    var LATIN_1 = 'iso-8859-1';
    var WIN_1251 = 'windows-1251';
    var WIN_1252 = 'windows-1252';
    /**
     * Supported charsets array
     */
    var SUPPORTED_CHARSETS = [DEFAULT_CHARSET, WIN_1251, WIN_1252, LATIN_1];
    /**
     * Parses charset from content-type header
     *
     * @param contentType
     * @returns {*}
     */
    function parseCharsetFromHeader(contentType) {
        if (!contentType) {
            return null;
        }
        var match = /charset="?(.*?)"?$/.exec(contentType.toLowerCase());
        if (match && match.length > 1) {
            return match[1].toLowerCase();
        }
        return null;
    }
    /**
     * Parses charset from html, looking for:
     * <meta charset="utf-8" />
     * <meta charset=utf-8 />
     * <meta charset=utf-8>
     * <meta http-equiv="content-type" content="text/html; charset=utf-8" />
     * <meta content="text/html; charset=utf-8" http-equiv="content-type" />
     *
     * @param text
     */
    function parseCharsetFromHtml(text) {
        var match = /<meta\s*charset\s*=\s*['"]?(.*?)['"]?\s*\/?>/.exec(text.toLowerCase());
        if (match && match.length > 1) {
            return match[1].trim().toLowerCase();
        }
        // eslint-disable-next-line max-len
        match = /<meta\s*http-equiv\s*=\s*['"]?content-type['"]?\s*content\s*=\s*[\\]?['"]text\/html;\s*charset=(.*?)[\\]?['"]/.exec(text.toLowerCase());
        if (match && match.length > 1) {
            return match[1].trim().toLowerCase();
        }
        // eslint-disable-next-line max-len
        match = /<meta\s*content\s*=\s*[\\]?['"]text\/html;\s*charset=(.*?)[\\]?['"]\s*http-equiv\s*=\s*['"]?content-type['"]?/.exec(text.toLowerCase());
        if (match && match.length > 1) {
            return match[1].trim().toLowerCase();
        }
        return null;
    }
    /**
     * Parses charset from css
     *
     * @param text
     */
    function parseCharsetFromCss(text) {
        var match = /^@charset\s*['"](.*?)['"]/.exec(text.toLowerCase());
        if (match && match.length > 1) {
            return match[1].trim().toLowerCase();
        }
        return null;
    }

    var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : 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 encoding$1 = {exports: {}};

    var encodingIndexes = {exports: {}};

    (function (module) {
    (function(global) {
      if (module.exports) {
        module.exports = global;
      }
      global["encoding-indexes"] =
    {
      "big5":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,17392,19506,17923,17830,17784,160359,19831,17843,162993,19682,163013,15253,18230,18244,19527,19520,148159,144919,160594,159371,159954,19543,172881,18255,17882,19589,162924,19719,19108,18081,158499,29221,154196,137827,146950,147297,26189,22267,null,32149,22813,166841,15860,38708,162799,23515,138590,23204,13861,171696,23249,23479,23804,26478,34195,170309,29793,29853,14453,138579,145054,155681,16108,153822,15093,31484,40855,147809,166157,143850,133770,143966,17162,33924,40854,37935,18736,34323,22678,38730,37400,31184,31282,26208,27177,34973,29772,31685,26498,31276,21071,36934,13542,29636,155065,29894,40903,22451,18735,21580,16689,145038,22552,31346,162661,35727,18094,159368,16769,155033,31662,140476,40904,140481,140489,140492,40905,34052,144827,16564,40906,17633,175615,25281,28782,40907,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,12736,12737,12738,12739,12740,131340,12741,131281,131277,12742,12743,131275,139240,12744,131274,12745,12746,12747,12748,131342,12749,12750,256,193,461,192,274,201,282,200,332,211,465,210,null,7870,null,7872,202,257,225,462,224,593,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,null,7871,null,7873,234,609,9178,9179,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,172969,135493,null,25866,null,null,20029,28381,40270,37343,null,null,161589,25745,20250,20264,20392,20822,20852,20892,20964,21153,21160,21307,21326,21457,21464,22242,22768,22788,22791,22834,22836,23398,23454,23455,23706,24198,24635,25993,26622,26628,26725,27982,28860,30005,32420,32428,32442,32455,32463,32479,32518,32567,33402,33487,33647,35270,35774,35810,36710,36711,36718,29713,31996,32205,26950,31433,21031,null,null,null,null,37260,30904,37214,32956,null,36107,33014,133607,null,null,32927,40647,19661,40393,40460,19518,171510,159758,40458,172339,13761,null,28314,33342,29977,null,18705,39532,39567,40857,31111,164972,138698,132560,142054,20004,20097,20096,20103,20159,20203,20279,13388,20413,15944,20483,20616,13437,13459,13477,20870,22789,20955,20988,20997,20105,21113,21136,21287,13767,21417,13649,21424,13651,21442,21539,13677,13682,13953,21651,21667,21684,21689,21712,21743,21784,21795,21800,13720,21823,13733,13759,21975,13765,163204,21797,null,134210,134421,151851,21904,142534,14828,131905,36422,150968,169189,16467,164030,30586,142392,14900,18389,164189,158194,151018,25821,134524,135092,134357,135412,25741,36478,134806,134155,135012,142505,164438,148691,null,134470,170573,164073,18420,151207,142530,39602,14951,169460,16365,13574,152263,169940,161992,142660,40302,38933,null,17369,155813,25780,21731,142668,142282,135287,14843,135279,157402,157462,162208,25834,151634,134211,36456,139681,166732,132913,null,18443,131497,16378,22643,142733,null,148936,132348,155799,134988,134550,21881,16571,17338,null,19124,141926,135325,33194,39157,134556,25465,14846,141173,36288,22177,25724,15939,null,173569,134665,142031,142537,null,135368,145858,14738,14854,164507,13688,155209,139463,22098,134961,142514,169760,13500,27709,151099,null,null,161140,142987,139784,173659,167117,134778,134196,157724,32659,135375,141315,141625,13819,152035,134796,135053,134826,16275,134960,134471,135503,134732,null,134827,134057,134472,135360,135485,16377,140950,25650,135085,144372,161337,142286,134526,134527,142417,142421,14872,134808,135367,134958,173618,158544,167122,167321,167114,38314,21708,33476,21945,null,171715,39974,39606,161630,142830,28992,33133,33004,23580,157042,33076,14231,21343,164029,37302,134906,134671,134775,134907,13789,151019,13833,134358,22191,141237,135369,134672,134776,135288,135496,164359,136277,134777,151120,142756,23124,135197,135198,135413,135414,22428,134673,161428,164557,135093,134779,151934,14083,135094,135552,152280,172733,149978,137274,147831,164476,22681,21096,13850,153405,31666,23400,18432,19244,40743,18919,39967,39821,154484,143677,22011,13810,22153,20008,22786,138177,194680,38737,131206,20059,20155,13630,23587,24401,24516,14586,25164,25909,27514,27701,27706,28780,29227,20012,29357,149737,32594,31035,31993,32595,156266,13505,null,156491,32770,32896,157202,158033,21341,34916,35265,161970,35744,36125,38021,38264,38271,38376,167439,38886,39029,39118,39134,39267,170000,40060,40479,40644,27503,63751,20023,131207,38429,25143,38050,null,20539,28158,171123,40870,15817,34959,147790,28791,23797,19232,152013,13657,154928,24866,166450,36775,37366,29073,26393,29626,144001,172295,15499,137600,19216,30948,29698,20910,165647,16393,27235,172730,16931,34319,133743,31274,170311,166634,38741,28749,21284,139390,37876,30425,166371,40871,30685,20131,20464,20668,20015,20247,40872,21556,32139,22674,22736,138678,24210,24217,24514,141074,25995,144377,26905,27203,146531,27903,null,29184,148741,29580,16091,150035,23317,29881,35715,154788,153237,31379,31724,31939,32364,33528,34199,40873,34960,40874,36537,40875,36815,34143,39392,37409,40876,167353,136255,16497,17058,23066,null,null,null,39016,26475,17014,22333,null,34262,149883,33471,160013,19585,159092,23931,158485,159678,40877,40878,23446,40879,26343,32347,28247,31178,15752,17603,143958,141206,17306,17718,null,23765,146202,35577,23672,15634,144721,23928,40882,29015,17752,147692,138787,19575,14712,13386,131492,158785,35532,20404,131641,22975,33132,38998,170234,24379,134047,null,139713,166253,16642,18107,168057,16135,40883,172469,16632,14294,18167,158790,16764,165554,160767,17773,14548,152730,17761,17691,19849,19579,19830,17898,16328,150287,13921,17630,17597,16877,23870,23880,23894,15868,14351,23972,23993,14368,14392,24130,24253,24357,24451,14600,14612,14655,14669,24791,24893,23781,14729,25015,25017,25039,14776,25132,25232,25317,25368,14840,22193,14851,25570,25595,25607,25690,14923,25792,23829,22049,40863,14999,25990,15037,26111,26195,15090,26258,15138,26390,15170,26532,26624,15192,26698,26756,15218,15217,15227,26889,26947,29276,26980,27039,27013,15292,27094,15325,27237,27252,27249,27266,15340,27289,15346,27307,27317,27348,27382,27521,27585,27626,27765,27818,15563,27906,27910,27942,28033,15599,28068,28081,28181,28184,28201,28294,166336,28347,28386,28378,40831,28392,28393,28452,28468,15686,147265,28545,28606,15722,15733,29111,23705,15754,28716,15761,28752,28756,28783,28799,28809,131877,17345,13809,134872,147159,22462,159443,28990,153568,13902,27042,166889,23412,31305,153825,169177,31333,31357,154028,31419,31408,31426,31427,29137,156813,16842,31450,31453,31466,16879,21682,154625,31499,31573,31529,152334,154878,31650,31599,33692,154548,158847,31696,33825,31634,31672,154912,15789,154725,33938,31738,31750,31797,154817,31812,31875,149634,31910,26237,148856,31945,31943,31974,31860,31987,31989,31950,32359,17693,159300,32093,159446,29837,32137,32171,28981,32179,32210,147543,155689,32228,15635,32245,137209,32229,164717,32285,155937,155994,32366,32402,17195,37996,32295,32576,32577,32583,31030,156368,39393,32663,156497,32675,136801,131176,17756,145254,17667,164666,32762,156809,32773,32776,32797,32808,32815,172167,158915,32827,32828,32865,141076,18825,157222,146915,157416,26405,32935,166472,33031,33050,22704,141046,27775,156824,151480,25831,136330,33304,137310,27219,150117,150165,17530,33321,133901,158290,146814,20473,136445,34018,33634,158474,149927,144688,137075,146936,33450,26907,194964,16859,34123,33488,33562,134678,137140,14017,143741,144730,33403,33506,33560,147083,159139,158469,158615,144846,15807,33565,21996,33669,17675,159141,33708,33729,33747,13438,159444,27223,34138,13462,159298,143087,33880,154596,33905,15827,17636,27303,33866,146613,31064,33960,158614,159351,159299,34014,33807,33681,17568,33939,34020,154769,16960,154816,17731,34100,23282,159385,17703,34163,17686,26559,34326,165413,165435,34241,159880,34306,136578,159949,194994,17770,34344,13896,137378,21495,160666,34430,34673,172280,34798,142375,34737,34778,34831,22113,34412,26710,17935,34885,34886,161248,146873,161252,34910,34972,18011,34996,34997,25537,35013,30583,161551,35207,35210,35238,35241,35239,35260,166437,35303,162084,162493,35484,30611,37374,35472,162393,31465,162618,147343,18195,162616,29052,35596,35615,152624,152933,35647,35660,35661,35497,150138,35728,35739,35503,136927,17941,34895,35995,163156,163215,195028,14117,163155,36054,163224,163261,36114,36099,137488,36059,28764,36113,150729,16080,36215,36265,163842,135188,149898,15228,164284,160012,31463,36525,36534,36547,37588,36633,36653,164709,164882,36773,37635,172703,133712,36787,18730,166366,165181,146875,24312,143970,36857,172052,165564,165121,140069,14720,159447,36919,165180,162494,36961,165228,165387,37032,165651,37060,165606,37038,37117,37223,15088,37289,37316,31916,166195,138889,37390,27807,37441,37474,153017,37561,166598,146587,166668,153051,134449,37676,37739,166625,166891,28815,23235,166626,166629,18789,37444,166892,166969,166911,37747,37979,36540,38277,38310,37926,38304,28662,17081,140922,165592,135804,146990,18911,27676,38523,38550,16748,38563,159445,25050,38582,30965,166624,38589,21452,18849,158904,131700,156688,168111,168165,150225,137493,144138,38705,34370,38710,18959,17725,17797,150249,28789,23361,38683,38748,168405,38743,23370,168427,38751,37925,20688,143543,143548,38793,38815,38833,38846,38848,38866,38880,152684,38894,29724,169011,38911,38901,168989,162170,19153,38964,38963,38987,39014,15118,160117,15697,132656,147804,153350,39114,39095,39112,39111,19199,159015,136915,21936,39137,39142,39148,37752,39225,150057,19314,170071,170245,39413,39436,39483,39440,39512,153381,14020,168113,170965,39648,39650,170757,39668,19470,39700,39725,165376,20532,39732,158120,14531,143485,39760,39744,171326,23109,137315,39822,148043,39938,39935,39948,171624,40404,171959,172434,172459,172257,172323,172511,40318,40323,172340,40462,26760,40388,139611,172435,172576,137531,172595,40249,172217,172724,40592,40597,40606,40610,19764,40618,40623,148324,40641,15200,14821,15645,20274,14270,166955,40706,40712,19350,37924,159138,40727,40726,40761,22175,22154,40773,39352,168075,38898,33919,40802,40809,31452,40846,29206,19390,149877,149947,29047,150008,148296,150097,29598,166874,137466,31135,166270,167478,37737,37875,166468,37612,37761,37835,166252,148665,29207,16107,30578,31299,28880,148595,148472,29054,137199,28835,137406,144793,16071,137349,152623,137208,14114,136955,137273,14049,137076,137425,155467,14115,136896,22363,150053,136190,135848,136134,136374,34051,145062,34051,33877,149908,160101,146993,152924,147195,159826,17652,145134,170397,159526,26617,14131,15381,15847,22636,137506,26640,16471,145215,147681,147595,147727,158753,21707,22174,157361,22162,135135,134056,134669,37830,166675,37788,20216,20779,14361,148534,20156,132197,131967,20299,20362,153169,23144,131499,132043,14745,131850,132116,13365,20265,131776,167603,131701,35546,131596,20120,20685,20749,20386,20227,150030,147082,20290,20526,20588,20609,20428,20453,20568,20732,20825,20827,20829,20830,28278,144789,147001,147135,28018,137348,147081,20904,20931,132576,17629,132259,132242,132241,36218,166556,132878,21081,21156,133235,21217,37742,18042,29068,148364,134176,149932,135396,27089,134685,29817,16094,29849,29716,29782,29592,19342,150204,147597,21456,13700,29199,147657,21940,131909,21709,134086,22301,37469,38644,37734,22493,22413,22399,13886,22731,23193,166470,136954,137071,136976,23084,22968,37519,23166,23247,23058,153926,137715,137313,148117,14069,27909,29763,23073,155267,23169,166871,132115,37856,29836,135939,28933,18802,37896,166395,37821,14240,23582,23710,24158,24136,137622,137596,146158,24269,23375,137475,137476,14081,137376,14045,136958,14035,33066,166471,138682,144498,166312,24332,24334,137511,137131,23147,137019,23364,34324,161277,34912,24702,141408,140843,24539,16056,140719,140734,168072,159603,25024,131134,131142,140827,24985,24984,24693,142491,142599,149204,168269,25713,149093,142186,14889,142114,144464,170218,142968,25399,173147,25782,25393,25553,149987,142695,25252,142497,25659,25963,26994,15348,143502,144045,149897,144043,21773,144096,137433,169023,26318,144009,143795,15072,16784,152964,166690,152975,136956,152923,152613,30958,143619,137258,143924,13412,143887,143746,148169,26254,159012,26219,19347,26160,161904,138731,26211,144082,144097,26142,153714,14545,145466,145340,15257,145314,144382,29904,15254,26511,149034,26806,26654,15300,27326,14435,145365,148615,27187,27218,27337,27397,137490,25873,26776,27212,15319,27258,27479,147392,146586,37792,37618,166890,166603,37513,163870,166364,37991,28069,28427,149996,28007,147327,15759,28164,147516,23101,28170,22599,27940,30786,28987,148250,148086,28913,29264,29319,29332,149391,149285,20857,150180,132587,29818,147192,144991,150090,149783,155617,16134,16049,150239,166947,147253,24743,16115,29900,29756,37767,29751,17567,159210,17745,30083,16227,150745,150790,16216,30037,30323,173510,15129,29800,166604,149931,149902,15099,15821,150094,16127,149957,149747,37370,22322,37698,166627,137316,20703,152097,152039,30584,143922,30478,30479,30587,149143,145281,14942,149744,29752,29851,16063,150202,150215,16584,150166,156078,37639,152961,30750,30861,30856,30930,29648,31065,161601,153315,16654,31131,33942,31141,27181,147194,31290,31220,16750,136934,16690,37429,31217,134476,149900,131737,146874,137070,13719,21867,13680,13994,131540,134157,31458,23129,141045,154287,154268,23053,131675,30960,23082,154566,31486,16889,31837,31853,16913,154547,155324,155302,31949,150009,137136,31886,31868,31918,27314,32220,32263,32211,32590,156257,155996,162632,32151,155266,17002,158581,133398,26582,131150,144847,22468,156690,156664,149858,32733,31527,133164,154345,154947,31500,155150,39398,34373,39523,27164,144447,14818,150007,157101,39455,157088,33920,160039,158929,17642,33079,17410,32966,33033,33090,157620,39107,158274,33378,33381,158289,33875,159143,34320,160283,23174,16767,137280,23339,137377,23268,137432,34464,195004,146831,34861,160802,23042,34926,20293,34951,35007,35046,35173,35149,153219,35156,161669,161668,166901,166873,166812,166393,16045,33955,18165,18127,14322,35389,35356,169032,24397,37419,148100,26068,28969,28868,137285,40301,35999,36073,163292,22938,30659,23024,17262,14036,36394,36519,150537,36656,36682,17140,27736,28603,140065,18587,28537,28299,137178,39913,14005,149807,37051,37015,21873,18694,37307,37892,166475,16482,166652,37927,166941,166971,34021,35371,38297,38311,38295,38294,167220,29765,16066,149759,150082,148458,16103,143909,38543,167655,167526,167525,16076,149997,150136,147438,29714,29803,16124,38721,168112,26695,18973,168083,153567,38749,37736,166281,166950,166703,156606,37562,23313,35689,18748,29689,147995,38811,38769,39224,134950,24001,166853,150194,38943,169178,37622,169431,37349,17600,166736,150119,166756,39132,166469,16128,37418,18725,33812,39227,39245,162566,15869,39323,19311,39338,39516,166757,153800,27279,39457,23294,39471,170225,19344,170312,39356,19389,19351,37757,22642,135938,22562,149944,136424,30788,141087,146872,26821,15741,37976,14631,24912,141185,141675,24839,40015,40019,40059,39989,39952,39807,39887,171565,39839,172533,172286,40225,19630,147716,40472,19632,40204,172468,172269,172275,170287,40357,33981,159250,159711,158594,34300,17715,159140,159364,159216,33824,34286,159232,145367,155748,31202,144796,144960,18733,149982,15714,37851,37566,37704,131775,30905,37495,37965,20452,13376,36964,152925,30781,30804,30902,30795,137047,143817,149825,13978,20338,28634,28633,28702,28702,21524,147893,22459,22771,22410,40214,22487,28980,13487,147884,29163,158784,151447,23336,137141,166473,24844,23246,23051,17084,148616,14124,19323,166396,37819,37816,137430,134941,33906,158912,136211,148218,142374,148417,22932,146871,157505,32168,155995,155812,149945,149899,166394,37605,29666,16105,29876,166755,137375,16097,150195,27352,29683,29691,16086,150078,150164,137177,150118,132007,136228,149989,29768,149782,28837,149878,37508,29670,37727,132350,37681,166606,166422,37766,166887,153045,18741,166530,29035,149827,134399,22180,132634,134123,134328,21762,31172,137210,32254,136898,150096,137298,17710,37889,14090,166592,149933,22960,137407,137347,160900,23201,14050,146779,14000,37471,23161,166529,137314,37748,15565,133812,19094,14730,20724,15721,15692,136092,29045,17147,164376,28175,168164,17643,27991,163407,28775,27823,15574,147437,146989,28162,28428,15727,132085,30033,14012,13512,18048,16090,18545,22980,37486,18750,36673,166940,158656,22546,22472,14038,136274,28926,148322,150129,143331,135856,140221,26809,26983,136088,144613,162804,145119,166531,145366,144378,150687,27162,145069,158903,33854,17631,17614,159014,159057,158850,159710,28439,160009,33597,137018,33773,158848,159827,137179,22921,23170,137139,23137,23153,137477,147964,14125,23023,137020,14023,29070,37776,26266,148133,23150,23083,148115,27179,147193,161590,148571,148170,28957,148057,166369,20400,159016,23746,148686,163405,148413,27148,148054,135940,28838,28979,148457,15781,27871,194597,150095,32357,23019,23855,15859,24412,150109,137183,32164,33830,21637,146170,144128,131604,22398,133333,132633,16357,139166,172726,28675,168283,23920,29583,31955,166489,168992,20424,32743,29389,29456,162548,29496,29497,153334,29505,29512,16041,162584,36972,29173,149746,29665,33270,16074,30476,16081,27810,22269,29721,29726,29727,16098,16112,16116,16122,29907,16142,16211,30018,30061,30066,30093,16252,30152,30172,16320,30285,16343,30324,16348,30330,151388,29064,22051,35200,22633,16413,30531,16441,26465,16453,13787,30616,16490,16495,23646,30654,30667,22770,30744,28857,30748,16552,30777,30791,30801,30822,33864,152885,31027,26627,31026,16643,16649,31121,31129,36795,31238,36796,16743,31377,16818,31420,33401,16836,31439,31451,16847,20001,31586,31596,31611,31762,31771,16992,17018,31867,31900,17036,31928,17044,31981,36755,28864,134351,32207,32212,32208,32253,32686,32692,29343,17303,32800,32805,31545,32814,32817,32852,15820,22452,28832,32951,33001,17389,33036,29482,33038,33042,30048,33044,17409,15161,33110,33113,33114,17427,22586,33148,33156,17445,33171,17453,33189,22511,33217,33252,33364,17551,33446,33398,33482,33496,33535,17584,33623,38505,27018,33797,28917,33892,24803,33928,17668,33982,34017,34040,34064,34104,34130,17723,34159,34160,34272,17783,34418,34450,34482,34543,38469,34699,17926,17943,34990,35071,35108,35143,35217,162151,35369,35384,35476,35508,35921,36052,36082,36124,18328,22623,36291,18413,20206,36410,21976,22356,36465,22005,36528,18487,36558,36578,36580,36589,36594,36791,36801,36810,36812,36915,39364,18605,39136,37395,18718,37416,37464,37483,37553,37550,37567,37603,37611,37619,37620,37629,37699,37764,37805,18757,18769,40639,37911,21249,37917,37933,37950,18794,37972,38009,38189,38306,18855,38388,38451,18917,26528,18980,38720,18997,38834,38850,22100,19172,24808,39097,19225,39153,22596,39182,39193,20916,39196,39223,39234,39261,39266,19312,39365,19357,39484,39695,31363,39785,39809,39901,39921,39924,19565,39968,14191,138178,40265,39994,40702,22096,40339,40381,40384,40444,38134,36790,40571,40620,40625,40637,40646,38108,40674,40689,40696,31432,40772,131220,131767,132000,26906,38083,22956,132311,22592,38081,14265,132565,132629,132726,136890,22359,29043,133826,133837,134079,21610,194619,134091,21662,134139,134203,134227,134245,134268,24807,134285,22138,134325,134365,134381,134511,134578,134600,26965,39983,34725,134660,134670,134871,135056,134957,134771,23584,135100,24075,135260,135247,135286,26398,135291,135304,135318,13895,135359,135379,135471,135483,21348,33965,135907,136053,135990,35713,136567,136729,137155,137159,20088,28859,137261,137578,137773,137797,138282,138352,138412,138952,25283,138965,139029,29080,26709,139333,27113,14024,139900,140247,140282,141098,141425,141647,33533,141671,141715,142037,35237,142056,36768,142094,38840,142143,38983,39613,142412,null,142472,142519,154600,142600,142610,142775,142741,142914,143220,143308,143411,143462,144159,144350,24497,26184,26303,162425,144743,144883,29185,149946,30679,144922,145174,32391,131910,22709,26382,26904,146087,161367,155618,146961,147129,161278,139418,18640,19128,147737,166554,148206,148237,147515,148276,148374,150085,132554,20946,132625,22943,138920,15294,146687,148484,148694,22408,149108,14747,149295,165352,170441,14178,139715,35678,166734,39382,149522,149755,150037,29193,150208,134264,22885,151205,151430,132985,36570,151596,21135,22335,29041,152217,152601,147274,150183,21948,152646,152686,158546,37332,13427,152895,161330,152926,18200,152930,152934,153543,149823,153693,20582,13563,144332,24798,153859,18300,166216,154286,154505,154630,138640,22433,29009,28598,155906,162834,36950,156082,151450,35682,156674,156746,23899,158711,36662,156804,137500,35562,150006,156808,147439,156946,19392,157119,157365,141083,37989,153569,24981,23079,194765,20411,22201,148769,157436,20074,149812,38486,28047,158909,13848,35191,157593,157806,156689,157790,29151,157895,31554,168128,133649,157990,37124,158009,31301,40432,158202,39462,158253,13919,156777,131105,31107,158260,158555,23852,144665,33743,158621,18128,158884,30011,34917,159150,22710,14108,140685,159819,160205,15444,160384,160389,37505,139642,160395,37680,160486,149968,27705,38047,160848,134904,34855,35061,141606,164979,137137,28344,150058,137248,14756,14009,23568,31203,17727,26294,171181,170148,35139,161740,161880,22230,16607,136714,14753,145199,164072,136133,29101,33638,162269,168360,23143,19639,159919,166315,162301,162314,162571,163174,147834,31555,31102,163849,28597,172767,27139,164632,21410,159239,37823,26678,38749,164207,163875,158133,136173,143919,163912,23941,166960,163971,22293,38947,166217,23979,149896,26046,27093,21458,150181,147329,15377,26422,163984,164084,164142,139169,164175,164233,164271,164378,164614,164655,164746,13770,164968,165546,18682,25574,166230,30728,37461,166328,17394,166375,17375,166376,166726,166868,23032,166921,36619,167877,168172,31569,168208,168252,15863,168286,150218,36816,29327,22155,169191,169449,169392,169400,169778,170193,170313,170346,170435,170536,170766,171354,171419,32415,171768,171811,19620,38215,172691,29090,172799,19857,36882,173515,19868,134300,36798,21953,36794,140464,36793,150163,17673,32383,28502,27313,20202,13540,166700,161949,14138,36480,137205,163876,166764,166809,162366,157359,15851,161365,146615,153141,153942,20122,155265,156248,22207,134765,36366,23405,147080,150686,25566,25296,137206,137339,25904,22061,154698,21530,152337,15814,171416,19581,22050,22046,32585,155352,22901,146752,34672,19996,135146,134473,145082,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096,33527,22053,33074,33816,32957,21994,31074,22083,21526,134813,13774,22021,22001,26353,164578,13869,30004,22000,21946,21655,21874,134209,134294,24272,151880,134774,142434,134818,40619,32090,21982,135285,25245,38765,21652,36045,29174,37238,25596,25529,25598,21865,142147,40050,143027,20890,13535,134567,20903,21581,21790,21779,30310,36397,157834,30129,32950,34820,34694,35015,33206,33820,135361,17644,29444,149254,23440,33547,157843,22139,141044,163119,147875,163187,159440,160438,37232,135641,37384,146684,173737,134828,134905,29286,138402,18254,151490,163833,135147,16634,40029,25887,142752,18675,149472,171388,135148,134666,24674,161187,135149,null,155720,135559,29091,32398,40272,19994,19972,13687,23309,27826,21351,13996,14812,21373,13989,149016,22682,150382,33325,21579,22442,154261,133497,null,14930,140389,29556,171692,19721,39917,146686,171824,19547,151465,169374,171998,33884,146870,160434,157619,145184,25390,32037,147191,146988,14890,36872,21196,15988,13946,17897,132238,30272,23280,134838,30842,163630,22695,16575,22140,39819,23924,30292,173108,40581,19681,30201,14331,24857,143578,148466,null,22109,135849,22439,149859,171526,21044,159918,13741,27722,40316,31830,39737,22494,137068,23635,25811,169168,156469,160100,34477,134440,159010,150242,134513,null,20990,139023,23950,38659,138705,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870,39726,31810,31878,39957,31740,39689,40727,39963,149822,40794,21875,23491,20477,40600,20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836,39232,38842,21292,24880,26924,21466,39946,40194,19515,38465,27008,20646,30022,137069,39386,21107,null,37209,38529,37212,null,37201,167575,25471,159011,27338,22033,37262,30074,25221,132092,29519,31856,154657,146685,null,149785,30422,39837,20010,134356,33726,34882,null,23626,27072,20717,22394,21023,24053,20174,27697,131570,20281,21660,21722,21146,36226,13822,24332,13811,null,27474,37244,40869,39831,38958,39092,39610,40616,40580,29050,31508,null,27642,34840,32632,null,22048,173642,36471,40787,null,36308,36431,40476,36353,25218,164733,36392,36469,31443,150135,31294,30936,27882,35431,30215,166490,40742,27854,34774,30147,172722,30803,194624,36108,29410,29553,35629,29442,29937,36075,150203,34351,24506,34976,17591,null,137275,159237,null,35454,140571,null,24829,30311,39639,40260,37742,39823,34805,null,34831,36087,29484,38689,39856,13782,29362,19463,31825,39242,155993,24921,19460,40598,24957,null,22367,24943,25254,25145,25294,14940,25058,21418,144373,25444,26626,13778,23895,166850,36826,167481,null,20697,138566,30982,21298,38456,134971,16485,null,30718,null,31938,155418,31962,31277,32870,32867,32077,29957,29938,35220,33306,26380,32866,160902,32859,29936,33027,30500,35209,157644,30035,159441,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877,27058,36262,null,35241,29800,28089,34753,147473,29927,15835,29046,24740,24988,15569,29026,24695,null,32625,166701,29264,24809,19326,21024,15384,146631,155351,161366,152881,137540,135934,170243,159196,159917,23745,156077,166415,145015,131310,157766,151310,17762,23327,156492,40784,40614,156267,12288,65292,12289,12290,65294,8231,65307,65306,65311,65281,65072,8230,8229,65104,65105,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075,9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309,65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087,65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,65115,65116,65117,65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167,12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963,8453,175,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120,65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786,8801,65122,65123,65124,65125,65126,65374,8745,8746,8869,8736,8735,8895,13266,13265,8747,8750,8757,8756,9792,9794,8853,8857,8593,8595,8592,8594,8598,8599,8601,8600,8741,8739,65295,65340,8725,65128,65284,65509,12306,65504,65505,65285,65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198,13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601,9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532,9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,9582,9584,9583,9552,9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316,21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,729,713,714,711,715,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9249,8364,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19968,20057,19969,19971,20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269,21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063,20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823,22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050,24051,24062,24178,24318,24331,24339,25165,19985,19984,19981,20013,20016,20025,20043,23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173,20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999,21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450,21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187,24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041,26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779,29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992,20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185,20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253,21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476,21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489,21488,21477,21485,21499,22235,22234,22806,22830,22833,22900,22902,23381,23427,23612,24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171,25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665,27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992,29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707,31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133,20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208,20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015,21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516,21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240,22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840,22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433,23546,23574,23673,24030,24070,24182,24180,24335,24347,24537,24534,25102,25100,25101,25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429,26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728,27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566,32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258,33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199,38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304,20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302,20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028,21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534,21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561,21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250,22256,22244,22251,22346,22353,22336,22349,22343,22350,22334,22352,22351,22331,22767,22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949,23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696,23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418,24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220,25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199,25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446,26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599,27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788,27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800,27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995,30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915,32925,32920,32923,32922,32946,33391,33426,33419,33421,35211,35282,35328,35895,35910,35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804,24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442,38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339,20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350,20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051,21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329,21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632,21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608,21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812,22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992,22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450,23448,23452,23449,23451,23578,23624,23621,23622,23735,23713,23736,23721,23723,23729,23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214,24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575,24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110,25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307,25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269,25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132,26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477,26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505,26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667,27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819,27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873,27867,27850,27820,27887,27868,27862,27872,28821,28814,28818,28810,28825,29228,29229,29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611,29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040,31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933,32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437,33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470,33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046,37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738,38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419,20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407,20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193,21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688,21670,21683,21703,21698,21693,21674,21697,21700,21704,21679,21675,21681,21691,21673,21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865,22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014,23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627,23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421,24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616,24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366,25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332,25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143,26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613,26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585,26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954,27946,27969,27941,27916,27953,27934,27927,27963,27965,27966,27958,27931,27893,27961,27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845,28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627,29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117,30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456,30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048,31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005,32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822,32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268,33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495,33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427,34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276,36557,36556,36848,36838,36834,36842,36837,36845,36843,36836,36840,37066,37070,37057,37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893,38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463,20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480,20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523,20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083,21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746,21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757,21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057,23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403,23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632,23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235,24237,24231,24369,24466,24465,24464,24665,24675,24677,24656,24661,24685,24681,24687,24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422,25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384,25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188,26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690,26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666,26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888,28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994,28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872,28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664,29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141,30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504,30697,30768,30759,30776,30749,30772,30775,30757,30765,30752,30751,30770,31061,31056,31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209,31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034,32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705,32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012,33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322,33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588,33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451,34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344,35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001,36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852,36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341,37335,37340,37337,38275,38498,38499,38497,38491,38493,38500,38488,38494,38587,39138,39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556,20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589,20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311,21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809,21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847,22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519,22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110,23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644,23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847,23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375,24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739,24713,24736,24744,24779,24756,24806,24765,24773,24763,24757,24796,24764,24792,24789,24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506,25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476,25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942,25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059,26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799,26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758,26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046,28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079,28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139,28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937,28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701,29706,29699,29702,29694,29709,29920,29942,29943,29980,29986,30053,30054,30050,30064,30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524,30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520,31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113,32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670,32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072,33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725,33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426,34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952,34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373,35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198,36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885,36894,36896,36879,36898,36886,36891,36884,37096,37101,37117,37207,37326,37365,37350,37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519,38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613,40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106,21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898,21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822,21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580,22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186,23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888,23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380,24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853,24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507,25484,25551,25536,25577,25545,25542,25549,25554,25571,25552,25569,25558,25581,25582,25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000,26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399,26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834,26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450,27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210,28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198,28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259,28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260,29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750,29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169,30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828,30831,31245,31240,31243,31237,31232,31384,31383,31382,31461,31459,31561,31574,31558,31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085,32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850,32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298,33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879,33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748,33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010,34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398,35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032,36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305,36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918,37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389,37392,37383,37393,38292,38287,38283,38289,38291,38290,38286,38538,38542,38539,38525,38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860,38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653,40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679,21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990,21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961,22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626,22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913,23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863,24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845,24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628,25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248,26262,26244,26264,26253,26371,27028,26989,26970,26999,26976,26964,26997,26928,27010,26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584,27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325,28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006,29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032,29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761,29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207,30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556,30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867,30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391,31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129,32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900,33137,33136,33144,33125,33134,33139,33131,33145,33146,33126,33285,33351,33922,33911,33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897,33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562,34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029,35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488,35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977,36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339,36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938,36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929,37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467,37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548,38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928,38929,38931,38922,38930,38924,39164,39156,39165,39166,39347,39345,39348,39649,40169,40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689,20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039,22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296,22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820,22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521,23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149,24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930,24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722,25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036,27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085,27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404,28457,28478,28448,28460,28431,28418,28450,28415,28399,28422,28465,28472,28466,28451,28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053,29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805,29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561,30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401,31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620,31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177,32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735,32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287,33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976,33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584,34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494,35468,35486,35491,35469,35489,35475,35492,35498,35493,35496,35480,35473,35482,35495,35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629,36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144,37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532,37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604,38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177,39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740,20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133,21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103,22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893,23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965,23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503,24501,24950,24935,24942,24925,24917,24962,24956,24944,24939,24958,24999,24976,25003,24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736,25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753,25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137,27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470,27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536,28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100,29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240,30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609,30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293,31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692,31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233,32158,32217,32242,32249,32629,32631,32687,32745,32806,33179,33180,33181,33184,33178,33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028,34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636,34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524,35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547,35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074,36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382,36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968,36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559,37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660,38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187,39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663,39719,39749,39748,39799,39791,40198,40201,40195,40617,40638,40654,22696,40786,20754,20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137,22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718,22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970,25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796,25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311,26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207,27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583,28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141,29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922,29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938,30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716,31707,31713,31721,31718,31957,31958,32266,32273,32264,32283,32291,32286,32285,32265,32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368,33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719,34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578,35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574,35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655,36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664,37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653,37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671,38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208,39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825,40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769,20786,21237,22158,22144,22160,22149,22151,22159,22741,22739,22737,22734,23344,23338,23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026,25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841,25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299,27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635,28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166,29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862,29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967,30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756,31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306,32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580,32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215,33213,33225,33214,33256,33289,33393,34218,34180,34174,34204,34193,34196,34223,34203,34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760,34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616,35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425,36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994,36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656,37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584,38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850,39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165,22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851,25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487,27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176,29559,29557,29863,29887,29973,30294,30296,30290,30653,30655,30651,30652,30990,31150,31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340,32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231,33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802,34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454,36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780,37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352,38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991,38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686,39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725,40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077,25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701,28693,28696,29190,29197,29272,29346,29560,29562,29885,29898,29923,30087,30086,30303,30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363,32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282,34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166,35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466,36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857,37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864,38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237,39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300,40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363,23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720,28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820,31811,31821,31983,31984,36782,32381,32380,32386,32588,32768,33242,33382,34299,34297,34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692,35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912,37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955,39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210,22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570,28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349,34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490,36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370,38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764,39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807,20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489,28753,28760,29568,29924,30090,30318,30316,31155,31840,31839,32894,32893,33247,35186,35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717,38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995,40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348,27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865,35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635,39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321,30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312,37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572,40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313,38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522,39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015,40474,29224,39530,39729,40475,40478,31858,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241,21304,21353,21430,22794,23424,24027,12083,24191,24308,24400,24417,25908,26080,30098,30326,36789,38582,168,710,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,65339,65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,12751,131276,20058,131210,20994,17553,40880,20872,40881,161287,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65506,65508,65287,65282,12849,8470,8481,12443,12444,11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943,11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991,11998,12003,null,null,null,643,592,603,596,629,339,248,331,650,618,20034,20060,20981,21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982,20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568,24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189,20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668,23667,24068,24192,24194,24521,25097,25168,27669,27702,27715,27711,27707,29358,29360,29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232,20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158,21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908,22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031,24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190,25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431,26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278,29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381,35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322,20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321,20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552,21559,21546,21588,21573,21529,21532,21541,21528,21565,21583,21569,21544,21540,21575,22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936,22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693,23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203,24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552,24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219,25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213,25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444,26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787,27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771,27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591,29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912,32914,32924,33424,33423,33413,33422,33425,33427,33418,33411,33412,35960,36809,36799,37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348,20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378,20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894,20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396,21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606,21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381,22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796,22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961,22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716,23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717,23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446,24445,24542,24549,24621,24614,24601,24626,24587,24628,24586,24599,24627,24602,24606,24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261,25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272,25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117,26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502,26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489,26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860,27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828,27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857,28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398,29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606,29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451,30449,30448,30453,30712,30716,30713,30715,30714,30711,31042,31039,31173,31352,31355,31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472,33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441,33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811,36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460,38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411,20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309,21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687,21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680,22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437,22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037,23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021,23464,23628,23760,23768,23756,23767,23755,23771,23774,23770,23753,23751,23754,23766,23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096,24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633,24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612,24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323,25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921,25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170,26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616,26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606,26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598,26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608,27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955,27908,27929,27962,27930,27921,27904,27933,27970,27905,27928,27959,27907,27919,27968,27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833,28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416,29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621,29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023,30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458,30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050,31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488,31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653,32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976,32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313,33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516,33505,33522,33525,33548,33531,33526,33520,33514,33508,33504,33530,33523,33517,34423,34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835,36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332,37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528,20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533,20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082,21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735,21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751,21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470,22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062,23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555,23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238,24234,24236,24371,24368,24423,24669,24666,24679,24641,24738,24712,24704,24722,24705,24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430,25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396,25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930,25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650,26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671,26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656,27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618,27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015,28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034,28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048,28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877,28869,28870,28871,28890,28878,28897,29250,29304,29303,29302,29440,29434,29428,29438,29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660,29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985,30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493,30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764,30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067,31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198,31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493,31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877,32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609,32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018,33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561,33617,33573,33622,33599,33601,33574,33564,33570,33602,33614,33563,33578,33544,33596,33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580,33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455,34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448,34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942,34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278,36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081,37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333,37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574,20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549,20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099,21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812,21802,21841,21858,21814,21813,21808,21842,21829,21772,21810,21861,21838,21817,21832,21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528,22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508,22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876,23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123,23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116,23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838,23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843,23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470,24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797,24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474,25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519,25461,25500,25453,25518,25468,25508,25403,25503,25464,25477,25473,25489,25485,25456,25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780,26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767,26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784,26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537,27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130,28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123,28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115,28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932,28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310,29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470,29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708,29707,29684,29704,30052,30051,30158,30162,30159,30155,30156,30161,30160,30351,30345,30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792,30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075,31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540,31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538,31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069,32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669,32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839,32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063,33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677,33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667,33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702,33671,33710,33654,33690,34393,34390,34495,34487,34498,34497,34501,34490,34480,34504,34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965,34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980,34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897,35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289,36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897,37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210,37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352,37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141,39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636,20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933,21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900,21926,21887,21909,21921,21902,22284,22569,22583,22553,22558,22567,22563,22568,22517,22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587,22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189,23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183,23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875,23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857,23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408,24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854,24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836,24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546,25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555,25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948,25960,25957,25996,26013,26014,26030,26064,26066,26236,26220,26235,26240,26225,26233,26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838,26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804,26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830,26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449,27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156,28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253,28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257,28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260,28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974,28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321,29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478,29475,29493,29452,29742,29740,29744,29739,29718,29722,29729,29741,29745,29732,29731,29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173,30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542,30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832,30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236,31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906,31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092,32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672,32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085,33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595,33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736,33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781,33737,33801,33807,33758,33809,33798,33730,33779,33749,33786,33735,33745,33770,33811,33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534,34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888,34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994,35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392,35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968,36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310,36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590,36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911,37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123,37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388,37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381,37398,38267,38285,38284,38288,38535,38526,38536,38537,38531,38528,38594,38600,38595,38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150,20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657,20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968,21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986,21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601,22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236,23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242,23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882,23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139,24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901,24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124,25541,25585,25579,25616,25618,25609,25632,25636,25651,25667,25631,25621,25624,25657,25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664,25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252,26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978,26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988,26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945,26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940,27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640,28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370,28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380,28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334,28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025,28994,29016,28995,29003,29040,29023,29008,29011,28996,29005,29018,29263,29325,29324,29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771,29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951,29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201,30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560,30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863,30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106,31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395,31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600,31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133,32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615,32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129,33115,33122,33138,26401,33118,33142,33127,33135,33092,33121,33309,33353,33348,33344,33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926,33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850,33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887,33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896,33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518,34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022,35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298,35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457,35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200,36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332,36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609,36608,36613,36615,36616,36610,36619,36946,36927,36932,36937,36925,37136,37133,37135,37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427,37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430,37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303,38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771,38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349,39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723,20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121,21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035,22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655,22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782,22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259,23276,23262,23261,23257,23272,23263,23415,23520,23523,23651,23938,23936,23933,23942,23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153,24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431,24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948,24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677,25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694,25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971,26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030,27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076,27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097,27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587,27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494,28441,28442,28455,28440,28475,28434,28397,28426,28470,28531,28409,28398,28461,28480,28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412,28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071,29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516,29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230,30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592,30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880,30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122,31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644,31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652,31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197,32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174,32169,32161,32201,32627,32738,32739,32741,32734,32804,32861,32860,33161,33158,33155,33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964,33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979,33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952,34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606,34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605,34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577,35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051,35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478,35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362,36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148,37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541,37540,37494,37531,37498,37536,37524,37546,37517,37542,37530,37547,37497,37527,37503,37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529,37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778,38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086,39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601,39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739,20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233,21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067,22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703,22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289,23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968,23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393,24498,24971,24963,24953,25009,25008,24994,24969,24987,24979,25007,25005,24991,24978,25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756,25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979,26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109,27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122,27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140,27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558,27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556,28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503,28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543,28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109,29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522,29534,29535,29536,29533,29531,29537,29530,29529,29538,29831,29833,29834,29830,29825,29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236,30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925,30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136,31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694,31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215,32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685,32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186,33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048,34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060,34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046,34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031,34041,34072,34080,34096,34059,34073,34095,34402,34646,34659,34660,34679,34785,34675,34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655,34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665,34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081,35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541,35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983,36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387,36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376,36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979,36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254,37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617,37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606,37581,37589,37577,37600,37598,37607,37585,37587,37557,37601,37574,37556,38268,38316,38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792,38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162,39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382,39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783,39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191,40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764,20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115,22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716,22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326,23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983,23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989,25000,24982,25029,25012,25030,25025,25036,25018,25023,25016,24972,25815,25814,25808,25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312,26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209,27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199,27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221,27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651,27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618,28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587,28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140,29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542,29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963,30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618,30621,30625,30620,30619,30626,30627,30613,30617,30615,30941,30953,30949,30954,30942,30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416,31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700,31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289,32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278,32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876,33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266,33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148,34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133,34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703,34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705,34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121,35106,35113,35107,35119,35116,35103,35313,35552,35554,35570,35572,35573,35549,35604,35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984,36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416,36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665,36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265,37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667,37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623,37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641,37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569,38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204,39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399,39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804,39806,39803,39810,39827,39826,39824,39802,39829,39805,39816,40229,40215,40224,40222,40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621,40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163,22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738,23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991,24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054,25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286,27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304,27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585,28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153,29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840,29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281,30279,30372,30441,30645,30635,30642,30647,30646,30644,30641,30632,30704,30963,30973,30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318,31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758,31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760,31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297,32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812,33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176,34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185,34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178,34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736,34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762,34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154,35127,35138,35245,35247,35246,35314,35315,35614,35608,35606,35601,35589,35595,35618,35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954,35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675,36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793,37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728,37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729,37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574,38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869,38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219,39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417,39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752,39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243,40257,40295,40246,40238,40239,40241,40248,40240,40261,40258,40259,40254,40247,40256,40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739,40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896,23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072,25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330,26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309,27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667,28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877,29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295,30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994,30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784,31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343,32339,32693,32691,32759,32760,32885,33233,33234,33232,33375,33374,34228,34246,34240,34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225,34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794,34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777,34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626,35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622,35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100,36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449,36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285,37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802,37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812,37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691,38690,38693,38828,38830,38824,38827,38820,38826,38818,38821,38871,38873,38870,38872,38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428,39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754,39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865,39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276,40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745,40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186,22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863,25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345,27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697,28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196,29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891,29974,30304,30665,30666,30660,30705,31005,31003,31009,31004,30999,31006,31152,31335,31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375,32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888,33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263,34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274,34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826,34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254,35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666,35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461,36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184,37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849,37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269,38362,38363,38625,38697,38699,38700,38696,38694,38835,38839,38838,38877,38878,38879,39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335,39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444,39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906,39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330,40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304,40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640,40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755,23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079,26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725,28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737,29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671,30669,30706,31013,31011,31015,31016,31012,31017,31154,31342,31340,31341,31479,31817,31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243,33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313,34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319,35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697,36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899,37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888,37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878,37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010,39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473,39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697,39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945,40351,40345,40356,40349,40338,40344,40336,40347,40352,40340,40348,40362,40343,40353,40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602,40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794,20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883,27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213,29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394,32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335,34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843,34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653,35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189,37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952,37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256,39254,39481,39485,39494,39492,39490,39489,39482,39487,39629,39701,39703,39704,39702,39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374,40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378,40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685,40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897,23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661,28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317,30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401,32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854,34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117,36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962,37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252,39259,39502,39507,39508,39500,39503,39496,39498,39497,39506,39504,39632,39705,39723,39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988,39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425,40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811,40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091,25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570,29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353,34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723,35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852,38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011,40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417,40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690,40691,40710,40732,40760,40759,40758,40771,40783,40817,40816,40814,40815,22227,22221,23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925,30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891,35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629,38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030,40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452,40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418,28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409,33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517,36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045,40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826,40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520,40052,40051,40049,40053,40468,40467,40694,40714,40868,28776,28773,31991,34410,34878,34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524,39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016,38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531,40058,40477,28777,28778,40612,40830,40777,40856,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583,65517,132423,37595,132575,147397,34124,17077,29679,20917,13897,149826,166372,37700,137691,33518,146632,30780,26436,25311,149811,166314,131744,158643,135941,20395,140525,20488,159017,162436,144896,150193,140563,20521,131966,24484,131968,131911,28379,132127,20605,20737,13434,20750,39020,14147,33814,149924,132231,20832,144308,20842,134143,139516,131813,140592,132494,143923,137603,23426,34685,132531,146585,20914,20920,40244,20937,20943,20945,15580,20947,150182,20915,20962,21314,20973,33741,26942,145197,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114,21216,34317,158483,21253,166622,21833,28377,147328,133460,147436,21299,21316,134114,27851,136998,26651,29653,24650,16042,14540,136936,29149,17570,21357,21364,165547,21374,21375,136598,136723,30694,21395,166555,21408,21419,21422,29607,153458,16217,29596,21441,21445,27721,20041,22526,21465,15019,134031,21472,147435,142755,21494,134263,21523,28793,21803,26199,27995,21613,158547,134516,21853,21647,21668,18342,136973,134877,15796,134477,166332,140952,21831,19693,21551,29719,21894,21929,22021,137431,147514,17746,148533,26291,135348,22071,26317,144010,26276,26285,22093,22095,30961,22257,38791,21502,22272,22255,22253,166758,13859,135759,22342,147877,27758,28811,22338,14001,158846,22502,136214,22531,136276,148323,22566,150517,22620,22698,13665,22752,22748,135740,22779,23551,22339,172368,148088,37843,13729,22815,26790,14019,28249,136766,23076,21843,136850,34053,22985,134478,158849,159018,137180,23001,137211,137138,159142,28017,137256,136917,23033,159301,23211,23139,14054,149929,23159,14088,23190,29797,23251,159649,140628,15749,137489,14130,136888,24195,21200,23414,25992,23420,162318,16388,18525,131588,23509,24928,137780,154060,132517,23539,23453,19728,23557,138052,23571,29646,23572,138405,158504,23625,18653,23685,23785,23791,23947,138745,138807,23824,23832,23878,138916,23738,24023,33532,14381,149761,139337,139635,33415,14390,15298,24110,27274,24181,24186,148668,134355,21414,20151,24272,21416,137073,24073,24308,164994,24313,24315,14496,24316,26686,37915,24333,131521,194708,15070,18606,135994,24378,157832,140240,24408,140401,24419,38845,159342,24434,37696,166454,24487,23990,15711,152144,139114,159992,140904,37334,131742,166441,24625,26245,137335,14691,15815,13881,22416,141236,31089,15936,24734,24740,24755,149890,149903,162387,29860,20705,23200,24932,33828,24898,194726,159442,24961,20980,132694,24967,23466,147383,141407,25043,166813,170333,25040,14642,141696,141505,24611,24924,25886,25483,131352,25285,137072,25301,142861,25452,149983,14871,25656,25592,136078,137212,25744,28554,142902,38932,147596,153373,25825,25829,38011,14950,25658,14935,25933,28438,150056,150051,25989,25965,25951,143486,26037,149824,19255,26065,16600,137257,26080,26083,24543,144384,26136,143863,143864,26180,143780,143781,26187,134773,26215,152038,26227,26228,138813,143921,165364,143816,152339,30661,141559,39332,26370,148380,150049,15147,27130,145346,26462,26471,26466,147917,168173,26583,17641,26658,28240,37436,26625,144358,159136,26717,144495,27105,27147,166623,26995,26819,144845,26881,26880,15666,14849,144956,15232,26540,26977,166474,17148,26934,27032,15265,132041,33635,20624,27129,144985,139562,27205,145155,27293,15347,26545,27336,168348,15373,27421,133411,24798,27445,27508,141261,28341,146139,132021,137560,14144,21537,146266,27617,147196,27612,27703,140427,149745,158545,27738,33318,27769,146876,17605,146877,147876,149772,149760,146633,14053,15595,134450,39811,143865,140433,32655,26679,159013,159137,159211,28054,27996,28284,28420,149887,147589,159346,34099,159604,20935,27804,28189,33838,166689,28207,146991,29779,147330,31180,28239,23185,143435,28664,14093,28573,146992,28410,136343,147517,17749,37872,28484,28508,15694,28532,168304,15675,28575,147780,28627,147601,147797,147513,147440,147380,147775,20959,147798,147799,147776,156125,28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,148087,28971,28997,23176,29002,29038,23708,148325,29007,37730,148161,28972,148570,150055,150050,29114,166888,28861,29198,37954,29205,22801,37955,29220,37697,153093,29230,29248,149876,26813,29269,29271,15957,143428,26637,28477,29314,29482,29483,149539,165931,18669,165892,29480,29486,29647,29610,134202,158254,29641,29769,147938,136935,150052,26147,14021,149943,149901,150011,29687,29717,26883,150054,29753,132547,16087,29788,141485,29792,167602,29767,29668,29814,33721,29804,14128,29812,37873,27180,29826,18771,150156,147807,150137,166799,23366,166915,137374,29896,137608,29966,29929,29982,167641,137803,23511,167596,37765,30029,30026,30055,30062,151426,16132,150803,30094,29789,30110,30132,30210,30252,30289,30287,30319,30326,156661,30352,33263,14328,157969,157966,30369,30373,30391,30412,159647,33890,151709,151933,138780,30494,30502,30528,25775,152096,30552,144044,30639,166244,166248,136897,30708,30729,136054,150034,26826,30895,30919,30931,38565,31022,153056,30935,31028,30897,161292,36792,34948,166699,155779,140828,31110,35072,26882,31104,153687,31133,162617,31036,31145,28202,160038,16040,31174,168205,31188],
      "euc-kr":[44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065,44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084,null,null,null,null,null,null,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099,44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114,44115,44117,null,null,null,null,null,null,44118,44119,44121,44122,44123,44125,44126,44127,44128,44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141,44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162,44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185,44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209,44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229,44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244,44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262,44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287,44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307,44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323,44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339,null,null,null,null,null,null,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354,44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373,44374,44375,null,null,null,null,null,null,44377,44378,44379,44380,44381,44382,44383,44384,44386,44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407,44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429,44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443,44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473,44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490,44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506,44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535,44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558,44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572,null,null,null,null,null,null,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601,44603,44604,null,null,null,null,null,null,44605,44606,44607,44610,44612,44615,44616,44617,44619,44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643,44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661,44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681,44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695,44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738,44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757,44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773,44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790,44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805,null,null,null,null,null,null,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820,44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833,44834,44835,null,null,null,null,null,null,44836,44837,44838,44839,44840,44841,44842,44843,44846,44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868,44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884,44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914,44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929,44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946,44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990,44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010,45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025,null,null,null,null,null,null,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038,45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055,45058,45059,null,null,null,null,null,null,45061,45062,45063,45064,45065,45066,45067,45069,45070,45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101,45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114,45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131,45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152,45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178,45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195,45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220,45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246,45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266,null,null,null,null,null,null,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279,45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294,45295,45296,null,null,null,null,null,null,45297,45298,45299,45300,45301,45302,45303,45304,45305,45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318,45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343,45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361,45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382,45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401,45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447,45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469,45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483,45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496,null,null,null,null,null,null,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522,45523,45525,null,null,null,null,null,null,45526,45527,45528,45529,45530,45531,45534,45536,45537,45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554,45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570,45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590,45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619,45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634,45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662,45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678,45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694,45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710,null,null,null,null,null,null,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727,45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749,45750,45751,null,null,null,null,null,null,45752,45753,45754,45755,45756,45757,45758,45759,45760,45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777,45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799,45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830,45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849,45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876,45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923,45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946,45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965,null,null,null,null,null,null,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994,45995,45997,null,null,null,null,null,null,45998,45999,46000,46001,46002,46003,46004,46005,46006,46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044,46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102,46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118,46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135,46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163,46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182,null,null,null,null,null,null,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46209,46210,null,null,null,null,null,null,46211,46212,46213,46214,46215,46217,46218,46219,46220,46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233,46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249,46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266,46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282,46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297,46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318,46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334,46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347,46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365,46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386,46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406,null,null,null,null,null,null,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422,46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440,46441,46442,null,null,null,null,null,null,46443,46444,46445,46446,46447,46448,46449,46450,46451,46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477,46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490,46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509,46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531,46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550,46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564,46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578,46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604,46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621,null,null,null,null,null,null,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633,46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648,46649,46650,null,null,null,null,null,null,46651,46652,46653,46654,46655,46656,46657,46658,46659,46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686,46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701,46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727,46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740,46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757,46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773,46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813,null,null,null,null,null,null,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824,46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839,46841,46842,null,null,null,null,null,null,46843,46844,46845,46846,46847,46850,46851,46852,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898,46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914,46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930,46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946,46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964,46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982,46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006,47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025,47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041,null,null,null,null,null,null,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054,47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067,47068,47069,null,null,null,null,null,null,47070,47071,47072,47073,47074,47075,47076,47077,47078,47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095,47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117,47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135,47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152,47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186,47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203,47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221,47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236,47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250,47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,null,null,null,null,null,null,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275,47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291,47292,47293,null,null,null,null,null,null,47294,47295,47298,47300,47302,47303,47304,47305,47306,47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322,47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341,47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359,47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373,47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387,47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414,47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431,47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447,47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466,47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485,null,null,null,null,null,null,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503,47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516,47517,47518,null,null,null,null,null,null,47519,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544,47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563,47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591,47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612,47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628,47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642,47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655,47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668,47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686,47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709,47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727,null,null,null,null,null,null,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742,47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760,47761,47762,null,null,null,null,null,null,47763,47764,47765,47766,47767,47768,47769,47770,47771,47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786,47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807,47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837,47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850,47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863,47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879,47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895,47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911,47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930,47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954,null,null,null,null,null,null,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967,47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983,47984,47985,null,null,null,null,null,null,47986,47987,47988,47989,47990,47991,47992,47993,47994,47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007,48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023,48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037,48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053,48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069,48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085,48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129,48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160,48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181,null,null,null,null,null,null,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198,48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215,48216,48217,null,null,null,null,null,null,48218,48219,48220,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253,48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272,48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293,48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313,48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330,48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350,48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363,48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381,48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398,48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413,null,null,null,null,null,null,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425,48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439,48440,48441,null,null,null,null,null,null,48442,48443,48444,48445,48446,48447,48449,48450,48451,48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468,48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483,48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511,48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535,48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566,48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593,48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610,48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625,null,null,null,null,null,null,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638,48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657,48658,48659,null,null,null,null,null,null,48661,48662,48663,48664,48665,48666,48667,48670,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685,48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714,48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735,48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758,48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776,48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796,48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810,48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823,48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836,48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851,null,null,null,null,null,null,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866,48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883,48884,48885,null,null,null,null,null,null,48886,48887,48888,48889,48890,48891,48892,48893,48894,48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910,48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928,48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941,48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954,48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971,48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026,49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039,49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053,null,null,null,null,null,null,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078,49079,49080,null,null,null,null,null,null,49081,49082,49083,49084,49085,49086,49087,49088,49089,49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106,49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123,49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136,49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149,49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162,49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188,49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228,49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243,null,null,null,null,null,null,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258,49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,null,null,null,null,null,null,49274,49275,49276,49277,49278,49279,49280,49281,49282,49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295,49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314,49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337,49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359,49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378,49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395,49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414,49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430,49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454,49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475,49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495,null,null,null,null,null,null,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510,49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529,49530,49531,null,null,null,null,null,null,49532,49533,49534,49535,49536,49537,49538,49539,49540,49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560,49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581,49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595,49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611,49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628,49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644,49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662,49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680,49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699,49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,null,null,null,null,null,null,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747,49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763,49764,49766,null,null,null,null,null,null,49767,49768,49769,49770,49771,49774,49775,49777,49778,49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796,49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812,49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830,49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850,49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863,49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876,49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894,49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917,49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935,49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953,49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970,null,null,null,null,null,null,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995,49996,49997,null,null,null,null,null,null,49998,49999,50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019,50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037,50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055,50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070,50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083,50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096,50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109,50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123,50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138,50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158,50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174,null,null,null,null,null,null,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186,50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200,50201,50202,null,null,null,null,null,null,50203,50204,50205,50206,50207,50208,50209,50210,50211,50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227,50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243,50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257,50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270,50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287,50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303,50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317,50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331,50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358,50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373,null,null,null,null,null,null,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,null,null,null,null,null,null,50400,50401,50402,50403,50404,50405,50406,50407,50408,50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427,50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459,50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475,50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494,50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518,50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540,50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561,50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580,50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598,50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614,null,null,null,null,null,null,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642,50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660,50662,50663,null,null,null,null,null,null,50664,50665,50666,50667,50671,50673,50674,50675,50677,50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703,50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721,50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746,50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764,50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785,50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800,50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818,50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835,50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854,50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875,50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894,null,null,null,null,null,null,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907,50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927,50929,50930,null,null,null,null,null,null,50931,50932,50933,50934,50935,50938,50939,50940,50942,50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959,50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978,50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996,50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015,51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042,51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057,51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083,51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106,51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127,51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147,51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164,null,null,null,null,null,null,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178,51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192,51193,51194,null,null,null,null,null,null,51195,51196,51197,51198,51199,51202,51203,51205,51206,51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226,51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243,51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262,51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280,51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307,51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325,51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347,51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364,51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378,51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393,null,null,null,null,null,null,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407,51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426,51427,51429,null,null,null,null,null,null,51430,51431,51432,51433,51434,51435,51436,51437,51438,51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454,51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504,65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595,8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834,8835,8746,8745,8743,8744,65506,51472,51474,51475,51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,null,null,null,null,null,null,51501,51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515,51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,null,null,null,null,null,null,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542,51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559,51560,51561,51562,51563,51565,51566,51567,8658,8660,8704,8707,180,65374,711,728,733,730,729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828,9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639,9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600,9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51569,51570,51571,51573,51574,51575,51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589,51590,51591,51594,51595,51597,51598,51599,null,null,null,null,null,null,51601,51602,51603,51604,51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,51628,51629,51630,null,null,null,null,null,null,51631,51632,51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645,51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666,51668,51671,51672,51675,65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,51678,51679,51681,51683,51685,51686,51688,51689,51690,51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711,51713,51714,51715,51716,null,null,null,null,null,null,51717,51718,51719,51722,51726,51727,51728,51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,null,null,null,null,null,null,51750,51751,51752,51754,51755,51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768,51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781,51782,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,12686,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798,51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817,51818,null,null,null,null,null,null,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828,51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842,51843,51845,51846,null,null,null,null,null,null,51847,51848,51849,51850,51851,51852,51853,51854,51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868,51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,null,null,null,null,null,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,51880,51881,51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894,51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,null,null,null,null,null,null,51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927,51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943,null,null,null,null,null,null,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955,51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969,51970,51971,51972,51973,51974,51975,51977,51978,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490,9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514,9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541,9542,9543,9544,9545,9546,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51979,51980,51981,51982,51983,51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999,52002,52003,52004,52005,52006,52007,52008,52009,null,null,null,null,null,null,52010,52011,52012,52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025,52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,null,null,null,null,null,null,52037,52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054,52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071,52072,52073,52074,52075,52076,13205,13206,13207,8467,13208,13252,13219,13220,13221,13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197,13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244,13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195,13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264,13267,13251,13257,13276,13254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52077,52078,52079,52080,52081,52082,52083,52084,52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099,52100,52101,52102,52103,52104,null,null,null,null,null,null,52105,52106,52107,52108,52109,52110,52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123,52125,52126,52127,52128,52129,52130,52131,null,null,null,null,null,null,52132,52133,52134,52135,52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148,52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162,52163,52164,198,208,170,294,null,306,null,319,321,216,338,186,222,358,330,null,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,189,8531,8532,188,190,8539,8540,8541,8542,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175,52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189,52190,52191,null,null,null,null,null,null,52192,52193,52194,52195,52197,52198,52200,52202,52203,52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216,52217,52218,52219,52220,null,null,null,null,null,null,52221,52222,52223,52224,52225,52226,52227,52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243,52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,230,273,240,295,305,307,312,320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,52261,52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282,52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,null,null,null,null,null,null,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319,52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337,52338,null,null,null,null,null,null,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,52372,52373,52374,52375,52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394,52398,52399,52400,52401,52402,52403,52406,52407,52409,null,null,null,null,null,null,52410,52411,52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429,52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,null,null,null,null,null,null,52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456,52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471,52472,52473,52474,52475,52476,52477,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,52478,52479,52480,52482,52483,52484,52485,52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502,52503,52506,52508,52510,52511,52512,null,null,null,null,null,null,52513,52514,52515,52517,52518,52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533,52534,52535,52536,52538,52539,52540,52541,52542,null,null,null,null,null,null,52543,52544,52545,52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558,52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571,52573,52574,52575,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587,52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605,52606,52607,52608,null,null,null,null,null,null,52609,52610,52611,52612,52613,52614,52615,52617,52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633,52634,52635,52637,52638,52639,null,null,null,null,null,null,52640,52641,52642,52643,52646,52648,52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663,52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692,52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705,null,null,null,null,null,null,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718,52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736,52737,52738,null,null,null,null,null,null,52739,52741,52742,52743,52745,52746,52747,52749,52750,52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765,52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52780,52781,52782,52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,null,null,null,null,null,null,52810,52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823,52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,null,null,null,null,null,null,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861,52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878,52879,52882,52883,52885,52886,52887,52889,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52890,52891,52892,52893,52894,52895,52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,null,null,null,null,null,null,52923,52924,52925,52926,52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,52941,52942,52943,52944,52945,52946,52947,52948,52949,null,null,null,null,null,null,52950,52951,52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966,52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987,52988,52989,52990,52991,44032,44033,44036,44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057,44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089,44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154,44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188,44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219,44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264,44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294,52994,52995,52997,52998,52999,53001,53002,53003,53004,53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022,53023,53025,53026,53027,null,null,null,null,null,null,53029,53030,53031,53032,53033,53034,53035,53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53060,null,null,null,null,null,null,53061,53062,53063,53064,53065,53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081,53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099,53100,44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344,44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400,44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428,44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508,44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564,44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620,44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649,44652,44656,44664,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116,53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131,53133,null,null,null,null,null,null,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157,53158,53159,53161,null,null,null,null,null,null,53162,53163,53164,53165,53166,53167,53169,53170,53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183,53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734,44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781,44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860,44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921,44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000,45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056,45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132,45134,45139,45140,45141,45143,45145,53196,53197,53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210,53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,null,null,null,null,null,null,53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242,53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258,null,null,null,null,null,null,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270,53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284,53285,53286,53287,53288,53289,53290,53291,53292,45149,45180,45181,45184,45188,45196,45197,45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227,45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255,45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328,45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364,45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400,45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459,45460,45464,45468,45480,45516,45520,45524,45532,45533,53294,53295,53296,53297,53298,53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315,53318,53320,53322,53323,53324,53325,53326,53327,null,null,null,null,null,null,53329,53330,53331,53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347,53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,null,null,null,null,null,null,53361,53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378,53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391,53392,53393,53394,53395,53396,45535,45544,45545,45548,45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593,45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701,45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738,45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794,45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815,45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844,45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,53397,53398,53399,53400,53401,53402,53403,53404,53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421,53422,53423,53424,53425,53426,null,null,null,null,null,null,53427,53430,53432,53434,53435,53436,53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454,53455,53458,53462,53463,53464,53465,53466,null,null,null,null,null,null,53467,53470,53471,53473,53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492,53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506,53507,53508,45927,45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964,45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032,46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108,46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181,46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280,46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328,46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385,46388,46392,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520,53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533,53534,53535,null,null,null,null,null,null,53536,53537,53538,53539,53540,53541,53542,53543,53544,53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561,53563,53564,53565,53566,null,null,null,null,null,null,53567,53570,53574,53575,53576,53577,53578,53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595,53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428,46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515,46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552,46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749,46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888,46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944,46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991,46992,46993,46994,46998,46999,53614,53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627,53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,null,null,null,null,null,null,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670,53671,null,null,null,null,null,null,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686,53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702,53703,53704,53705,53706,53707,53708,53709,53710,53711,47000,47001,47004,47008,47016,47017,47019,47020,47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103,47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141,47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197,47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288,47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340,47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436,47439,47441,47448,47449,47452,47456,47464,47465,53712,53713,53714,53715,53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729,53730,53731,53732,53733,53734,53735,53736,53737,53738,null,null,null,null,null,null,53739,53740,53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755,53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,null,null,null,null,null,null,53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782,53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,53799,53800,53801,47467,47469,47476,47477,47480,47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548,47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577,47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608,47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689,47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721,47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788,47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,53802,53803,53806,53807,53809,53810,53811,53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829,53830,53831,53833,53834,53835,53836,null,null,null,null,null,null,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855,53856,53857,53858,53859,53861,53862,53863,53864,null,null,null,null,null,null,53865,53866,53867,53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897,53898,53899,53900,47872,47876,47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931,47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969,47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072,48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141,48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164,48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197,48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277,48279,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913,53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929,53930,53931,53933,null,null,null,null,null,null,53934,53935,53936,53938,53939,53940,53941,53942,53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964,53965,53966,53967,53968,53969,null,null,null,null,null,null,53970,53971,53973,53974,53975,53977,53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993,53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309,48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373,48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456,48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521,48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597,48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660,48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730,48731,48736,48737,48740,54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027,54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051,null,null,null,null,null,null,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067,54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087,54088,54089,null,null,null,null,null,null,54090,54091,54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,48744,48746,48752,48753,48755,48756,48757,48763,48764,48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849,48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921,48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093,49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256,49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328,49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356,49360,49368,49369,49371,49372,49373,49380,54122,54123,54124,54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137,54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,null,null,null,null,null,null,54152,54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173,54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,null,null,null,null,null,null,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205,54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222,54223,54225,54226,54227,54228,54229,54230,49381,49384,49388,49396,49397,49399,49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444,49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480,49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513,49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567,49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624,49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679,49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,54231,54233,54234,54235,54236,54237,54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254,54255,54257,54258,54259,54261,54262,54263,null,null,null,null,null,null,54264,54265,54266,54267,54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,null,null,null,null,null,null,54295,54296,54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310,54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323,54324,54325,54326,54327,49711,49713,49714,49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788,49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836,49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901,49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939,49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032,50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143,50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224,54328,54329,54330,54331,54332,54333,54334,54335,54337,54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,null,null,null,null,null,null,54356,54357,54358,54359,54360,54361,54362,54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378,54379,54380,54382,54384,54385,54386,null,null,null,null,null,null,54387,54388,54389,54390,54391,54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414,54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428,54429,50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324,50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444,50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501,50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525,50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560,50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612,50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633,50634,50636,50638,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442,54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455,54456,null,null,null,null,null,null,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466,54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481,54482,54483,54485,null,null,null,null,null,null,54486,54487,54488,54489,54490,54491,54493,54494,54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510,54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669,50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694,50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733,50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768,50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812,50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857,50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896,50900,50908,50909,50912,50913,50920,54526,54527,54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543,54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,null,null,null,null,null,null,54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583,null,null,null,null,null,null,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598,54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615,54618,54619,54621,54622,54623,54625,54626,54627,50921,50924,50928,50936,50937,50941,50948,50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993,50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026,51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064,51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089,51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117,51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160,51165,51172,51176,51180,51200,51201,51204,51208,51210,54628,54630,54631,54634,54636,54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654,54655,54656,54657,54658,54659,54662,54666,54667,null,null,null,null,null,null,54668,54669,54670,54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,null,null,null,null,null,null,54696,54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709,54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722,54723,54724,54725,54726,54727,51216,51217,51219,51221,51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272,51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333,51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396,51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456,51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540,51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608,51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,54730,54731,54733,54734,54735,54737,54739,54740,54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759,54761,54762,54763,54765,54766,null,null,null,null,null,null,54767,54768,54769,54770,54771,54774,54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793,54794,54795,54796,54797,54798,54799,54802,null,null,null,null,null,null,54806,54807,54808,54809,54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825,54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839,54842,54843,51669,51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696,51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753,51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864,51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948,51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056,52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237,52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280,52281,52283,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860,54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879,54880,54881,null,null,null,null,null,null,54882,54883,54884,54885,54886,54888,54890,54891,54892,54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54911,54912,null,null,null,null,null,null,54913,54914,54916,54918,54919,54920,54921,54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938,54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312,52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393,52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436,52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516,52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628,52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716,52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772,52776,52784,52785,52787,52789,54955,54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972,54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,null,null,null,null,null,null,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004,55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020,55021,null,null,null,null,null,null,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033,55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050,55051,55052,55053,55054,55055,55056,55058,55059,55060,52824,52825,52828,52831,52832,52833,52840,52841,52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884,52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971,52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011,53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080,53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153,53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248,53252,53265,53272,53293,53300,53301,53304,53308,55061,55062,55063,55066,55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084,55086,55087,55088,55089,55090,55091,55094,55095,55097,null,null,null,null,null,null,55098,55099,55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116,55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,null,null,null,null,null,null,55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154,55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171,55172,55173,55174,55175,55178,55179,53316,53317,53319,53321,53328,53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416,53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459,53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517,53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584,53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668,53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769,53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,55181,55182,55183,55185,55186,55187,55188,55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,53860,53888,53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945,53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000,54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038,54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075,54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161,54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213,54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271,54273,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396,54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492,54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551,54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629,54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665,54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757,54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803,54804,54805,54812,54816,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54820,54829,54840,54841,54844,54848,54853,54856,54857,54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915,54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971,54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029,55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085,55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128,55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176,55177,55180,55184,55192,55193,55195,55197,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20285,20339,20551,20729,21152,21487,21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292,33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508,24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014,24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487,31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883,35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204,28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21283,23724,30002,32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743,30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477,40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117,30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923,32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067,36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967,33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608,33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963,40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772,20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950,25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898,30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629,36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760,25106,26690,26800,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336,35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235,25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660,32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678,38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372,23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844,20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002,38799,20018,23521,25096,26524,29916,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31185,33747,35463,35506,36328,36942,37707,38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748,29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866,20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979,21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439,32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657,27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171,39509,39851,19992,20037,20061,20167,20465,20855,21246,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21312,21475,21477,21646,22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472,27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777,33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378,39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676,35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524,20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152,36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,39740,63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215,36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067,21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822,31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278,29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201,27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120,22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216,26071,26083,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103,29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098,31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668,39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931,20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762,63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262,63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275,63778,30007,63779,63780,63781,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32013,63782,63783,34930,22218,23064,63784,63785,63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754,31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792,63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803,63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786,24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823,63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021,63832,63833,23612,27877,21311,28346,22810,33590,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20025,20150,20294,21934,22296,22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962,37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129,28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035,31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739,40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274,34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615,23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26873,27330,28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339,36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544,30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129,35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847,27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168,31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471,23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313,32645,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226,39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888,25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266,26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504,30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635,37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268,34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722,24976,25088,25891,28451,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29001,29833,32244,32879,34030,36646,36899,37706,20925,21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278,22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646,38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347,28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565,30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903,31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534,24278,26009,29134,30274,30637,32842,34044,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36988,39719,40845,22744,23105,23650,27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611,27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134,38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202,32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774,23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633,32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298,36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31435,31520,31890,25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707,37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771,30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178,38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017,22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993,39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906,35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719,37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286,26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584,35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406,33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672,21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687,30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006,21563,21839,25991,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289,21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859,32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108,27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615,25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843,38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504,29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930,39151,21187,25300,25765,28196,28497,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30332,36299,37297,37474,39662,39747,20515,20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036,28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450,40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972,32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658,30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132,20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539,27861,29754,20731,21128,22721,25816,27287,29863,30294,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30887,34327,38370,38713,63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482,20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647,39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995,33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119,33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857,23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586,40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23386,23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566,33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096,37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575,24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847,20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269,21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604,27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203,32737,32933,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131,40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007,36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351,20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556,24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863,28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293,33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391,40605,21066,63849,26388,63850,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20632,21034,23665,25955,27733,29642,29987,30109,31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862,28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830,21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248,29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684,22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513,22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360,26646,26866,29312,29790,31598,32110,32214,32626,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32997,33298,34223,35199,35475,36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101,28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159,25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680,33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352,23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089,26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995,23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32854,32882,33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484,22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040,28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057,34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463,28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575,23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782,34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101,24833,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159,29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353,32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228,37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654,22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490,24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020,33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899,36848,37477,23815,23847,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23913,29791,33181,34664,28629,25342,32722,35126,35186,19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070,22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612,29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516,23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135,39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070,32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833,23460,23526,24713,23529,23563,24515,27777,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63858,28145,28683,29978,33455,35574,20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273,33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997,24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736,25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813,23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830,24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861,33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27387,32588,40367,40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369,63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756,23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162,30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178,22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233,27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196,22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878,39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377,35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888,25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982,29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895,34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037,63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976,29744,33398,33490,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913,22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214,28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310,32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034,20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306,63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425,20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034,25942,26111,26212,26791,27738,28595,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28879,29100,29522,31613,34568,35492,39986,40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800,22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402,33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740,30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505,27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931,20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747,25854,63934,26332,63935,27208,63936,29183,29796,63937,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31368,31407,32327,32350,32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020,32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029,28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854,63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962,26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398,36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020,31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36939,38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290,22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503,29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301,20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239,32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369,20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840,24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946,28216,63947,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173,33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321,37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609,63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963,32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577,20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210,40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681,33380,34191,34811,34915,35516,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,35696,37291,20108,20197,20234,63965,63966,22839,23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972,30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029,36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764,35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270,63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968,20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641,63988,63989,31252,63990,33615,36035,20837,21316,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63991,63992,63993,20173,21097,23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363,28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566,36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196,38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870,38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484,26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144,33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38556,20877,21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001,36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213,25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785,33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490,25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627,36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856,21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656,28593,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438,36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240,27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822,40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128,24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273,27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855,31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478,37580,37664,38662,38742,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38748,38914,40718,21046,21137,21884,22564,24093,24351,24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500,38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805,26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226,29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299,34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751,36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837,28121,29742,31278,32066,32156,32305,33131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36394,36405,37758,37912,20304,22352,24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014,22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855,29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659,36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803,26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423,33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366,25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21675,22320,22336,24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460,30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996,36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634,26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433,30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914,37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209,31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425,27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015,40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106,38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921,25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884,25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750,33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365,20874,26613,31574,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957,25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912,22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351,38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941,20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086,25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531,38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021,21119,21736,24980,25220,25307,26786,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26898,26970,27189,28818,28966,30813,30977,30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294,20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541,24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277,25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138,37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569,31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668,20805,24544,27798,34802,34909,34935,24756,33205,33795,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36101,21462,21561,22068,23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164,21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100,29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601,39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784,28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702,22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828,22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37944,21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506,30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488,22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004,25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570,32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879,39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966,29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009,36774,37393,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260,29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255,31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536,23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263,21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770,32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292,26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080,34920,35961,39111,39108,39491,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21697,31263,26963,35575,35914,39080,39342,24444,25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091,31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781,33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680,24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106,36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569,21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658,25239,26477,26689,27782,28207,32568,32923,33322,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,64008,64009,38917,20133,20565,21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559,36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190,29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563,36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203,27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010,36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406,28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24418,27842,28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795,39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628,22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246,28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286,32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785,25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344,27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779,30069,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906,30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185,29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140,24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004,29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458,24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588,34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989,26313,26783,28045,28102,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29243,32948,37237,39501,20399,20505,21402,21518,21564,21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932,29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585,24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407,24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165,21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694,20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081,29113,29114,29351,31143,31232,32690,35440,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
      "gb18030":[19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009,20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042,20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075,20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,20112,20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150,20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187,20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217,20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236,20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269,20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292,20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326,20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349,20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373,20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400,20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414,20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436,20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466,20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,20494,20496,20497,20499,20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527,20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543,20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562,20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578,20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593,20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612,20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661,20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690,20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724,20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20744,20745,20746,20748,20749,20750,20751,20752,20753,20755,20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823,20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841,20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878,20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902,20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929,20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950,20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968,20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003,21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029,21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061,21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100,21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133,21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156,21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197,21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214,21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229,21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245,21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267,21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291,21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308,21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339,21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374,21376,21377,21379,21383,21384,21386,21390,21391,21392,21393,21394,21395,21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419,21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434,21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458,21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503,21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541,21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575,21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603,21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626,21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655,21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686,21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728,21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751,21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772,21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790,21791,21793,21797,21798,21800,21801,21803,21805,21810,21812,21813,21814,21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837,21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854,21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876,21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909,21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928,21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946,21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967,21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997,21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019,22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037,22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057,22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095,22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133,22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151,22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195,22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224,22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248,22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272,22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306,22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332,22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356,22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386,22388,22389,22392,22393,22394,22397,22398,22399,22400,22401,22407,22408,22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425,22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451,22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468,22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487,22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507,22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527,22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547,22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566,22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613,22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628,22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662,22663,22664,22666,22667,22668,22669,22670,22671,22672,22673,22676,22677,22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694,22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739,22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772,22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789,22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808,22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835,22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861,22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901,22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927,22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946,22950,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968,22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985,22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010,23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051,23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069,23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087,23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106,23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137,23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153,23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,23213,23214,23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232,23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249,23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271,23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358,23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406,23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430,23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468,23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496,23497,23498,23499,23501,23502,23503,23505,23508,23509,23510,23511,23512,23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532,23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554,23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577,23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598,23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629,23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652,23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670,23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689,23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716,23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738,23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756,23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771,23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806,23807,23808,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823,23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840,23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859,23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875,23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892,23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009,24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,24048,24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074,24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100,24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118,24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139,24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156,24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197,24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228,24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251,24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267,24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300,24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317,24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346,24348,24349,24350,24353,24354,24355,24356,24360,24363,24364,24366,24368,24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399,24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424,24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451,24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479,24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497,24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514,24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543,24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566,24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599,24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626,24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646,24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664,24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693,24695,24702,24704,24705,24706,24709,24710,24711,24712,24714,24715,24718,24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740,24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765,24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782,24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803,24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831,24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852,24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873,24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901,24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920,24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937,24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995,24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028,25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089,25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120,25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142,25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173,25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189,25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219,25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244,25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267,25268,25270,25271,25272,25274,25278,25280,25281,25283,25291,25295,25297,25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337,25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360,25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389,25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407,25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432,25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452,25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473,25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498,25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525,25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546,25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565,25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585,25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608,25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629,25631,25634,25635,25636,25637,25639,25640,25641,25643,25646,25647,25648,25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666,25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687,25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702,25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718,25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738,25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756,25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775,25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796,25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814,25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860,25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875,25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905,25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927,25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951,25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971,25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005,26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030,26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048,26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073,26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099,26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119,26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162,26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182,26183,26184,26185,26186,26189,26190,26192,26193,26200,26201,26203,26204,26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225,26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245,26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261,26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277,26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294,26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339,26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358,26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382,26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402,26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425,26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452,26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475,26476,26478,26481,26484,26486,26488,26489,26490,26491,26493,26496,26498,26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516,26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546,26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593,26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615,26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640,26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659,26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676,26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736,26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752,26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770,26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821,26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839,26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875,26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892,26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926,26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944,26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977,26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995,26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019,27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055,27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,27070,27071,27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089,27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120,27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165,27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182,27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200,27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215,27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232,27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263,27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279,27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295,27297,27298,27299,27300,27301,27302,27303,27304,27306,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451,27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484,27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520,27525,27528,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545,27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561,27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579,27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598,27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621,27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639,27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657,27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691,27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715,27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736,27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761,27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787,27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808,27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842,27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,27865,27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897,27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921,27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940,27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967,27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999,28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019,28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038,28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060,28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091,28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112,28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135,28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157,28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175,28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200,28202,28204,28206,28208,28209,28211,28213,28214,28215,28217,28219,28220,28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235,28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305,28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321,28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344,28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364,28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408,28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424,28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460,28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479,28480,28481,28482,28483,28484,28485,28488,28489,28490,28492,28494,28495,28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511,28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528,28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546,28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580,28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612,28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701,28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728,28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791,28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812,28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853,28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894,28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917,28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933,28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969,28970,28971,28972,28973,28974,28978,28979,28980,28981,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999,29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034,29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052,29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068,29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085,29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102,29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118,29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148,29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164,29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179,29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,29210,29211,29212,29214,29215,29216,29217,29218,29219,29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242,29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262,29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283,29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303,29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326,29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355,29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381,29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400,29402,29403,58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578,58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,12288,12289,12290,183,713,711,168,12291,12293,8212,65374,8214,8230,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712,8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800,8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164,65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,8251,8594,8592,8593,8595,12307,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,59238,59239,59240,59241,59242,59243,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,8364,59245,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,59246,59247,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,59248,59249,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796,58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,12288,65281,65282,65283,65509,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,58854,58855,58856,58857,58858,58859,58860,58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58913,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58924,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950,58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040,59041,59042,59043,59044,59045,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,59261,59262,59263,59264,59265,59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094,59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132,59133,59134,59135,59136,59137,59138,59139,59140,59141,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,59269,59270,59271,59272,59273,59274,59275,59276,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,59277,59278,59279,59280,59281,59282,59283,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092,59284,59285,65083,65084,65079,65080,65073,59286,65075,65076,59287,59288,59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147,59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160,59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173,59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199,59200,59201,59202,59203,59204,59205,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,59296,59297,59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,59311,59312,59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,714,715,729,8211,8213,8229,8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737,8853,12306,12317,12318,59324,59325,59326,59327,59328,59329,59330,59331,59332,59333,59334,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,234,593,7743,324,328,505,609,59337,59338,59339,59340,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,59341,59342,59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,12321,12322,12323,12324,12325,12326,12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265,13266,13269,65072,65506,65508,59362,8481,12849,59363,8208,59364,59365,59366,12540,12443,12444,12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65128,65129,65130,65131,12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283,12295,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,29404,29405,29407,29410,29411,29412,29413,29414,29415,29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446,29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465,29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491,29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525,29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570,29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589,29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606,29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629,29630,29631,29633,29635,29636,29637,29638,29639,29643,29644,29646,29650,29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666,29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684,29685,29686,29687,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717,29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735,29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758,29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806,29807,29809,29810,29811,29812,29813,29816,29817,29818,57532,57533,57534,57535,57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,29819,29820,29821,29823,29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858,29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914,29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936,29937,29938,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953,29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970,29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990,29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020,30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059,30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076,30077,30078,30080,30081,30082,30084,30085,30087,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,30088,30089,30090,30092,30093,30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121,30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158,30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181,30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203,30205,30206,30210,30212,30214,30215,30216,30217,30219,30221,30222,30223,30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248,30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274,30276,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290,30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308,30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323,30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345,30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377,30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394,30395,30396,30397,30398,30400,30401,30403,21834,38463,22467,25384,21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688,23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100,32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843,30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575,30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495,29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152,32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,30404,30407,30409,30411,30412,30419,30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439,30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459,30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499,30500,30501,30503,30506,30507,30508,30510,30512,30513,30514,30515,30516,30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539,30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556,34180,38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865,24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987,22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604,37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381,25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153,20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971,21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177,39292,28851,30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595,30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635,30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,30652,30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682,30685,30686,30687,30688,30689,30692,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615,38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754,34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165,36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808,28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574,20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519,23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130,20135,38416,39076,26124,29462,30694,30696,30698,30703,30704,30705,30706,30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728,30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754,30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783,30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803,30804,30808,30809,30810,30811,30812,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837,30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,22330,23581,24120,38271,20607,32928,21378,25950,30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710,25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472,36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802,25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827,40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277,37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986,27249,21416,36487,38148,38607,28353,38500,26970,30852,30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877,30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895,30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916,30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936,30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966,30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983,30984,30985,30986,30987,30988,30784,20648,30679,25616,35302,22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202,38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431,34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050,36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419,36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384,23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823,21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,30989,30990,30991,30992,30993,30994,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011,31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045,31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064,31065,31073,31075,31076,31078,31081,31082,31083,31084,31086,31088,31089,31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107,31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,24608,32829,25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377,34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548,21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634,20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269,24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857,20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500,38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853,21472,31123,31124,31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175,31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195,31196,31197,31198,31200,31201,31202,31205,31208,31210,31212,31214,31217,31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236,31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254,31256,31257,31259,31260,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908,33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910,36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208,32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431,23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810,22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420,39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819,23572,39285,27953,20108,31261,31263,31265,31266,31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286,31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306,31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347,31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374,31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,36144,21457,32602,31567,20240,20047,38400,27861,29648,34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539,36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775,32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832,36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221,24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898,20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282,36752,24133,27679,31526,20239,20440,26381,31395,31396,31399,31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465,31466,31467,31468,31470,31472,31473,31474,31475,31476,31477,31478,31479,31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502,31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523,31527,31529,31533,28014,28074,31119,34993,24343,29995,25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171,22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648,22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487,32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703,28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733,27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548,38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549,31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573,31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613,31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630,31631,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648,31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674,31675,31676,31677,31678,31679,31680,31682,31683,31684,22466,32831,26775,24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329,36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735,21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925,39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874,20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891,29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588,36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704,31685,31688,31689,31690,31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708,31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727,31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744,31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761,31762,31763,31764,31765,31767,31768,31769,31770,31771,31772,31773,31774,31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805,31806,31810,39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085,23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721,22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621,21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088,36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178,34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399,29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676,29392,31946,28246,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863,31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897,31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919,31920,31924,31925,31926,31927,31928,31930,31931,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326,29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615,26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618,24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854,28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214,36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985,28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334,22522,26426,30072,31293,31215,31637,31935,31936,31938,31939,31940,31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963,31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980,31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32011,32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037,32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053,32054,32908,39269,36857,28608,35749,40481,23020,32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363,23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058,24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025,26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215,26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392,22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943,33616,27099,37492,36341,36145,35265,38190,31661,20214,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,32150,32151,32152,20581,33328,21073,39279,28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870,35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556,23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119,25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130,21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249,33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941,35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,32153,32154,32155,32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172,32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,23613,21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117,35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928,28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937,26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738,23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191,20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733,25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891,21531,23803,32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577,26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179,25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063,31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691,22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391,33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555,23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743,31397,33909,22862,39745,20608,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,32412,32413,32414,32430,32436,32443,32444,32470,32484,32492,32505,32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,39304,24871,28291,22372,26118,25414,22256,25324,25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182,34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518,28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769,20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769,22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729,29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029,21385,21169,30782,21382,21033,20616,20363,20432,32598,32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620,32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639,32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656,32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675,32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,32691,32692,32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712,32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731,32732,32733,32734,32738,32739,30178,31435,31890,27813,38582,21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947,33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327,26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730,38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020,37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278,32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311,30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,32740,32743,32744,32746,32747,32748,32749,32751,32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775,32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801,32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828,32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851,32853,32854,32855,32857,32859,32860,32861,32862,32863,32864,32865,32866,32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,38534,22404,25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809,25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405,38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459,29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718,20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064,33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527,22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930,28459,32894,32897,32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919,32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953,32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980,32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022,33023,33024,33025,33027,33028,33029,33031,33032,33035,33036,33045,33047,33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063,33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082,33083,33084,33085,33087,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683,38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665,29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391,20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964,36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501,20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217,22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125,21517,21629,35884,25720,33088,33089,33090,33091,33092,33093,33095,33097,33101,33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122,33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143,33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168,33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186,33188,33189,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202,33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223,33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,25721,34321,27169,33180,30952,25705,39764,25273,26411,33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137,22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343,21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007,38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958,38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180,30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218,38221,28037,24744,26592,29406,20957,23425,33236,33237,33238,33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252,33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271,33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295,33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318,33319,33321,33326,33330,33338,33340,33341,33343,33344,33345,33346,33347,33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365,33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381,33382,33383,33385,25319,27870,29275,25197,38062,32445,33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062,31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228,24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928,30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846,34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943,30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527,25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403,33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429,33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467,33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501,33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526,33528,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554,33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573,33574,33577,33578,33582,33584,33586,33591,33595,33597,21860,33086,30130,30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922,31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179,20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078,25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889,26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854,26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682,20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488,33598,33599,33601,33602,33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624,33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662,33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679,33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699,33700,33701,33702,33703,33708,33709,33710,33711,33717,33723,33726,33727,33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747,33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771,33772,33773,24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660,38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595,33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052,20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363,38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731,27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351,31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527,23624,39537,28192,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790,33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813,33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834,33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849,33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878,33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902,33903,33904,33906,33908,33911,33913,33915,33916,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849,20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830,38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286,25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922,32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466,20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837,35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832,33134,40131,22622,36187,19977,21441,33917,33918,33919,33920,33921,33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941,33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974,33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996,33998,33999,34002,34004,34005,34007,34008,34009,34010,34011,34012,34014,34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049,34050,20254,25955,26705,21971,20007,25620,39578,25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433,20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378,38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188,19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045,32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774,30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978,32958,24910,28183,22768,29983,29989,29298,21319,32499,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063,34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082,34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118,34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150,34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166,34167,34168,34172,34173,34175,34176,34177,30465,30427,21097,32988,22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102,20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034,22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181,20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432,23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460,33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653,40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,34178,34179,34182,34184,34185,34186,34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217,34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236,34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251,34252,34253,34254,34257,34258,34260,34262,34263,34264,34265,34266,34267,34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,24661,21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700,30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070,24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051,26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487,37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948,31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385,25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427,22905,22612,34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387,34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404,34405,34406,34407,34408,34409,34410,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826,24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848,22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179,21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691,36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386,38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825,28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148,38081,24086,21381,21548,28867,34413,34415,34416,34418,34419,34420,34421,34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448,34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465,34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492,34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517,34518,34519,34522,34524,34525,34528,34529,34530,34531,34533,34534,34535,34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559,34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,27712,24311,20572,20141,24237,25402,33351,36890,26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599,25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520,20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302,25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521,27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919,23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129,26505,32593,24448,26106,26395,24536,22916,23041,34585,34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607,34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626,34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645,34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664,34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,34679,34680,34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703,34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718,34720,34721,34722,34723,34724,24013,24494,21361,38886,36829,26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614,32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944,21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705,29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056,20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410,21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823,26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,34725,34726,34727,34729,34730,34734,34736,34737,34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755,34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774,34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790,34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805,34806,34807,34808,34810,34811,34812,34813,34815,34816,34817,34818,34820,34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834,34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,31232,24687,24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109,20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686,36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185,40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616,29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321,31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233,20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102,26195,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867,34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883,34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901,34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925,34927,34929,34931,34932,34933,34934,34936,34937,34938,34939,34940,34944,34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965,34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982,34983,34984,34985,34986,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795,21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844,27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885,26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447,24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429,21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768,33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927,23459,24748,26059,29572,34988,34990,34991,34992,34994,34995,34996,34997,34998,35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018,35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037,35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058,35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078,35079,35080,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094,35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112,35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,36873,30307,30505,32474,38772,34203,23398,31348,38634,34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759,36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905,28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740,34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436,33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523,22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162,20859,26679,28478,36992,33136,22934,29814,35128,35129,35130,35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35194,35196,35197,35198,35200,35202,35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,25671,23591,36965,31377,35875,23002,21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029,25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381,20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413,26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159,24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322,35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899,38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285,35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305,35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,21360,33521,27185,23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433,39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647,27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038,38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188,36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841,28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577,22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454,35455,35456,28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407,25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498,26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095,21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685,21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900,36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790,29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939,28195,26413,36711,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469,35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688,25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759,23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467,24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157,25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761,32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024,20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424,20105,24596,25972,25327,27491,25919,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,24103,30151,37073,35777,33437,26525,25903,21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191,20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267,33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835,31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311,21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588,29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633,22065,20027,33879,26609,21161,34496,36142,38136,31569,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756,35761,35771,35783,35792,35818,35849,35870,20303,27880,31069,39547,25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918,25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305,21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039,28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837,36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063,31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152,24038,20304,26590,20570,20316,22352,24231,59408,59409,59410,59411,59412,35896,35897,35898,35899,35900,35901,35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919,35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934,35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951,35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968,35969,35971,35972,35974,35975,35976,35979,35981,35982,35983,35984,35985,35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,20109,19980,20800,19984,24319,21317,19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243,21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073,20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189,21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043,21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866,32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324,20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,20319,20311,20274,20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372,20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467,20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552,20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718,20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649,39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147,34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191,36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219,36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237,36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36256,36257,36258,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288,36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779,35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812,35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847,35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872,35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370,38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508,38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044,37043,37046,37050,36309,36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336,36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358,36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376,36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397,36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,36415,36419,36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440,36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455,36456,36458,36459,36462,36465,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094,37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167,37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232,21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441,22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364,22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445,22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482,22456,22516,22511,22520,22500,22493,36467,36469,36471,36472,36473,36474,36475,36477,36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494,36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512,36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528,36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36549,36550,36551,36552,36553,36554,36555,36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,22539,22541,22525,22509,22528,22558,22553,22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405,33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456,33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450,33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490,33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617,33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603,33631,33600,33559,33632,33581,33594,33587,33638,33637,36581,36582,36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36643,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672,36673,36674,36675,36676,33640,33563,33641,33644,33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660,33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765,33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759,33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882,33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934,33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953,33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736,36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781,36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800,36803,36806,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826,36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859,36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,34134,34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171,34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241,34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869,22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306,25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524,25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550,25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732,25709,25750,36889,36892,36899,36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916,36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939,36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961,36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982,36983,36984,36985,36986,36987,36988,36990,36993,36996,36997,36998,36999,37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020,37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052,37053,37055,37056,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865,25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522,21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554,21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677,21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708,21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757,21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869,21825,21845,21823,21840,21820,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076,37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098,37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116,37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147,37148,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162,37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178,37179,37180,37181,37182,37183,37184,37185,37186,37188,21815,21846,21877,21878,21879,21811,21808,21852,21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983,21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990,21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046,22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060,22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149,22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281,22300,24079,24089,24084,24081,24113,24123,24124,37189,37191,37192,37201,37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224,37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256,37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278,37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297,37298,37299,37302,37303,37304,37305,37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333,37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347,37348,37349,24119,24132,24148,24155,24158,24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733,23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781,23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869,23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955,23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493,24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389,29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373,37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399,37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424,37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37443,37444,37445,29435,29463,29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520,29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271,39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309,39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245,24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527,24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629,24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698,24642,37446,37447,37448,37449,37450,37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476,37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489,37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37507,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529,37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763,24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846,24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379,38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412,38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732,27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817,27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886,27825,27859,27887,27902,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569,37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583,37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634,37635,37636,37637,37638,37639,37640,37641,27961,27943,27916,27971,27976,27911,27908,27929,27918,27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064,27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095,28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267,28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461,28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514,28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553,28557,28556,28536,28530,28540,28538,28625,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660,37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700,37701,37702,37703,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725,37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739,28617,28583,28601,28598,28610,28641,28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428,23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591,36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875,36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944,36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407,24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365,33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779,37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817,37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,37833,37835,37836,37837,22935,22986,22955,22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000,23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100,23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224,23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360,23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551,39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580,39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425,37838,37839,37840,37841,37842,37843,37844,37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884,37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37902,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475,32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510,32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540,32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557,32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585,29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657,39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736,29744,29742,29740,37935,37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948,37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962,37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975,37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,38000,38001,38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100,38106,38118,38139,38172,38176,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822,29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882,38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520,26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601,26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561,26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726,26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731,26818,26990,26876,26911,26912,26873,38183,38195,38205,38211,38216,38219,38229,38234,38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285,38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314,38315,38316,38317,38318,38319,38320,38321,38322,38323,38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336,38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,26916,26864,26891,26881,26967,26851,26896,26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015,27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057,27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122,27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281,27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533,27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727,36729,36730,36732,36734,36737,36738,36740,36743,36747,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375,38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439,38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465,38467,38474,38478,38479,38481,38482,38483,38486,38487,38488,38489,38490,38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513,38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38535,38537,38538,36749,36750,36751,36760,36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935,29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115,26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177,26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342,26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173,36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277,29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,38540,38542,38545,38546,38547,38549,38550,38554,38555,38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570,38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587,38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630,38631,38635,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650,38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674,38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,25663,25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672,27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270,29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948,32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989,33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054,33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148,33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406,33226,33211,38689,38690,38691,38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708,38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737,38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760,38762,38763,38764,38765,38766,38767,38768,38769,38770,38773,38775,38776,38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791,38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810,38811,38812,38813,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123,39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052,26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843,28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042,29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213,29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046,31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114,31130,31143,31155,24529,24528,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825,38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,24636,24669,24666,24679,24641,24665,24675,24747,24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156,30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778,30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800,30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885,30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697,40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502,30517,30520,30544,30545,30535,30531,30554,30568,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,30562,30565,30591,30605,30589,30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024,30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641,32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032,38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063,38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088,38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105,38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065,39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117,39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154,39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39170,39171,39172,39173,39174,39175,38121,38123,38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150,38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171,38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199,38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223,38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242,38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259,38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262,31252,39176,39177,39178,39179,39180,39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208,39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222,39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235,39236,39237,39238,39239,39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299,39305,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918,29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504,40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524,40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553,40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115,30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182,30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218,30245,30232,30229,30233,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331,39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410,39411,39412,39413,39414,39415,39416,39417,30235,30268,30242,30240,30272,30253,30256,30271,30261,30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352,31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921,34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045,35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115,35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796,32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845,32850,32873,32881,35203,39032,39040,39043,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,39484,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513,39049,39052,39053,39055,39060,39066,39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426,34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486,34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546,34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568,34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609,34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699,34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526,39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577,39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609,39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630,39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,39645,39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664,39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679,39680,39681,39682,39684,39685,39686,34758,34696,34693,34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752,34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876,32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531,31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518,31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632,31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697,31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755,39687,39689,39690,39691,39692,39693,39694,39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709,39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724,39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741,39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766,39767,39768,39769,39770,39771,39772,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313,33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353,33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671,32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932,31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718,32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411,40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200,37198,37199,37220,39804,39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830,39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241,37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300,37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292,36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345,36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416,36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476,36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992,35988,26011,35286,35294,35290,35292,39900,39901,39902,39903,39904,39905,39906,39907,39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39969,39970,39971,39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,35301,35307,35311,35390,35622,38739,38633,38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835,40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589,38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995,40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084,40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104,40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122,40123,40124,40125,40132,40133,40134,40135,40138,40139,39996,39997,39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036,40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40061,40062,40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093,40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146,40154,40155,40160,40161,40140,40141,40142,40143,40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789,38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606,39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753,39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659,39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583,40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681,40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000,58001,40259,40260,40261,40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287,40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,40321,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338,40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351,40352,40353,40354,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390,40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403,40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441,40442,40443,40444,40445,40446,40447,40448,40449,40450,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,40451,40452,40453,40454,40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487,40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537,40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567,40568,40569,40570,40571,40572,40573,40576,40577,40579,40580,40581,40582,40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600,40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616,40617,40618,58190,58191,58192,58193,58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630,40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648,40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673,40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692,40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726,40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743,40744,40745,40746,40747,40749,40750,40752,40753,58284,58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,40754,40755,40756,40757,40758,40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792,40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805,40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,40820,40821,40822,40823,40824,40825,40826,40827,40828,40829,40830,40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855,40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975,63985,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035,64036,64039,64040,64041,11905,59414,59415,59416,11908,13427,13383,11912,11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963,14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950,17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822,18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731,19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565],
      "gb18030-ranges":[[0,128],[36,165],[38,169],[45,178],[50,184],[81,216],[89,226],[95,235],[96,238],[100,244],[103,248],[104,251],[105,253],[109,258],[126,276],[133,284],[148,300],[172,325],[175,329],[179,334],[208,364],[306,463],[307,465],[308,467],[309,469],[310,471],[311,473],[312,475],[313,477],[341,506],[428,594],[443,610],[544,712],[545,716],[558,730],[741,930],[742,938],[749,962],[750,970],[805,1026],[819,1104],[820,1106],[7922,8209],[7924,8215],[7925,8218],[7927,8222],[7934,8231],[7943,8241],[7944,8244],[7945,8246],[7950,8252],[8062,8365],[8148,8452],[8149,8454],[8152,8458],[8164,8471],[8174,8482],[8236,8556],[8240,8570],[8262,8596],[8264,8602],[8374,8713],[8380,8720],[8381,8722],[8384,8726],[8388,8731],[8390,8737],[8392,8740],[8393,8742],[8394,8748],[8396,8751],[8401,8760],[8406,8766],[8416,8777],[8419,8781],[8424,8787],[8437,8802],[8439,8808],[8445,8816],[8482,8854],[8485,8858],[8496,8870],[8521,8896],[8603,8979],[8936,9322],[8946,9372],[9046,9548],[9050,9588],[9063,9616],[9066,9622],[9076,9634],[9092,9652],[9100,9662],[9108,9672],[9111,9676],[9113,9680],[9131,9702],[9162,9735],[9164,9738],[9218,9793],[9219,9795],[11329,11906],[11331,11909],[11334,11913],[11336,11917],[11346,11928],[11361,11944],[11363,11947],[11366,11951],[11370,11956],[11372,11960],[11375,11964],[11389,11979],[11682,12284],[11686,12292],[11687,12312],[11692,12319],[11694,12330],[11714,12351],[11716,12436],[11723,12447],[11725,12535],[11730,12543],[11736,12586],[11982,12842],[11989,12850],[12102,12964],[12336,13200],[12348,13215],[12350,13218],[12384,13253],[12393,13263],[12395,13267],[12397,13270],[12510,13384],[12553,13428],[12851,13727],[12962,13839],[12973,13851],[13738,14617],[13823,14703],[13919,14801],[13933,14816],[14080,14964],[14298,15183],[14585,15471],[14698,15585],[15583,16471],[15847,16736],[16318,17208],[16434,17325],[16438,17330],[16481,17374],[16729,17623],[17102,17997],[17122,18018],[17315,18212],[17320,18218],[17402,18301],[17418,18318],[17859,18760],[17909,18811],[17911,18814],[17915,18820],[17916,18823],[17936,18844],[17939,18848],[17961,18872],[18664,19576],[18703,19620],[18814,19738],[18962,19887],[19043,40870],[33469,59244],[33470,59336],[33471,59367],[33484,59413],[33485,59417],[33490,59423],[33497,59431],[33501,59437],[33505,59443],[33513,59452],[33520,59460],[33536,59478],[33550,59493],[37845,63789],[37921,63866],[37948,63894],[38029,63976],[38038,63986],[38064,64016],[38065,64018],[38066,64021],[38069,64025],[38075,64034],[38076,64037],[38078,64042],[39108,65074],[39109,65093],[39113,65107],[39114,65112],[39115,65127],[39116,65132],[39265,65375],[39394,65510],[189000,65536]],
      "jis0208":[12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,8213,8208,65295,65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,65293,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,null,null,null,null,null,null,null,null,null,null,null,8712,8715,8838,8839,8834,8835,8746,8745,null,null,null,null,null,null,null,null,8743,8744,65506,8658,8660,8704,8707,null,null,null,null,null,null,null,null,null,null,null,8736,8869,8978,8706,8711,8801,8786,8810,8811,8730,8765,8733,8757,8747,8748,null,null,null,null,null,null,null,8491,8240,9839,9837,9834,8224,8225,182,null,null,null,null,9711,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,null,null,null,null,null,null,null,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,null,null,null,null,null,null,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,null,null,null,null,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,13129,13076,13090,13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212,13213,13214,13198,13199,13252,13217,null,null,null,null,null,null,null,null,13179,12317,12319,8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,28286,30871,33109,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956,29081,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
      "jis0212":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,728,711,184,729,733,175,731,730,65374,900,901,null,null,null,null,null,null,null,null,161,166,191,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,186,170,169,174,8482,164,8470,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,902,904,905,906,938,null,908,null,910,939,null,911,null,null,null,null,940,941,942,943,970,912,972,962,973,971,944,974,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1038,1039,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1118,1119,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,198,272,null,294,null,306,null,321,319,null,330,216,338,null,358,222,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,230,273,240,295,305,307,312,322,320,329,331,248,339,223,359,254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270,201,200,203,202,282,278,274,280,null,284,286,290,288,292,205,204,207,206,463,304,298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332,213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370,366,360,471,475,473,469,372,221,376,374,377,381,379,null,null,null,null,null,null,null,225,224,228,226,259,462,257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501,285,287,null,289,293,237,236,239,238,464,null,299,303,297,309,311,314,318,316,324,328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357,355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255,375,378,382,380,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011,20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072,20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176,20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223,20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273,20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300,20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345,20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370,20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413,20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444,20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492,20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528,20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562,20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593,20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630,20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669,20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703,20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743,20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766,20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802,20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875,20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936,20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980,20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042,21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094,21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143,21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178,21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212,21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251,21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288,21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323,21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384,21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429,21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470,21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553,21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609,21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653,21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689,21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756,21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803,21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841,21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896,21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953,21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982,21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034,22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081,22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115,22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165,22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193,22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236,22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263,22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307,22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341,22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384,22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412,22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441,22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503,22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537,22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591,22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652,22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678,22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733,22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790,22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832,22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879,22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924,22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967,22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011,23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054,23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111,23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166,23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217,23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260,23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321,23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400,23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441,23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484,23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540,23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602,23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668,23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712,23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767,23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847,23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882,23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937,23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979,23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036,24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110,24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158,24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229,24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273,24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345,24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374,24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416,24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461,24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504,24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546,24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583,24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640,24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702,24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738,24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778,24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821,24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854,24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889,24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960,24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992,24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045,25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089,25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145,25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180,25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267,25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332,25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386,25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422,25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464,25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502,25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556,25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610,25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648,25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693,25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744,25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789,25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828,25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865,25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902,25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959,25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022,26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072,26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125,26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188,26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220,26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253,26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293,26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344,26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419,26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486,26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545,26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578,26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653,26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693,26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741,26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785,26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833,26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865,26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903,26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980,26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021,27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066,27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125,27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184,27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217,27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270,27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313,27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356,27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399,27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445,27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499,27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555,27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593,27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650,27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692,27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732,27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782,27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846,27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883,27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942,27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001,28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056,28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118,28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160,28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233,28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264,28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347,28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398,28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454,28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499,28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551,28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581,28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618,28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679,28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745,28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790,28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848,28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922,28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975,28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018,29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088,29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139,29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210,29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262,29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294,29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339,29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400,29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453,29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493,29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536,29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569,29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600,29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637,29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670,29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700,29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777,29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824,29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852,29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874,29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918,29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970,29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014,30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063,30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101,30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158,30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201,30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230,30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261,30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293,30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349,30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376,30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438,30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484,30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518,30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551,30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580,30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631,30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686,30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726,30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775,30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820,30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879,30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920,30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950,30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002,31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037,31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079,31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125,31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163,31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202,31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244,31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288,31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327,31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370,31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420,31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483,31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535,31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590,31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638,31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676,31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722,31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750,31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793,31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834,31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865,31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930,31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959,31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017,32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062,32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101,32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136,32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182,32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256,32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272,32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310,32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363,32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408,32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594,32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638,32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678,32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739,32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778,32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806,32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864,32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939,32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006,33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052,33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100,33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156,33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211,33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252,33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283,33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347,33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389,33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425,33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450,33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498,33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537,33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581,33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614,33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677,33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726,33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782,33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849,33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884,33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921,33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978,33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031,34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062,34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100,34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142,34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177,34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213,34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251,34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303,34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337,34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390,34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421,34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472,34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501,34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556,34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591,34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624,34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691,34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712,34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753,34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788,34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826,34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856,34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890,34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929,34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005,35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047,35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096,35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130,35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169,35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213,35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255,35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318,35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360,35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397,35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431,35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471,35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511,35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549,35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612,35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656,35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710,35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897,35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931,35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966,35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037,36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080,36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197,36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255,36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294,36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332,36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372,36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409,36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449,36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489,36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531,36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584,36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624,36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654,36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691,36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789,36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821,36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872,36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927,36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997,37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026,37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063,37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103,37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142,37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167,37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203,37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249,37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286,37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311,37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354,37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380,37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405,37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433,37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457,37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488,37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517,37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554,37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574,37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596,37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627,37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665,37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712,37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741,37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768,37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798,37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833,37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881,37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903,37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949,37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995,37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284,38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330,38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365,38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449,38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488,38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545,38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602,38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659,38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723,38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771,38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810,38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844,38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865,38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900,38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944,38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983,38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018,39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109,39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176,39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217,39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240,39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327,39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380,39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421,39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459,39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499,39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605,39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637,39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669,39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691,39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725,39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767,39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795,39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819,39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857,39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895,39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930,39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966,39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001,40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027,40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053,40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221,40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263,40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311,40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342,40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391,40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425,40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466,40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581,40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624,40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686,40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722,40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753,40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774,40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814,40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854,40855,40862,40865,40866,40867,40869,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
      "ibm866":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1025,1105,1028,1108,1031,1111,1038,1118,176,8729,183,8730,8470,164,9632,160],
      "iso-8859-2":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,728,321,164,317,346,167,168,352,350,356,377,173,381,379,176,261,731,322,180,318,347,711,184,353,351,357,378,733,382,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],
      "iso-8859-3":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,294,728,163,164,null,292,167,168,304,350,286,308,173,null,379,176,295,178,179,180,181,293,183,184,305,351,287,309,189,null,380,192,193,194,null,196,266,264,199,200,201,202,203,204,205,206,207,null,209,210,211,212,288,214,215,284,217,218,219,220,364,348,223,224,225,226,null,228,267,265,231,232,233,234,235,236,237,238,239,null,241,242,243,244,289,246,247,285,249,250,251,252,365,349,729],
      "iso-8859-4":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,312,342,164,296,315,167,168,352,274,290,358,173,381,175,176,261,731,343,180,297,316,711,184,353,275,291,359,330,382,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,298,272,325,332,310,212,213,214,215,216,370,218,219,220,360,362,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,299,273,326,333,311,244,245,246,247,248,371,250,251,252,361,363,729],
      "iso-8859-5":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,173,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8470,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,167,1118,1119],
      "iso-8859-6":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,null,null,164,null,null,null,null,null,null,null,1548,173,null,null,null,null,null,null,null,null,null,null,null,null,null,1563,null,null,null,1567,null,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,null,null,null,null,null,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,null,null,null,null,null,null,null,null,null,null,null,null,null],
      "iso-8859-7":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8216,8217,163,8364,8367,166,167,168,169,890,171,172,173,null,8213,176,177,178,179,900,901,902,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],
      "iso-8859-8":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,162,163,164,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8215,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],
      "iso-8859-10":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,274,290,298,296,310,167,315,272,352,358,381,173,362,330,176,261,275,291,299,297,311,183,316,273,353,359,382,8213,363,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,207,208,325,332,211,212,213,214,360,216,370,218,219,220,221,222,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,239,240,326,333,243,244,245,246,361,248,371,250,251,252,253,254,312],
      "iso-8859-13":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8221,162,163,164,8222,166,167,216,169,342,171,172,173,174,198,176,177,178,179,8220,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,8217],
      "iso-8859-14":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,7682,7683,163,266,267,7690,167,7808,169,7810,7691,7922,173,174,376,7710,7711,288,289,7744,7745,182,7766,7809,7767,7811,7776,7923,7812,7813,7777,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,372,209,210,211,212,213,214,7786,216,217,218,219,220,221,374,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,373,241,242,243,244,245,246,7787,248,249,250,251,252,253,375,255],
      "iso-8859-15":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,8364,165,352,167,353,169,170,171,172,173,174,175,176,177,178,179,381,181,182,183,382,185,186,187,338,339,376,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],
      "iso-8859-16":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,261,321,8364,8222,352,167,353,169,536,171,377,173,378,379,176,177,268,322,381,8221,182,183,382,269,537,187,338,339,376,380,192,193,194,258,196,262,198,199,200,201,202,203,204,205,206,207,272,323,210,211,212,336,214,346,368,217,218,219,220,280,538,223,224,225,226,259,228,263,230,231,232,233,234,235,236,237,238,239,273,324,242,243,244,337,246,347,369,249,250,251,252,281,539,255],
      "koi8-r":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,1025,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],
      "koi8-u":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,1108,9556,1110,1111,9559,9560,9561,9562,9563,1169,1118,9566,9567,9568,9569,1025,1028,9571,1030,1031,9574,9575,9576,9577,9578,1168,1038,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],
      "macintosh":[196,197,199,201,209,214,220,225,224,226,228,227,229,231,233,232,234,235,237,236,238,239,241,243,242,244,246,245,250,249,251,252,8224,176,162,163,167,8226,182,223,174,169,8482,180,168,8800,198,216,8734,177,8804,8805,165,181,8706,8721,8719,960,8747,170,186,937,230,248,191,161,172,8730,402,8776,8710,171,187,8230,160,192,195,213,338,339,8211,8212,8220,8221,8216,8217,247,9674,255,376,8260,8364,8249,8250,64257,64258,8225,183,8218,8222,8240,194,202,193,203,200,205,206,207,204,211,212,63743,210,218,219,217,305,710,732,175,728,729,730,184,733,731,711],
      "windows-874":[8364,129,130,131,132,8230,134,135,136,137,138,139,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,153,154,155,156,157,158,159,160,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,null,null,null,null,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,null,null,null,null],
      "windows-1250":[8364,129,8218,131,8222,8230,8224,8225,136,8240,352,8249,346,356,381,377,144,8216,8217,8220,8221,8226,8211,8212,152,8482,353,8250,347,357,382,378,160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379,176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],
      "windows-1251":[1026,1027,8218,1107,8222,8230,8224,8225,8364,8240,1033,8249,1034,1036,1035,1039,1106,8216,8217,8220,8221,8226,8211,8212,152,8482,1113,8250,1114,1116,1115,1119,160,1038,1118,1032,164,1168,166,167,1025,169,1028,171,172,173,174,1031,176,177,1030,1110,1169,181,182,183,1105,8470,1108,187,1112,1029,1109,1111,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103],
      "windows-1252":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,381,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,382,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],
      "windows-1253":[8364,129,8218,402,8222,8230,8224,8225,136,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,157,158,159,160,901,902,163,164,165,166,167,168,169,null,171,172,173,174,8213,176,177,178,179,900,181,182,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],
      "windows-1254":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,286,209,210,211,212,213,214,215,216,217,218,219,220,304,350,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,287,241,242,243,244,245,246,247,248,249,250,251,252,305,351,255],
      "windows-1255":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,156,157,158,159,160,161,162,163,8362,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,191,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1520,1521,1522,1523,1524,null,null,null,null,null,null,null,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],
      "windows-1256":[8364,1662,8218,402,8222,8230,8224,8225,710,8240,1657,8249,338,1670,1688,1672,1711,8216,8217,8220,8221,8226,8211,8212,1705,8482,1681,8250,339,8204,8205,1722,160,1548,162,163,164,165,166,167,168,169,1726,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,1563,187,188,189,190,1567,1729,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,215,1591,1592,1593,1594,1600,1601,1602,1603,224,1604,226,1605,1606,1607,1608,231,232,233,234,235,1609,1610,238,239,1611,1612,1613,1614,244,1615,1616,247,1617,249,1618,251,252,8206,8207,1746],
      "windows-1257":[8364,129,8218,131,8222,8230,8224,8225,136,8240,138,8249,140,168,711,184,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,175,731,159,160,null,162,163,164,null,166,167,216,169,342,171,172,173,174,198,176,177,178,179,180,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,729],
      "windows-1258":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,258,196,197,198,199,200,201,202,203,768,205,206,207,272,209,777,211,212,416,214,215,216,217,218,219,220,431,771,223,224,225,226,259,228,229,230,231,232,233,234,235,769,237,238,239,273,241,803,243,244,417,246,247,248,249,250,251,252,432,8363,255],
      "x-mac-cyrillic":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,8224,176,1168,163,167,8226,182,1030,174,169,8482,1026,1106,8800,1027,1107,8734,177,8804,8805,1110,181,1169,1032,1028,1108,1031,1111,1033,1113,1034,1114,1112,1029,172,8730,402,8776,8710,171,187,8230,160,1035,1115,1036,1116,1109,8211,8212,8220,8221,8216,8217,247,8222,1038,1118,1039,1119,8470,1025,1105,1103,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,8364]
    };
    }(commonjsGlobal || {}));
    }(encodingIndexes));

    (function (module) {
    (function(global) {
      if (module.exports &&
        !global["encoding-indexes"]) {
        global["encoding-indexes"] =
          encodingIndexes.exports["encoding-indexes"];
      }
      function inRange(a, min, max) {
        return min <= a && a <= max;
      }
      function includes(array, item) {
        return array.indexOf(item) !== -1;
      }
      var floor = Math.floor;
      function ToDictionary(o) {
        if (o === undefined) return {};
        if (o === Object(o)) return o;
        throw TypeError('Could not convert argument to dictionary');
      }
      function stringToCodePoints(string) {
        var s = String(string);
        var n = s.length;
        var i = 0;
        var u = [];
        while (i < n) {
          var c = s.charCodeAt(i);
          if (c < 0xD800 || c > 0xDFFF) {
            u.push(c);
          }
          else if (0xDC00 <= c && c <= 0xDFFF) {
            u.push(0xFFFD);
          }
          else if (0xD800 <= c && c <= 0xDBFF) {
            if (i === n - 1) {
              u.push(0xFFFD);
            }
            else {
              var d = s.charCodeAt(i + 1);
              if (0xDC00 <= d && d <= 0xDFFF) {
                var a = c & 0x3FF;
                var b = d & 0x3FF;
                u.push(0x10000 + (a << 10) + b);
                i += 1;
              }
              else  {
                u.push(0xFFFD);
              }
            }
          }
          i += 1;
        }
        return u;
      }
      function codePointsToString(code_points) {
        var s = '';
        for (var i = 0; i < code_points.length; ++i) {
          var cp = code_points[i];
          if (cp <= 0xFFFF) {
            s += String.fromCharCode(cp);
          } else {
            cp -= 0x10000;
            s += String.fromCharCode((cp >> 10) + 0xD800,
                                     (cp & 0x3FF) + 0xDC00);
          }
        }
        return s;
      }
      function isASCIIByte(a) {
        return 0x00 <= a && a <= 0x7F;
      }
      var isASCIICodePoint = isASCIIByte;
     var end_of_stream = -1;
      function Stream(tokens) {
        this.tokens = [].slice.call(tokens);
        this.tokens.reverse();
      }
      Stream.prototype = {
        endOfStream: function() {
          return !this.tokens.length;
        },
         read: function() {
          if (!this.tokens.length)
            return end_of_stream;
           return this.tokens.pop();
         },
        prepend: function(token) {
          if (Array.isArray(token)) {
            var tokens = (token);
            while (tokens.length)
              this.tokens.push(tokens.pop());
          } else {
            this.tokens.push(token);
          }
        },
        push: function(token) {
          if (Array.isArray(token)) {
            var tokens = (token);
            while (tokens.length)
              this.tokens.unshift(tokens.shift());
          } else {
            this.tokens.unshift(token);
          }
        }
      };
      var finished = -1;
      function decoderError(fatal, opt_code_point) {
        if (fatal)
          throw TypeError('Decoder error');
        return opt_code_point || 0xFFFD;
      }
      function encoderError(code_point) {
        throw TypeError('The code point ' + code_point + ' could not be encoded.');
      }
      function getEncoding(label) {
        label = String(label).trim().toLowerCase();
        if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) {
          return label_to_encoding[label];
        }
        return null;
      }
      var encodings = [
        {
          "encodings": [
            {
              "labels": [
                "unicode-1-1-utf-8",
                "utf-8",
                "utf8"
              ],
              "name": "UTF-8"
            }
          ],
          "heading": "The Encoding"
        },
        {
          "encodings": [
            {
              "labels": [
                "866",
                "cp866",
                "csibm866",
                "ibm866"
              ],
              "name": "IBM866"
            },
            {
              "labels": [
                "csisolatin2",
                "iso-8859-2",
                "iso-ir-101",
                "iso8859-2",
                "iso88592",
                "iso_8859-2",
                "iso_8859-2:1987",
                "l2",
                "latin2"
              ],
              "name": "ISO-8859-2"
            },
            {
              "labels": [
                "csisolatin3",
                "iso-8859-3",
                "iso-ir-109",
                "iso8859-3",
                "iso88593",
                "iso_8859-3",
                "iso_8859-3:1988",
                "l3",
                "latin3"
              ],
              "name": "ISO-8859-3"
            },
            {
              "labels": [
                "csisolatin4",
                "iso-8859-4",
                "iso-ir-110",
                "iso8859-4",
                "iso88594",
                "iso_8859-4",
                "iso_8859-4:1988",
                "l4",
                "latin4"
              ],
              "name": "ISO-8859-4"
            },
            {
              "labels": [
                "csisolatincyrillic",
                "cyrillic",
                "iso-8859-5",
                "iso-ir-144",
                "iso8859-5",
                "iso88595",
                "iso_8859-5",
                "iso_8859-5:1988"
              ],
              "name": "ISO-8859-5"
            },
            {
              "labels": [
                "arabic",
                "asmo-708",
                "csiso88596e",
                "csiso88596i",
                "csisolatinarabic",
                "ecma-114",
                "iso-8859-6",
                "iso-8859-6-e",
                "iso-8859-6-i",
                "iso-ir-127",
                "iso8859-6",
                "iso88596",
                "iso_8859-6",
                "iso_8859-6:1987"
              ],
              "name": "ISO-8859-6"
            },
            {
              "labels": [
                "csisolatingreek",
                "ecma-118",
                "elot_928",
                "greek",
                "greek8",
                "iso-8859-7",
                "iso-ir-126",
                "iso8859-7",
                "iso88597",
                "iso_8859-7",
                "iso_8859-7:1987",
                "sun_eu_greek"
              ],
              "name": "ISO-8859-7"
            },
            {
              "labels": [
                "csiso88598e",
                "csisolatinhebrew",
                "hebrew",
                "iso-8859-8",
                "iso-8859-8-e",
                "iso-ir-138",
                "iso8859-8",
                "iso88598",
                "iso_8859-8",
                "iso_8859-8:1988",
                "visual"
              ],
              "name": "ISO-8859-8"
            },
            {
              "labels": [
                "csiso88598i",
                "iso-8859-8-i",
                "logical"
              ],
              "name": "ISO-8859-8-I"
            },
            {
              "labels": [
                "csisolatin6",
                "iso-8859-10",
                "iso-ir-157",
                "iso8859-10",
                "iso885910",
                "l6",
                "latin6"
              ],
              "name": "ISO-8859-10"
            },
            {
              "labels": [
                "iso-8859-13",
                "iso8859-13",
                "iso885913"
              ],
              "name": "ISO-8859-13"
            },
            {
              "labels": [
                "iso-8859-14",
                "iso8859-14",
                "iso885914"
              ],
              "name": "ISO-8859-14"
            },
            {
              "labels": [
                "csisolatin9",
                "iso-8859-15",
                "iso8859-15",
                "iso885915",
                "iso_8859-15",
                "l9"
              ],
              "name": "ISO-8859-15"
            },
            {
              "labels": [
                "iso-8859-16"
              ],
              "name": "ISO-8859-16"
            },
            {
              "labels": [
                "cskoi8r",
                "koi",
                "koi8",
                "koi8-r",
                "koi8_r"
              ],
              "name": "KOI8-R"
            },
            {
              "labels": [
                "koi8-ru",
                "koi8-u"
              ],
              "name": "KOI8-U"
            },
            {
              "labels": [
                "csmacintosh",
                "mac",
                "macintosh",
                "x-mac-roman"
              ],
              "name": "macintosh"
            },
            {
              "labels": [
                "dos-874",
                "iso-8859-11",
                "iso8859-11",
                "iso885911",
                "tis-620",
                "windows-874"
              ],
              "name": "windows-874"
            },
            {
              "labels": [
                "cp1250",
                "windows-1250",
                "x-cp1250"
              ],
              "name": "windows-1250"
            },
            {
              "labels": [
                "cp1251",
                "windows-1251",
                "x-cp1251"
              ],
              "name": "windows-1251"
            },
            {
              "labels": [
                "ansi_x3.4-1968",
                "ascii",
                "cp1252",
                "cp819",
                "csisolatin1",
                "ibm819",
                "iso-8859-1",
                "iso-ir-100",
                "iso8859-1",
                "iso88591",
                "iso_8859-1",
                "iso_8859-1:1987",
                "l1",
                "latin1",
                "us-ascii",
                "windows-1252",
                "x-cp1252"
              ],
              "name": "windows-1252"
            },
            {
              "labels": [
                "cp1253",
                "windows-1253",
                "x-cp1253"
              ],
              "name": "windows-1253"
            },
            {
              "labels": [
                "cp1254",
                "csisolatin5",
                "iso-8859-9",
                "iso-ir-148",
                "iso8859-9",
                "iso88599",
                "iso_8859-9",
                "iso_8859-9:1989",
                "l5",
                "latin5",
                "windows-1254",
                "x-cp1254"
              ],
              "name": "windows-1254"
            },
            {
              "labels": [
                "cp1255",
                "windows-1255",
                "x-cp1255"
              ],
              "name": "windows-1255"
            },
            {
              "labels": [
                "cp1256",
                "windows-1256",
                "x-cp1256"
              ],
              "name": "windows-1256"
            },
            {
              "labels": [
                "cp1257",
                "windows-1257",
                "x-cp1257"
              ],
              "name": "windows-1257"
            },
            {
              "labels": [
                "cp1258",
                "windows-1258",
                "x-cp1258"
              ],
              "name": "windows-1258"
            },
            {
              "labels": [
                "x-mac-cyrillic",
                "x-mac-ukrainian"
              ],
              "name": "x-mac-cyrillic"
            }
          ],
          "heading": "Legacy single-byte encodings"
        },
        {
          "encodings": [
            {
              "labels": [
                "chinese",
                "csgb2312",
                "csiso58gb231280",
                "gb2312",
                "gb_2312",
                "gb_2312-80",
                "gbk",
                "iso-ir-58",
                "x-gbk"
              ],
              "name": "GBK"
            },
            {
              "labels": [
                "gb18030"
              ],
              "name": "gb18030"
            }
          ],
          "heading": "Legacy multi-byte Chinese (simplified) encodings"
        },
        {
          "encodings": [
            {
              "labels": [
                "big5",
                "big5-hkscs",
                "cn-big5",
                "csbig5",
                "x-x-big5"
              ],
              "name": "Big5"
            }
          ],
          "heading": "Legacy multi-byte Chinese (traditional) encodings"
        },
        {
          "encodings": [
            {
              "labels": [
                "cseucpkdfmtjapanese",
                "euc-jp",
                "x-euc-jp"
              ],
              "name": "EUC-JP"
            },
            {
              "labels": [
                "csiso2022jp",
                "iso-2022-jp"
              ],
              "name": "ISO-2022-JP"
            },
            {
              "labels": [
                "csshiftjis",
                "ms932",
                "ms_kanji",
                "shift-jis",
                "shift_jis",
                "sjis",
                "windows-31j",
                "x-sjis"
              ],
              "name": "Shift_JIS"
            }
          ],
          "heading": "Legacy multi-byte Japanese encodings"
        },
        {
          "encodings": [
            {
              "labels": [
                "cseuckr",
                "csksc56011987",
                "euc-kr",
                "iso-ir-149",
                "korean",
                "ks_c_5601-1987",
                "ks_c_5601-1989",
                "ksc5601",
                "ksc_5601",
                "windows-949"
              ],
              "name": "EUC-KR"
            }
          ],
          "heading": "Legacy multi-byte Korean encodings"
        },
        {
          "encodings": [
            {
              "labels": [
                "csiso2022kr",
                "hz-gb-2312",
                "iso-2022-cn",
                "iso-2022-cn-ext",
                "iso-2022-kr"
              ],
              "name": "replacement"
            },
            {
              "labels": [
                "utf-16be"
              ],
              "name": "UTF-16BE"
            },
            {
              "labels": [
                "utf-16",
                "utf-16le"
              ],
              "name": "UTF-16LE"
            },
            {
              "labels": [
                "x-user-defined"
              ],
              "name": "x-user-defined"
            }
          ],
          "heading": "Legacy miscellaneous encodings"
        }
      ];
      var label_to_encoding = {};
      encodings.forEach(function(category) {
        category.encodings.forEach(function(encoding) {
          encoding.labels.forEach(function(label) {
            label_to_encoding[label] = encoding;
          });
        });
      });
      var encoders = {};
      var decoders = {};
      function indexCodePointFor(pointer, index) {
        if (!index) return null;
        return index[pointer] || null;
      }
      function indexPointerFor(code_point, index) {
        var pointer = index.indexOf(code_point);
        return pointer === -1 ? null : pointer;
      }
      function index(name) {
        if (!('encoding-indexes' in global)) {
          throw Error("Indexes missing." +
                      " Did you forget to include encoding-indexes.js first?");
        }
        return global['encoding-indexes'][name];
      }
      function fallbackReplacement(name) {
        var fallbackConfiguration = global['encode-fallback-replacement'];
        if (fallbackConfiguration) {
          var fallback = fallbackConfiguration[name];
          if (fallback) {
            return {
              "replacement": fallback.replacement,
              "index": index(fallback.index)
            }
          }
        }
        return null;
      }
      function indexGB18030RangesCodePointFor(pointer) {
        if ((pointer > 39419 && pointer < 189000) || (pointer > 1237575))
          return null;
        if (pointer === 7457) return 0xE7C7;
        var offset = 0;
        var code_point_offset = 0;
        var idx = index('gb18030-ranges');
        var i;
        for (i = 0; i < idx.length; ++i) {
          var entry = idx[i];
          if (entry[0] <= pointer) {
            offset = entry[0];
            code_point_offset = entry[1];
          } else {
            break;
          }
        }
        return code_point_offset + pointer - offset;
      }
      function indexGB18030RangesPointerFor(code_point) {
        if (code_point === 0xE7C7) return 7457;
        var offset = 0;
        var pointer_offset = 0;
        var idx = index('gb18030-ranges');
        var i;
        for (i = 0; i < idx.length; ++i) {
          var entry = idx[i];
          if (entry[1] <= code_point) {
            offset = entry[1];
            pointer_offset = entry[0];
          } else {
            break;
          }
        }
        return pointer_offset + code_point - offset;
      }
      function indexShiftJISPointerFor(code_point) {
        shift_jis_index = shift_jis_index ||
          index('jis0208').map(function(code_point, pointer) {
            return inRange(pointer, 8272, 8835) ? null : code_point;
          });
        var index_ = shift_jis_index;
        return index_.indexOf(code_point);
      }
      var shift_jis_index;
      function indexBig5PointerFor(code_point) {
        big5_index_no_hkscs = big5_index_no_hkscs ||
          index('big5').map(function(code_point, pointer) {
            return (pointer < (0xA1 - 0x81) * 157) ? null : code_point;
          });
        var index_ = big5_index_no_hkscs;
        if (code_point === 0x2550 || code_point === 0x255E ||
            code_point === 0x2561 || code_point === 0x256A ||
            code_point === 0x5341 || code_point === 0x5345) {
          return index_.lastIndexOf(code_point);
        }
        return indexPointerFor(code_point, index_);
      }
      var big5_index_no_hkscs;
       var DEFAULT_ENCODING = 'utf-8';
      function TextDecoder(label, options) {
        if (!(this instanceof TextDecoder))
          throw TypeError('Called as a function. Did you forget \'new\'?');
        label = label !== undefined ? String(label) : DEFAULT_ENCODING;
        options = ToDictionary(options);
        this._encoding = null;
        this._decoder = null;
        this._ignoreBOM = false;
        this._BOMseen = false;
        this._error_mode = 'replacement';
        this._do_not_flush = false;
        var encoding = getEncoding(label);
        if (encoding === null || encoding.name === 'replacement')
          throw RangeError('Unknown encoding: ' + label);
        if (!decoders[encoding.name]) {
          throw Error('Decoder not present.' +
                      ' Did you forget to include encoding-indexes.js first?');
        }
        var dec = this;
        dec._encoding = encoding;
        if (Boolean(options['fatal']))
          dec._error_mode = 'fatal';
        if (Boolean(options['ignoreBOM']))
          dec._ignoreBOM = true;
        if (!Object.defineProperty) {
          this.encoding = dec._encoding.name.toLowerCase();
          this.fatal = dec._error_mode === 'fatal';
          this.ignoreBOM = dec._ignoreBOM;
        }
        return dec;
      }
      if (Object.defineProperty) {
        Object.defineProperty(TextDecoder.prototype, 'encoding', {
          get: function() { return this._encoding.name.toLowerCase(); }
        });
        Object.defineProperty(TextDecoder.prototype, 'fatal', {
          get: function() { return this._error_mode === 'fatal'; }
        });
        Object.defineProperty(TextDecoder.prototype, 'ignoreBOM', {
          get: function() { return this._ignoreBOM; }
        });
      }
      TextDecoder.prototype.decode = function decode(input, options) {
        var bytes;
        if (typeof input === 'object' && input instanceof ArrayBuffer) {
          bytes = new Uint8Array(input);
        } else if (typeof input === 'object' && 'buffer' in input &&
                   input.buffer instanceof ArrayBuffer) {
          bytes = new Uint8Array(input.buffer,
                                 input.byteOffset,
                                 input.byteLength);
        } else if (typeof input === 'object' && input instanceof Uint8Array) {
          bytes = input;
        } else {
          bytes = new Uint8Array(0);
        }
        options = ToDictionary(options);
        if (!this._do_not_flush) {
          this._decoder = decoders[this._encoding.name]({
            fatal: this._error_mode === 'fatal'});
          this._BOMseen = false;
        }
        this._do_not_flush = Boolean(options['stream']);
        var input_stream = new Stream(bytes);
        var output = [];
        var result;
        while (true) {
          var token = input_stream.read();
          if (token === end_of_stream)
            break;
          result = this._decoder.handler(input_stream, token);
          if (result === finished)
            break;
          if (result !== null) {
            if (Array.isArray(result))
              output.push.apply(output, (result));
            else
              output.push(result);
          }
        }
        if (!this._do_not_flush) {
          do {
            result = this._decoder.handler(input_stream, input_stream.read());
            if (result === finished)
              break;
            if (result === null)
              continue;
            if (Array.isArray(result))
              output.push.apply(output, (result));
            else
              output.push(result);
          } while (!input_stream.endOfStream());
          this._decoder = null;
        }
        function serializeStream(stream) {
          if (includes(['UTF-8', 'UTF-16LE', 'UTF-16BE'], this._encoding.name) &&
              !this._ignoreBOM && !this._BOMseen) {
            if (stream.length > 0 && stream[0] === 0xFEFF) {
              this._BOMseen = true;
              stream.shift();
            } else if (stream.length > 0) {
              this._BOMseen = true;
            } else ;
          }
          return codePointsToString(stream);
        }
        return serializeStream.call(this, output);
      };
      function TextEncoder(label, options) {
        if (!(this instanceof TextEncoder))
          throw TypeError('Called as a function. Did you forget \'new\'?');
        options = ToDictionary(options);
        this._encoding = null;
        this._encoder = null;
        this._do_not_flush = false;
        this._fatal = Boolean(options['fatal']) ? 'fatal' : 'replacement';
        var enc = this;
        if (Boolean(options['NONSTANDARD_allowLegacyEncoding'])) {
          label = label !== undefined ? String(label) : DEFAULT_ENCODING;
          var encoding = getEncoding(label);
          if (encoding === null || encoding.name === 'replacement')
            throw RangeError('Unknown encoding: ' + label);
          if (!encoders[encoding.name]) {
            throw Error('Encoder not present.' +
                        ' Did you forget to include encoding-indexes.js first?');
          }
          enc._encoding = encoding;
        } else {
          enc._encoding = getEncoding('utf-8');
          if (label !== undefined && 'console' in global) {
            console.warn('TextEncoder constructor called with encoding label, '
                         + 'which is ignored.');
          }
        }
        if (!Object.defineProperty)
          this.encoding = enc._encoding.name.toLowerCase();
        return enc;
      }
      if (Object.defineProperty) {
        Object.defineProperty(TextEncoder.prototype, 'encoding', {
          get: function() { return this._encoding.name.toLowerCase(); }
        });
      }
      TextEncoder.prototype.encode = function encode(opt_string, options) {
        opt_string = opt_string === undefined ? '' : String(opt_string);
        options = ToDictionary(options);
        if (!this._do_not_flush)
          this._encoder = encoders[this._encoding.name]({
            fatal: this._fatal === 'fatal'});
        this._do_not_flush = Boolean(options['stream']);
        var input = new Stream(stringToCodePoints(opt_string));
        var output = [];
        var result;
        while (true) {
          var token = input.read();
          if (token === end_of_stream)
            break;
          result = this._encoder.handler(input, token);
          if (result === finished)
            break;
          if (Array.isArray(result))
            output.push.apply(output, (result));
          else
            output.push(result);
        }
        if (!this._do_not_flush) {
          while (true) {
            result = this._encoder.handler(input, input.read());
            if (result === finished)
              break;
            if (Array.isArray(result))
              output.push.apply(output, (result));
            else
              output.push(result);
          }
          this._encoder = null;
        }
        return new Uint8Array(output);
      };
      function UTF8Decoder(options) {
        var fatal = options.fatal;
        var  utf8_code_point = 0,
             utf8_bytes_seen = 0,
             utf8_bytes_needed = 0,
             utf8_lower_boundary = 0x80,
             utf8_upper_boundary = 0xBF;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && utf8_bytes_needed !== 0) {
            utf8_bytes_needed = 0;
            return decoderError(fatal);
          }
          if (bite === end_of_stream)
            return finished;
          if (utf8_bytes_needed === 0) {
            if (inRange(bite, 0x00, 0x7F)) {
              return bite;
            }
            else if (inRange(bite, 0xC2, 0xDF)) {
              utf8_bytes_needed = 1;
              utf8_code_point = bite & 0x1F;
            }
            else if (inRange(bite, 0xE0, 0xEF)) {
              if (bite === 0xE0)
                utf8_lower_boundary = 0xA0;
              if (bite === 0xED)
                utf8_upper_boundary = 0x9F;
              utf8_bytes_needed = 2;
              utf8_code_point = bite & 0xF;
            }
            else if (inRange(bite, 0xF0, 0xF4)) {
              if (bite === 0xF0)
                utf8_lower_boundary = 0x90;
              if (bite === 0xF4)
                utf8_upper_boundary = 0x8F;
              utf8_bytes_needed = 3;
              utf8_code_point = bite & 0x7;
            }
            else {
              return decoderError(fatal);
            }
            return null;
          }
          if (!inRange(bite, utf8_lower_boundary, utf8_upper_boundary)) {
            utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
            utf8_lower_boundary = 0x80;
            utf8_upper_boundary = 0xBF;
            stream.prepend(bite);
            return decoderError(fatal);
          }
          utf8_lower_boundary = 0x80;
          utf8_upper_boundary = 0xBF;
          utf8_code_point = (utf8_code_point << 6) | (bite & 0x3F);
          utf8_bytes_seen += 1;
          if (utf8_bytes_seen !== utf8_bytes_needed)
            return null;
          var code_point = utf8_code_point;
          utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
          return code_point;
        };
      }
      function UTF8Encoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          var count, offset;
          if (inRange(code_point, 0x0080, 0x07FF)) {
            count = 1;
            offset = 0xC0;
          }
          else if (inRange(code_point, 0x0800, 0xFFFF)) {
            count = 2;
            offset = 0xE0;
          }
          else if (inRange(code_point, 0x10000, 0x10FFFF)) {
            count = 3;
            offset = 0xF0;
          }
          var bytes = [(code_point >> (6 * count)) + offset];
          while (count > 0) {
            var temp = code_point >> (6 * (count - 1));
            bytes.push(0x80 | (temp & 0x3F));
            count -= 1;
          }
          return bytes;
        };
      }
      encoders['UTF-8'] = function(options) {
        return new UTF8Encoder(options);
      };
      decoders['UTF-8'] = function(options) {
        return new UTF8Decoder(options);
      };
      function SingleByteDecoder(index, options) {
        var fatal = options.fatal;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream)
            return finished;
          if (isASCIIByte(bite))
            return bite;
          var code_point = index[bite - 0x80];
          if (code_point === null)
            return decoderError(fatal);
          return code_point;
        };
      }
      function SingleByteEncoder(index, options, fallback) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          var pointer = indexPointerFor(code_point, index);
          if (pointer == null && fallback && fallback.index) {
            pointer = indexPointerFor(code_point, fallback.index);
          }
          if (pointer == null && fallback) {
            return fallback.replacement;
          }
          if (pointer === null)
            encoderError(code_point);
          return pointer + 0x80;
        };
      }
      (function() {
        if (!('encoding-indexes' in global))
          return;
        encodings.forEach(function(category) {
          if (category.heading !== 'Legacy single-byte encodings')
            return;
          category.encodings.forEach(function(encoding) {
            var name = encoding.name;
            var idx = index(name.toLowerCase());
            var fallback = fallbackReplacement(name.toLowerCase());
            decoders[name] = function(options) {
              return new SingleByteDecoder(idx, options);
            };
            encoders[name] = function(options) {
              return new SingleByteEncoder(idx, options, fallback);
            };
          });
        });
      }());
      decoders['GBK'] = function(options) {
        return new GB18030Decoder(options);
      };
      encoders['GBK'] = function(options) {
        return new GB18030Encoder(options, true);
      };
      function GB18030Decoder(options) {
        var fatal = options.fatal;
        var  gb18030_first = 0x00,
             gb18030_second = 0x00,
             gb18030_third = 0x00;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && gb18030_first === 0x00 &&
              gb18030_second === 0x00 && gb18030_third === 0x00) {
            return finished;
          }
          if (bite === end_of_stream &&
              (gb18030_first !== 0x00 || gb18030_second !== 0x00 ||
               gb18030_third !== 0x00)) {
            gb18030_first = 0x00;
            gb18030_second = 0x00;
            gb18030_third = 0x00;
            decoderError(fatal);
          }
          var code_point;
          if (gb18030_third !== 0x00) {
            code_point = null;
            if (inRange(bite, 0x30, 0x39)) {
              code_point = indexGB18030RangesCodePointFor(
                  (((gb18030_first - 0x81) * 10 + gb18030_second - 0x30) * 126 +
                   gb18030_third - 0x81) * 10 + bite - 0x30);
            }
            var buffer = [gb18030_second, gb18030_third, bite];
            gb18030_first = 0x00;
            gb18030_second = 0x00;
            gb18030_third = 0x00;
            if (code_point === null) {
              stream.prepend(buffer);
              return decoderError(fatal);
            }
            return code_point;
          }
          if (gb18030_second !== 0x00) {
            if (inRange(bite, 0x81, 0xFE)) {
              gb18030_third = bite;
              return null;
            }
            stream.prepend([gb18030_second, bite]);
            gb18030_first = 0x00;
            gb18030_second = 0x00;
            return decoderError(fatal);
          }
          if (gb18030_first !== 0x00) {
            if (inRange(bite, 0x30, 0x39)) {
              gb18030_second = bite;
              return null;
            }
            var lead = gb18030_first;
            var pointer = null;
            gb18030_first = 0x00;
            var offset = bite < 0x7F ? 0x40 : 0x41;
            if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE))
              pointer = (lead - 0x81) * 190 + (bite - offset);
            code_point = pointer === null ? null :
                indexCodePointFor(pointer, index('gb18030'));
            if (code_point === null && isASCIIByte(bite))
              stream.prepend(bite);
            if (code_point === null)
              return decoderError(fatal);
            return code_point;
          }
          if (isASCIIByte(bite))
            return bite;
          if (bite === 0x80)
            return 0x20AC;
          if (inRange(bite, 0x81, 0xFE)) {
            gb18030_first = bite;
            return null;
          }
          return decoderError(fatal);
        };
      }
      function GB18030Encoder(options, gbk_flag) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          if (code_point === 0xE5E5)
            return encoderError(code_point);
          if (gbk_flag && code_point === 0x20AC)
            return 0x80;
          var pointer = indexPointerFor(code_point, index('gb18030'));
          if (pointer !== null) {
            var lead = floor(pointer / 190) + 0x81;
            var trail = pointer % 190;
            var offset = trail < 0x3F ? 0x40 : 0x41;
            return [lead, trail + offset];
          }
          if (gbk_flag)
            return encoderError(code_point);
          pointer = indexGB18030RangesPointerFor(code_point);
          var byte1 = floor(pointer / 10 / 126 / 10);
          pointer = pointer - byte1 * 10 * 126 * 10;
          var byte2 = floor(pointer / 10 / 126);
          pointer = pointer - byte2 * 10 * 126;
          var byte3 = floor(pointer / 10);
          var byte4 = pointer - byte3 * 10;
          return [byte1 + 0x81,
                  byte2 + 0x30,
                  byte3 + 0x81,
                  byte4 + 0x30];
        };
      }
      encoders['gb18030'] = function(options) {
        return new GB18030Encoder(options);
      };
      decoders['gb18030'] = function(options) {
        return new GB18030Decoder(options);
      };
      function Big5Decoder(options) {
        var fatal = options.fatal;
        var  Big5_lead = 0x00;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && Big5_lead !== 0x00) {
            Big5_lead = 0x00;
            return decoderError(fatal);
          }
          if (bite === end_of_stream && Big5_lead === 0x00)
            return finished;
          if (Big5_lead !== 0x00) {
            var lead = Big5_lead;
            var pointer = null;
            Big5_lead = 0x00;
            var offset = bite < 0x7F ? 0x40 : 0x62;
            if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE))
              pointer = (lead - 0x81) * 157 + (bite - offset);
            switch (pointer) {
              case 1133: return [0x00CA, 0x0304];
              case 1135: return [0x00CA, 0x030C];
              case 1164: return [0x00EA, 0x0304];
              case 1166: return [0x00EA, 0x030C];
            }
            var code_point = (pointer === null) ? null :
                indexCodePointFor(pointer, index('big5'));
            if (code_point === null && isASCIIByte(bite))
              stream.prepend(bite);
            if (code_point === null)
              return decoderError(fatal);
            return code_point;
          }
          if (isASCIIByte(bite))
            return bite;
          if (inRange(bite, 0x81, 0xFE)) {
            Big5_lead = bite;
            return null;
          }
          return decoderError(fatal);
        };
      }
      function Big5Encoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          var pointer = indexBig5PointerFor(code_point);
          if (pointer === null)
            return encoderError(code_point);
          var lead = floor(pointer / 157) + 0x81;
          if (lead < 0xA1)
            return encoderError(code_point);
          var trail = pointer % 157;
          var offset = trail < 0x3F ? 0x40 : 0x62;
          return [lead, trail + offset];
        };
      }
      encoders['Big5'] = function(options) {
        return new Big5Encoder(options);
      };
      decoders['Big5'] = function(options) {
        return new Big5Decoder(options);
      };
      function EUCJPDecoder(options) {
        var fatal = options.fatal;
        var  eucjp_jis0212_flag = false,
             eucjp_lead = 0x00;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && eucjp_lead !== 0x00) {
            eucjp_lead = 0x00;
            return decoderError(fatal);
          }
          if (bite === end_of_stream && eucjp_lead === 0x00)
            return finished;
          if (eucjp_lead === 0x8E && inRange(bite, 0xA1, 0xDF)) {
            eucjp_lead = 0x00;
            return 0xFF61 - 0xA1 + bite;
          }
          if (eucjp_lead === 0x8F && inRange(bite, 0xA1, 0xFE)) {
            eucjp_jis0212_flag = true;
            eucjp_lead = bite;
            return null;
          }
          if (eucjp_lead !== 0x00) {
            var lead = eucjp_lead;
            eucjp_lead = 0x00;
            var code_point = null;
            if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) {
              code_point = indexCodePointFor(
                (lead - 0xA1) * 94 + (bite - 0xA1),
                index(!eucjp_jis0212_flag ? 'jis0208' : 'jis0212'));
            }
            eucjp_jis0212_flag = false;
            if (!inRange(bite, 0xA1, 0xFE))
              stream.prepend(bite);
            if (code_point === null)
              return decoderError(fatal);
            return code_point;
          }
          if (isASCIIByte(bite))
            return bite;
          if (bite === 0x8E || bite === 0x8F || inRange(bite, 0xA1, 0xFE)) {
            eucjp_lead = bite;
            return null;
          }
          return decoderError(fatal);
        };
      }
      function EUCJPEncoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          if (code_point === 0x00A5)
            return 0x5C;
          if (code_point === 0x203E)
            return 0x7E;
          if (inRange(code_point, 0xFF61, 0xFF9F))
            return [0x8E, code_point - 0xFF61 + 0xA1];
          if (code_point === 0x2212)
            code_point = 0xFF0D;
          var pointer = indexPointerFor(code_point, index('jis0208'));
          if (pointer === null)
            return encoderError(code_point);
          var lead = floor(pointer / 94) + 0xA1;
          var trail = pointer % 94 + 0xA1;
          return [lead, trail];
        };
      }
      encoders['EUC-JP'] = function(options) {
        return new EUCJPEncoder(options);
      };
      decoders['EUC-JP'] = function(options) {
        return new EUCJPDecoder(options);
      };
      function ISO2022JPDecoder(options) {
        var fatal = options.fatal;
        var states = {
          ASCII: 0,
          Roman: 1,
          Katakana: 2,
          LeadByte: 3,
          TrailByte: 4,
          EscapeStart: 5,
          Escape: 6
        };
        var  iso2022jp_decoder_state = states.ASCII,
             iso2022jp_decoder_output_state = states.ASCII,
             iso2022jp_lead = 0x00,
             iso2022jp_output_flag = false;
        this.handler = function(stream, bite) {
          switch (iso2022jp_decoder_state) {
          default:
          case states.ASCII:
            if (bite === 0x1B) {
              iso2022jp_decoder_state = states.EscapeStart;
              return null;
            }
            if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
                && bite !== 0x0F && bite !== 0x1B) {
              iso2022jp_output_flag = false;
              return bite;
            }
            if (bite === end_of_stream) {
              return finished;
            }
            iso2022jp_output_flag = false;
            return decoderError(fatal);
          case states.Roman:
            if (bite === 0x1B) {
              iso2022jp_decoder_state = states.EscapeStart;
              return null;
            }
            if (bite === 0x5C) {
              iso2022jp_output_flag = false;
              return 0x00A5;
            }
            if (bite === 0x7E) {
              iso2022jp_output_flag = false;
              return 0x203E;
            }
            if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
                && bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
              iso2022jp_output_flag = false;
              return bite;
            }
            if (bite === end_of_stream) {
              return finished;
            }
            iso2022jp_output_flag = false;
            return decoderError(fatal);
          case states.Katakana:
            if (bite === 0x1B) {
              iso2022jp_decoder_state = states.EscapeStart;
              return null;
            }
            if (inRange(bite, 0x21, 0x5F)) {
              iso2022jp_output_flag = false;
              return 0xFF61 - 0x21 + bite;
            }
            if (bite === end_of_stream) {
              return finished;
            }
            iso2022jp_output_flag = false;
            return decoderError(fatal);
          case states.LeadByte:
            if (bite === 0x1B) {
              iso2022jp_decoder_state = states.EscapeStart;
              return null;
            }
            if (inRange(bite, 0x21, 0x7E)) {
              iso2022jp_output_flag = false;
              iso2022jp_lead = bite;
              iso2022jp_decoder_state = states.TrailByte;
              return null;
            }
            if (bite === end_of_stream) {
              return finished;
            }
            iso2022jp_output_flag = false;
            return decoderError(fatal);
          case states.TrailByte:
            if (bite === 0x1B) {
              iso2022jp_decoder_state = states.EscapeStart;
              return decoderError(fatal);
            }
            if (inRange(bite, 0x21, 0x7E)) {
              iso2022jp_decoder_state = states.LeadByte;
              var pointer = (iso2022jp_lead - 0x21) * 94 + bite - 0x21;
              var code_point = indexCodePointFor(pointer, index('jis0208'));
              if (code_point === null)
                return decoderError(fatal);
              return code_point;
            }
            if (bite === end_of_stream) {
              iso2022jp_decoder_state = states.LeadByte;
              stream.prepend(bite);
              return decoderError(fatal);
            }
            iso2022jp_decoder_state = states.LeadByte;
            return decoderError(fatal);
          case states.EscapeStart:
            if (bite === 0x24 || bite === 0x28) {
              iso2022jp_lead = bite;
              iso2022jp_decoder_state = states.Escape;
              return null;
            }
            stream.prepend(bite);
            iso2022jp_output_flag = false;
            iso2022jp_decoder_state = iso2022jp_decoder_output_state;
            return decoderError(fatal);
          case states.Escape:
            var lead = iso2022jp_lead;
            iso2022jp_lead = 0x00;
            var state = null;
            if (lead === 0x28 && bite === 0x42)
              state = states.ASCII;
            if (lead === 0x28 && bite === 0x4A)
              state = states.Roman;
            if (lead === 0x28 && bite === 0x49)
              state = states.Katakana;
            if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
              state = states.LeadByte;
            if (state !== null) {
              iso2022jp_decoder_state = iso2022jp_decoder_state = state;
              var output_flag = iso2022jp_output_flag;
              iso2022jp_output_flag = true;
              return !output_flag ? null : decoderError(fatal);
            }
            stream.prepend([lead, bite]);
            iso2022jp_output_flag = false;
            iso2022jp_decoder_state = iso2022jp_decoder_output_state;
            return decoderError(fatal);
          }
        };
      }
      function ISO2022JPEncoder(options) {
        options.fatal;
        var states = {
          ASCII: 0,
          Roman: 1,
          jis0208: 2
        };
        var  iso2022jp_state = states.ASCII;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream &&
              iso2022jp_state !== states.ASCII) {
            stream.prepend(code_point);
            iso2022jp_state = states.ASCII;
            return [0x1B, 0x28, 0x42];
          }
          if (code_point === end_of_stream && iso2022jp_state === states.ASCII)
            return finished;
          if ((iso2022jp_state === states.ASCII ||
               iso2022jp_state === states.Roman) &&
              (code_point === 0x000E || code_point === 0x000F ||
               code_point === 0x001B)) {
            return encoderError(0xFFFD);
          }
          if (iso2022jp_state === states.ASCII &&
              isASCIICodePoint(code_point))
            return code_point;
          if (iso2022jp_state === states.Roman &&
              ((isASCIICodePoint(code_point) &&
               code_point !== 0x005C && code_point !== 0x007E) ||
              (code_point == 0x00A5 || code_point == 0x203E))) {
            if (isASCIICodePoint(code_point))
              return code_point;
            if (code_point === 0x00A5)
              return 0x5C;
            if (code_point === 0x203E)
              return 0x7E;
          }
          if (isASCIICodePoint(code_point) &&
              iso2022jp_state !== states.ASCII) {
            stream.prepend(code_point);
            iso2022jp_state = states.ASCII;
            return [0x1B, 0x28, 0x42];
          }
          if ((code_point === 0x00A5 || code_point === 0x203E) &&
              iso2022jp_state !== states.Roman) {
            stream.prepend(code_point);
            iso2022jp_state = states.Roman;
            return [0x1B, 0x28, 0x4A];
          }
          if (code_point === 0x2212)
            code_point = 0xFF0D;
          var pointer = indexPointerFor(code_point, index('jis0208'));
          if (pointer === null)
            return encoderError(code_point);
          if (iso2022jp_state !== states.jis0208) {
            stream.prepend(code_point);
            iso2022jp_state = states.jis0208;
            return [0x1B, 0x24, 0x42];
          }
          var lead = floor(pointer / 94) + 0x21;
          var trail = pointer % 94 + 0x21;
          return [lead, trail];
        };
      }
      encoders['ISO-2022-JP'] = function(options) {
        return new ISO2022JPEncoder(options);
      };
      decoders['ISO-2022-JP'] = function(options) {
        return new ISO2022JPDecoder(options);
      };
      function ShiftJISDecoder(options) {
        var fatal = options.fatal;
        var  Shift_JIS_lead = 0x00;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && Shift_JIS_lead !== 0x00) {
            Shift_JIS_lead = 0x00;
            return decoderError(fatal);
          }
          if (bite === end_of_stream && Shift_JIS_lead === 0x00)
            return finished;
          if (Shift_JIS_lead !== 0x00) {
            var lead = Shift_JIS_lead;
            var pointer = null;
            Shift_JIS_lead = 0x00;
            var offset = (bite < 0x7F) ? 0x40 : 0x41;
            var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1;
            if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC))
              pointer = (lead - lead_offset) * 188 + bite - offset;
            if (inRange(pointer, 8836, 10715))
              return 0xE000 - 8836 + pointer;
            var code_point = (pointer === null) ? null :
                  indexCodePointFor(pointer, index('jis0208'));
            if (code_point === null && isASCIIByte(bite))
              stream.prepend(bite);
            if (code_point === null)
              return decoderError(fatal);
            return code_point;
          }
          if (isASCIIByte(bite) || bite === 0x80)
            return bite;
          if (inRange(bite, 0xA1, 0xDF))
            return 0xFF61 - 0xA1 + bite;
          if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) {
            Shift_JIS_lead = bite;
            return null;
          }
          return decoderError(fatal);
        };
      }
      function ShiftJISEncoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point) || code_point === 0x0080)
            return code_point;
          if (code_point === 0x00A5)
            return 0x5C;
          if (code_point === 0x203E)
            return 0x7E;
          if (inRange(code_point, 0xFF61, 0xFF9F))
            return code_point - 0xFF61 + 0xA1;
          if (code_point === 0x2212)
            code_point = 0xFF0D;
          var pointer = indexShiftJISPointerFor(code_point);
          if (pointer === null)
            return encoderError(code_point);
          var lead = floor(pointer / 188);
          var lead_offset = (lead < 0x1F) ? 0x81 : 0xC1;
          var trail = pointer % 188;
          var offset = (trail < 0x3F) ? 0x40 : 0x41;
          return [lead + lead_offset, trail + offset];
        };
      }
      encoders['Shift_JIS'] = function(options) {
        return new ShiftJISEncoder(options);
      };
      decoders['Shift_JIS'] = function(options) {
        return new ShiftJISDecoder(options);
      };
      function EUCKRDecoder(options) {
        var fatal = options.fatal;
        var  euckr_lead = 0x00;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && euckr_lead !== 0) {
            euckr_lead = 0x00;
            return decoderError(fatal);
          }
          if (bite === end_of_stream && euckr_lead === 0)
            return finished;
          if (euckr_lead !== 0x00) {
            var lead = euckr_lead;
            var pointer = null;
            euckr_lead = 0x00;
            if (inRange(bite, 0x41, 0xFE))
              pointer = (lead - 0x81) * 190 + (bite - 0x41);
            var code_point = (pointer === null)
                  ? null : indexCodePointFor(pointer, index('euc-kr'));
            if (pointer === null && isASCIIByte(bite))
              stream.prepend(bite);
            if (code_point === null)
              return decoderError(fatal);
            return code_point;
          }
          if (isASCIIByte(bite))
            return bite;
          if (inRange(bite, 0x81, 0xFE)) {
            euckr_lead = bite;
            return null;
          }
          return decoderError(fatal);
        };
      }
      function EUCKREncoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          var pointer = indexPointerFor(code_point, index('euc-kr'));
          if (pointer === null)
            return encoderError(code_point);
          var lead = floor(pointer / 190) + 0x81;
          var trail = (pointer % 190) + 0x41;
          return [lead, trail];
        };
      }
      encoders['EUC-KR'] = function(options) {
        return new EUCKREncoder(options);
      };
      decoders['EUC-KR'] = function(options) {
        return new EUCKRDecoder(options);
      };
      function convertCodeUnitToBytes(code_unit, utf16be) {
        var byte1 = code_unit >> 8;
        var byte2 = code_unit & 0x00FF;
        if (utf16be)
          return [byte1, byte2];
        return [byte2, byte1];
      }
      function UTF16Decoder(utf16_be, options) {
        var fatal = options.fatal;
        var  utf16_lead_byte = null,
             utf16_lead_surrogate = null;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream && (utf16_lead_byte !== null ||
                                    utf16_lead_surrogate !== null)) {
            return decoderError(fatal);
          }
          if (bite === end_of_stream && utf16_lead_byte === null &&
              utf16_lead_surrogate === null) {
            return finished;
          }
          if (utf16_lead_byte === null) {
            utf16_lead_byte = bite;
            return null;
          }
          var code_unit;
          if (utf16_be) {
            code_unit = (utf16_lead_byte << 8) + bite;
          } else {
            code_unit = (bite << 8) + utf16_lead_byte;
          }
          utf16_lead_byte = null;
          if (utf16_lead_surrogate !== null) {
            var lead_surrogate = utf16_lead_surrogate;
            utf16_lead_surrogate = null;
            if (inRange(code_unit, 0xDC00, 0xDFFF)) {
              return 0x10000 + (lead_surrogate - 0xD800) * 0x400 +
                  (code_unit - 0xDC00);
            }
            stream.prepend(convertCodeUnitToBytes(code_unit, utf16_be));
            return decoderError(fatal);
          }
          if (inRange(code_unit, 0xD800, 0xDBFF)) {
            utf16_lead_surrogate = code_unit;
            return null;
          }
          if (inRange(code_unit, 0xDC00, 0xDFFF))
            return decoderError(fatal);
          return code_unit;
        };
      }
      function UTF16Encoder(utf16_be, options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (inRange(code_point, 0x0000, 0xFFFF))
            return convertCodeUnitToBytes(code_point, utf16_be);
          var lead = convertCodeUnitToBytes(
            ((code_point - 0x10000) >> 10) + 0xD800, utf16_be);
          var trail = convertCodeUnitToBytes(
            ((code_point - 0x10000) & 0x3FF) + 0xDC00, utf16_be);
          return lead.concat(trail);
        };
      }
      encoders['UTF-16BE'] = function(options) {
        return new UTF16Encoder(true, options);
      };
      decoders['UTF-16BE'] = function(options) {
        return new UTF16Decoder(true, options);
      };
      encoders['UTF-16LE'] = function(options) {
        return new UTF16Encoder(false, options);
      };
      decoders['UTF-16LE'] = function(options) {
        return new UTF16Decoder(false, options);
      };
      function XUserDefinedDecoder(options) {
        options.fatal;
        this.handler = function(stream, bite) {
          if (bite === end_of_stream)
            return finished;
          if (isASCIIByte(bite))
            return bite;
          return 0xF780 + bite - 0x80;
        };
      }
      function XUserDefinedEncoder(options) {
        options.fatal;
        this.handler = function(stream, code_point) {
          if (code_point === end_of_stream)
            return finished;
          if (isASCIICodePoint(code_point))
            return code_point;
          if (inRange(code_point, 0xF780, 0xF7FF))
            return code_point - 0xF780 + 0x80;
          return encoderError(code_point);
        };
      }
      encoders['x-user-defined'] = function(options) {
        return new XUserDefinedEncoder(options);
      };
      decoders['x-user-defined'] = function(options) {
        return new XUserDefinedDecoder(options);
      };
      if (!global['TextEncoder'])
        global['TextEncoder'] = TextEncoder;
      if (!global['TextDecoder'])
        global['TextDecoder'] = TextDecoder;
      if (module.exports) {
        module.exports = {
          TextEncoder: TextEncoder,
          TextDecoder: global['TextDecoder'],
          EncodingIndexes: global["encoding-indexes"]
        };
      }
    }(commonjsGlobal || {}));
    }(encoding$1));

    var encoding = encoding$1.exports;
    var textEncoding = {
      TextEncoder: encoding.TextEncoder,
      TextDecoder: encoding.TextDecoder,
    };

    /**
     * RequestType is the request types enumeration
     */
    exports.RequestType = void 0;
    (function (RequestType) {
        /** main frame */
        RequestType[RequestType["Document"] = 1] = "Document";
        /** (iframe) $subdocument */
        RequestType[RequestType["Subdocument"] = 2] = "Subdocument";
        /** (javascript, etc) $script */
        RequestType[RequestType["Script"] = 4] = "Script";
        /** (css) $stylesheet */
        RequestType[RequestType["Stylesheet"] = 8] = "Stylesheet";
        /** (flash, etc) $object */
        RequestType[RequestType["Object"] = 16] = "Object";
        /** (any image) $image */
        RequestType[RequestType["Image"] = 32] = "Image";
        /** (ajax/fetch) $xmlhttprequest */
        RequestType[RequestType["XmlHttpRequest"] = 64] = "XmlHttpRequest";
        /** (video/music) $media */
        RequestType[RequestType["Media"] = 128] = "Media";
        /** (any custom font) $font */
        RequestType[RequestType["Font"] = 256] = "Font";
        /** (a websocket connection) $websocket */
        RequestType[RequestType["Websocket"] = 512] = "Websocket";
        /** (navigator.sendBeacon()) $ping */
        RequestType[RequestType["Ping"] = 1024] = "Ping";
        /** (webrtc, in extension works via wrappers) $webrtc */
        RequestType[RequestType["Webrtc"] = 2048] = "Webrtc";
        /** any other request type */
        RequestType[RequestType["Other"] = 4096] = "Other";
    })(exports.RequestType || (exports.RequestType = {}));

    /**
     * Export logger implementation
     */
    exports.logger = console;
    /**
     * Set logger implementation
     *
     * @param loggerImpl
     */
    function setLogger(loggerImpl) {
        exports.logger = loggerImpl;
    }

    /**
     * Content Filter class
     *
     * Encapsulates response data filter logic
     * https://mail.mozilla.org/pipermail/dev-addons/2017-April/002729.html
     */
    var ContentFilter = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param filter implementation
         * @param context request context
         * @param htmlRules
         * @param replaceRules
         * @param onContentCallback
         */
        function ContentFilter(filter, context, htmlRules, replaceRules, onContentCallback) {
            this.filter = filter;
            this.context = context;
            this.htmlRules = htmlRules;
            this.replaceRules = replaceRules;
            this.content = '';
            this.onContentCallback = onContentCallback;
            this.initEncoders();
            this.initFilter();
        }
        /**
         * Initializes encoders
         */
        ContentFilter.prototype.initEncoders = function () {
            var set = this.charset ? this.charset : DEFAULT_CHARSET;
            // Redefining it as TextDecoder does not understand the iso- name
            if (set === LATIN_1) {
                set = WIN_1252;
            }
            this.decoder = new textEncoding.TextDecoder(set);
            if (set === DEFAULT_CHARSET) {
                this.encoder = new textEncoding.TextEncoder();
            }
            else {
                this.encoder = new textEncoding.TextEncoder(set, { NONSTANDARD_allowLegacyEncoding: true });
            }
        };
        /**
         * Initializes inner filter
         */
        ContentFilter.prototype.initFilter = function () {
            var _this = this;
            this.filter.ondata = function (event) {
                // check if app should apply decoding/encoding,
                // applications is checking ondata event,
                // because disconnecting onstart event is crashing loading of some requests
                var htmlRulesToApply = null;
                if (_this.htmlRules.length > 0
                    && ContentFilter.shouldApplyHtmlRules(_this.context.engineRequestType)) {
                    htmlRulesToApply = _this.htmlRules;
                }
                var replaceRulesToApply = null;
                if (_this.replaceRules.length > 0
                    && ContentFilter.shouldApplyReplaceRule(_this.context.engineRequestType, _this.context.contentType)) {
                    replaceRulesToApply = _this.replaceRules;
                }
                if (!htmlRulesToApply && !replaceRulesToApply) {
                    // disconnect on data
                    _this.filter.write(event.data);
                    _this.filter.disconnect();
                    return;
                }
                if (!_this.charset) {
                    try {
                        var charset = void 0;
                        /**
                         * If this.charset is undefined and requestType is DOCUMENT or SUBDOCUMENT, we try
                         * to detect charset from page <meta> tags
                         */
                        if (_this.context.engineRequestType === exports.RequestType.Subdocument
                            || _this.context.engineRequestType === exports.RequestType.Document) {
                            charset = ContentFilter.parseHtmlCharset(event.data);
                        }
                        /**
                         * If this.charset is undefined and requestType is Stylesheet, we try
                         * to detect charset from '@charset' directive
                         */
                        if (_this.context.engineRequestType === exports.RequestType.Stylesheet) {
                            charset = ContentFilter.parseCssCharset(event.data);
                        }
                        if (!charset) {
                            charset = DEFAULT_CHARSET;
                        }
                        if (charset && SUPPORTED_CHARSETS.indexOf(charset) >= 0) {
                            _this.charset = charset;
                            _this.initEncoders();
                            _this.content += _this.decoder.decode(event.data, { stream: true });
                        }
                        else {
                            // Charset is not supported
                            _this.disconnect(event.data);
                        }
                    }
                    catch (e) {
                        exports.logger.warn(e.message);
                        // on error we disconnect the filter from the request
                        _this.disconnect(event.data);
                    }
                }
                else {
                    _this.content += _this.decoder.decode(event.data, { stream: true });
                }
            };
            this.filter.onstop = function () {
                _this.content += _this.decoder.decode(); // finish stream
                _this.onContentCallback(_this.content, _this.context);
            };
            this.filter.onerror = function () {
                if (_this.filter.error) {
                    // eslint-disable-next-line max-len
                    exports.logger.debug("An error in the content filtering occurred: ".concat(_this.filter.error, ", request id: ").concat(_this.context.requestId));
                }
            };
        };
        /**
         * Writes data to stream
         *
         * @param content
         */
        ContentFilter.prototype.write = function (content) {
            this.filter.write(this.encoder.encode(content));
            this.filter.close();
        };
        /**
         * Sets charset
         *
         * @param charset
         */
        ContentFilter.prototype.setCharset = function (charset) {
            if (charset) {
                this.charset = charset;
                this.initEncoders();
            }
        };
        /**
         * Disconnects filter from stream
         *
         * @param data
         */
        ContentFilter.prototype.disconnect = function (data) {
            this.filter.write(data);
            this.filter.disconnect();
        };
        /**
         * Parses charset from html
         */
        ContentFilter.parseHtmlCharset = function (data) {
            var decoded = new textEncoding.TextDecoder('utf-8').decode(data).toLowerCase();
            return parseCharsetFromHtml(decoded);
        };
        /**
         * Parses charset from css
         */
        ContentFilter.parseCssCharset = function (data) {
            var decoded = new textEncoding.TextDecoder('utf-8').decode(data).toLowerCase();
            return parseCharsetFromCss(decoded);
        };
        /**
         * Checks if $replace rule should be applied to this request
         *
         * @returns {boolean}
         */
        ContentFilter.shouldApplyReplaceRule = function (requestType, contentType) {
            if (ContentFilter.replaceRulesRequestTypes.indexOf(requestType) >= 0) {
                return true;
            }
            if (requestType === exports.RequestType.Other && contentType) {
                for (var i = 0; i < ContentFilter.supportedContentTypes.length; i += 1) {
                    if (contentType.indexOf(ContentFilter.supportedContentTypes[i]) === 0) {
                        return true;
                    }
                }
            }
            return false;
        };
        /**
         * Checks if content filtration rules should by applied to this request
         * @param requestType Request type
         */
        ContentFilter.shouldApplyHtmlRules = function (requestType) {
            return requestType === exports.RequestType.Document
                || requestType === exports.RequestType.Subdocument;
        };
        /**
         * Contains collection of accepted content types
         */
        ContentFilter.supportedContentTypes = [
            'text/',
            'application/json',
            'application/xml',
            'application/xhtml+xml',
            'application/javascript',
            'application/x-javascript',
        ];
        /**
         * Contains collection of accepted request types for replace rules
         */
        ContentFilter.replaceRulesRequestTypes = [
            exports.RequestType.Document,
            exports.RequestType.Subdocument,
            exports.RequestType.Script,
            exports.RequestType.Stylesheet,
            exports.RequestType.XmlHttpRequest,
        ];
        /**
         * Contains collection of accepted request types for html rules
         */
        ContentFilter.htmlRulesRequestTypes = [
            exports.RequestType.Document,
            exports.RequestType.Subdocument,
        ];
        return ContentFilter;
    }());

    /**
     * Document parser wrapper
     */
    var DocumentParser = /** @class */ (function () {
        function DocumentParser() {
            // eslint-disable-next-line no-undef
            this.parser = new DOMParser();
            var errorneousParse = this.parser.parseFromString('<', 'text/xml');
            this.parsererrorNS = errorneousParse.getElementsByTagName('parsererror')[0].namespaceURI;
        }
        /**
         * Checking for parse errors
         * https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Error_handling
         * @param parsedDocument
         * @returns true if html cannot parsed
         */
        DocumentParser.prototype.isParseError = function (parsedDocument) {
            if (this.parsererrorNS === 'http://www.w3.org/1999/xhtml') {
                return parsedDocument.getElementsByTagName('parsererror').length > 0;
            }
            return parsedDocument.getElementsByTagNameNS(this.parsererrorNS, 'parsererror').length > 0;
        };
        /**
         * Parse html to document
         * @param html HTML content
         * @returns Document
         */
        DocumentParser.prototype.parse = function (html) {
            var doc = this.parser.parseFromString(html, 'text/html');
            if (this.isParseError(doc)) {
                return null;
            }
            return doc;
        };
        return DocumentParser;
    }());

    /**
     * Splits the string by the delimiter, ignoring escaped delimiters.
     *
     * @param str - string to split
     * @param delimiter - delimiter
     * @param escapeCharacter - escape character
     * @param preserveAllTokens - if true, preserve empty parts
     * @param unescape - if true, delete EscapeCharacter
     * @return array of string parts
     */
    function splitByDelimiterWithEscapeCharacter(str, delimiter, escapeCharacter, preserveAllTokens, unescape) {
        if (unescape === void 0) { unescape = true; }
        var parts = [];
        if (!str) {
            return parts;
        }
        if (str.startsWith(delimiter)) {
            // eslint-disable-next-line no-param-reassign
            str = str.substring(1);
        }
        if (!str.includes(escapeCharacter)) {
            parts = str.split(delimiter);
            if (!preserveAllTokens) {
                parts = parts.filter(function (x) { return !!x; });
            }
            return parts;
        }
        var sb = [];
        for (var i = 0; i < str.length; i += 1) {
            var c = str.charAt(i);
            if (c === delimiter) {
                if (i > 0 && str.charAt(i - 1) === escapeCharacter) {
                    if (unescape) {
                        sb.splice(sb.length - 1, 1);
                    }
                    sb.push(c);
                }
                else if (preserveAllTokens || sb.length > 0) {
                    var part = sb.join('');
                    parts.push(part);
                    sb = [];
                }
            }
            else {
                sb.push(c);
            }
        }
        if (preserveAllTokens || sb.length > 0) {
            parts.push(sb.join(''));
        }
        return parts;
    }
    /**
     * Checks if the specified string starts with a substr at the specified index.
     *
     * @param str - String to check
     * @param startIndex - Index to start checking from
     * @param substr - Substring to check
     * @return boolean true if it does start
     */
    function startsAtIndexWith(str, startIndex, substr) {
        if (str.length - startIndex < substr.length) {
            return false;
        }
        for (var i = 0; i < substr.length; i += 1) {
            if (str.charAt(startIndex + i) !== substr.charAt(i)) {
                return false;
            }
        }
        return true;
    }
    /**
     * Checks if str has unquoted substr
     *
     * @param str
     * @param substr
     */
    function hasUnquotedSubstring(str, substr) {
        var quotes = ['"', "'", '/'];
        if (!str.includes(substr)) {
            return false;
        }
        // eslint-disable-next-line @typescript-eslint/no-use-before-define
        if (indexOfAny(str, quotes) === -1) {
            return true;
        }
        var stack = [];
        for (var i = 0; i < str.length; i += 1) {
            var cursor = str[i];
            if (stack.length === 0) {
                if (startsAtIndexWith(str, i, substr)) {
                    return true;
                }
            }
            if (quotes.indexOf(cursor) >= 0
                && (i === 0 || str[i - 1] !== '\\')) {
                var last = stack.pop();
                if (!last) {
                    stack.push(cursor);
                }
                else if (last !== cursor) {
                    stack.push(last);
                    stack.push(cursor);
                }
            }
        }
        return false;
    }
    /**
     * djb2 hash algorithm
     *
     * @param str string to get hash
     * @param begin index from
     * @param end index to
     * @return {number} hash
     */
    function fastHashBetween(str, begin, end) {
        var hash = 5381;
        for (var idx = begin; idx < end; idx += 1) {
            hash = 33 * hash + str.charCodeAt(idx);
        }
        return hash;
    }
    /**
     * djb2 hash algorithm
     *
     * @param str string to get hash
     * @return {number} hash
     */
    function fastHash(str) {
        if (str === '') {
            return 0;
        }
        var len = str.length;
        return fastHashBetween(str, 0, len);
    }
    /**
     * Look for any symbol from "chars" array starting at "start" index or from the start of the string
     *
     * @param str   String to search
     * @param chars Chars to search for
     * @param start Start index (optional, inclusive)
     * @return int Index of the element found or -1 if not
     */
    function indexOfAny(str, chars, start) {
        if (start === void 0) { start = 0; }
        if (str.length <= start) {
            return -1;
        }
        for (var i = start; i < str.length; i += 1) {
            var c = str.charAt(i);
            if (chars.indexOf(c) > -1) {
                return i;
            }
        }
        return -1;
    }
    /**
     * Replaces all occurences of find with replace in str
     *
     * @param str
     * @param find
     * @param replace
     */
    function replaceAll(str, find, replace) {
        if (!str) {
            return str;
        }
        return str.split(find).join(replace);
    }
    /**
     * Checks if arrays are equal
     *
     * @param left array
     * @param right array
     * @return {boolean} true on equality
     */
    function stringArraysEquals(left, right) {
        if (!left || !right) {
            return !left && !right;
        }
        if (left.length !== right.length) {
            return false;
        }
        for (var i = 0; i < left.length; i += 1) {
            if (left[i] !== right[i]) {
                return false;
            }
        }
        return true;
    }
    /**
     * Checks if arrays have an intersection
     *
     * @param left array
     * @param right array
     * @return {boolean} true on equality
     */
    function stringArraysHaveIntersection(left, right) {
        if (!left || !right) {
            return true;
        }
        for (var i = 0; i < left.length; i += 1) {
            if (right.includes(left[i])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Html rule wildcard
     */
    var Wildcard = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param pattern
         */
        function Wildcard(pattern) {
            this.regexp = new RegExp(Wildcard.wildcardToRegex(pattern), 'i');
            this.shortcut = Wildcard.extractShortcut(pattern);
        }
        /**
         * Returns 'true' if input text is matching wildcard.
         * This method first checking shortcut -- if shortcut exists in input string -- than it checks regexp.
         *
         * @param input Input string
         * @return boolean if input string matches wildcard
         */
        Wildcard.prototype.matches = function (input) {
            if (!input) {
                return false;
            }
            if (input.toLowerCase().indexOf(this.shortcut) < 0) {
                return false;
            }
            return this.regexp.test(input);
        };
        /**
         * Converts wildcard to regular expression
         *
         * @param pattern The wildcard pattern to convert
         * @return string A regex equivalent of the given wildcard
         */
        Wildcard.wildcardToRegex = function (pattern) {
            var specials = [
                '\\', '*', '+', '?', '|', '{', '}', '[', ']', '(', ')', '^', '$', '.', '#',
            ];
            var specialsRegex = new RegExp("[".concat(specials.join('\\'), "]"), 'g');
            var result = pattern.replace(specialsRegex, '\\$&');
            result = replaceAll(result, '\\*', '[\\s\\S]*');
            result = replaceAll(result, '\\?', '.');
            return "^".concat(result, "$");
        };
        /**
         * Extracts longest string that does not contain * or ? symbols.
         *
         * @param pattern Wildcard pattern
         * @return Longest string without special symbols
         */
        Wildcard.extractShortcut = function (pattern) {
            var wildcardChars = ['*', '?'];
            var startIndex = 0;
            var endIndex = indexOfAny(pattern, wildcardChars);
            if (endIndex < 0) {
                return pattern.toLowerCase();
            }
            var shortcut = endIndex === startIndex ? '' : pattern.substring(startIndex, endIndex - startIndex);
            while (endIndex >= 0) {
                startIndex = startIndex + endIndex + 1;
                if (pattern.length <= startIndex) {
                    break;
                }
                endIndex = indexOfAny(pattern.substring(startIndex), wildcardChars);
                // eslint-disable-next-line max-len
                var tmpShortcut = endIndex < 0 ? pattern.substring(startIndex) : pattern.substring(startIndex, endIndex + startIndex);
                if (tmpShortcut.length > shortcut.length) {
                    shortcut = tmpShortcut;
                }
            }
            return shortcut.toLowerCase();
        };
        return Wildcard;
    }());

    /**
     * Html rule attributes
     *
     * rule = [domains] "$$" tagName [attributes]
     * domains = [domain0, domain1[, ...[, domainN]]]
     * attributes = "[" name0 = value0 "]" "[" name1 = value2 "]" ... "[" nameN = valueN "]"
     *
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#html-filtering-rules-syntax-1
     */
    var HtmlRuleAttributes = /** @class */ (function () {
        function HtmlRuleAttributes() {
        }
        return HtmlRuleAttributes;
    }());

    /**
     * Encapsulates html rule attributes parsing
     */
    var HtmlRuleParser = /** @class */ (function () {
        function HtmlRuleParser() {
        }
        /**
         * Parses html rule
         *
         * @param rule
         */
        HtmlRuleParser.parse = function (rule) {
            var result = new HtmlRuleAttributes();
            result.parentSearchLevel = HtmlRuleParser.DEFAULT_PARENT_SEARCH_LEVEL;
            result.maxLength = HtmlRuleParser.DEFAULT_MAX_LENGTH;
            var ruleContent = rule.getContent();
            var htmlAttributesStartIndex = ruleContent.indexOf(HtmlRuleParser.ATTRIBUTE_START_MARK);
            // Cutting tag name from string
            if (htmlAttributesStartIndex === -1) {
                result.tagName = ruleContent;
            }
            else {
                result.tagName = ruleContent.substring(0, htmlAttributesStartIndex);
            }
            var selector = [result.tagName];
            // Loading attributes filter
            while (htmlAttributesStartIndex !== -1) {
                var equalityIndex = ruleContent.indexOf('=', htmlAttributesStartIndex + 1);
                var quoteStartIndex = ruleContent.indexOf(HtmlRuleParser.QUOTES, equalityIndex + 1);
                var quoteEndIndex = HtmlRuleParser.getClosingQuoteIndex(ruleContent, quoteStartIndex + 1);
                if (quoteStartIndex === -1 || quoteEndIndex === -1) {
                    break;
                }
                var ruleEndIndex = ruleContent.indexOf(HtmlRuleParser.ATTRIBUTE_END_MARK, quoteEndIndex + 1);
                var attributeName = ruleContent.substring(htmlAttributesStartIndex + 1, equalityIndex);
                var attributeValue = ruleContent.substring(quoteStartIndex + 1, quoteEndIndex);
                attributeValue = replaceAll(attributeValue, '""', '"');
                switch (attributeName) {
                    case HtmlRuleParser.TAG_CONTENT_MASK:
                        result.tagContentFilter = attributeValue;
                        break;
                    case HtmlRuleParser.WILDCARD_MASK:
                        result.wildcard = new Wildcard(attributeValue);
                        break;
                    case HtmlRuleParser.TAG_CONTENT_MAX_LENGTH:
                        result.maxLength = parseInt(attributeValue, 10);
                        break;
                    case HtmlRuleParser.TAG_CONTENT_MIN_LENGTH:
                        result.minLength = parseInt(attributeValue, 10);
                        break;
                    case HtmlRuleParser.PARENT_ELEMENTS:
                        result.parentElements = attributeValue.split(',');
                        break;
                    case HtmlRuleParser.PARENT_SEARCH_LEVEL:
                        result.parentSearchLevel = parseInt(attributeValue, 10);
                        break;
                    default:
                        selector.push('[');
                        selector.push(attributeName);
                        selector.push('*="');
                        selector.push(attributeValue);
                        selector.push('"]');
                        break;
                }
                if (ruleEndIndex === -1) {
                    break;
                }
                htmlAttributesStartIndex = ruleContent.indexOf(HtmlRuleParser.ATTRIBUTE_START_MARK, ruleEndIndex + 1);
            }
            result.selector = selector.join('');
            // Validates selector immediately
            // eslint-disable-next-line no-undef
            if (typeof window !== 'undefined') {
                window.document.querySelectorAll(result.selector);
            }
            return result;
        };
        /**
         * Looks up next closing quotation
         * Skips double quotes in text like:
         * [tag-content="teas""ernet"]
         *
         * @param text
         * @param startIndex
         * @return {number}
         */
        HtmlRuleParser.getClosingQuoteIndex = function (text, startIndex) {
            var nextChar = HtmlRuleParser.QUOTES;
            var quoteIndex = startIndex - 2;
            while (nextChar === '"') {
                quoteIndex = text.indexOf(HtmlRuleParser.QUOTES, quoteIndex + 2);
                if (quoteIndex === -1) {
                    return -1;
                }
                nextChar = text.length === (quoteIndex + 1) ? '0' : text.charAt(quoteIndex + 1);
            }
            return quoteIndex;
        };
        HtmlRuleParser.ATTRIBUTE_START_MARK = '[';
        HtmlRuleParser.ATTRIBUTE_END_MARK = ']';
        HtmlRuleParser.QUOTES = '"';
        HtmlRuleParser.TAG_CONTENT_MASK = 'tag-content';
        HtmlRuleParser.WILDCARD_MASK = 'wildcard';
        HtmlRuleParser.TAG_CONTENT_MAX_LENGTH = 'max-length';
        HtmlRuleParser.TAG_CONTENT_MIN_LENGTH = 'min-length';
        HtmlRuleParser.PARENT_ELEMENTS = 'parent-elements';
        HtmlRuleParser.PARENT_SEARCH_LEVEL = 'parent-search-level';
        HtmlRuleParser.DEFAULT_PARENT_SEARCH_LEVEL = 3;
        HtmlRuleParser.DEFAULT_MAX_LENGTH = 8192;
        return HtmlRuleParser;
    }());

    /**
     * Encapsulates document element matching
     */
    var HtmlRuleSelector = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param parsedHtmlRule
         */
        function HtmlRuleSelector(parsedHtmlRule) {
            this.ruleAttributes = parsedHtmlRule;
        }
        /**
         * Returns matched elements for provided html rule
         *
         * @param doc document object
         * @return Array of elements or null
         */
        HtmlRuleSelector.prototype.getMatchedElements = function (doc) {
            var elements = doc.querySelectorAll(this.ruleAttributes.selector);
            var result = null;
            for (var i = 0; i < elements.length; i += 1) {
                var element = elements[i];
                var elementToDelete = null;
                if (this.isFiltered(element)) {
                    if (this.ruleAttributes.parentElements) {
                        var parentElement = this.searchForParentElement(element);
                        if (parentElement) {
                            elementToDelete = parentElement;
                        }
                    }
                    else {
                        elementToDelete = element;
                    }
                    if (elementToDelete) {
                        if (result === null) {
                            result = [];
                        }
                        result.push(elementToDelete);
                    }
                }
            }
            return result;
        };
        /**
         * Checks if element is filtered by provided rule
         *
         * @param element to check
         * @return {boolean} is element filtered
         */
        HtmlRuleSelector.prototype.isFiltered = function (element) {
            // Checking tag content length limits
            var content = element.innerHTML || '';
            if (this.ruleAttributes.maxLength && this.ruleAttributes.maxLength > 0) {
                // If max-length is set - checking content length (it should be lesser than max length)
                if (content.length > this.ruleAttributes.maxLength) {
                    return false;
                }
            }
            if (this.ruleAttributes.minLength && this.ruleAttributes.minLength > 0) {
                // If min-length is set - checking content length (it should be greater than min length)
                if (content.length < this.ruleAttributes.minLength) {
                    return false;
                }
            }
            if (!this.ruleAttributes.tagContentFilter && !this.ruleAttributes.wildcard) {
                // Rule does not depend on content
                return true;
            }
            if (!content) {
                return false;
            }
            // Checking tag content against filter
            if (this.ruleAttributes.tagContentFilter && content.indexOf(this.ruleAttributes.tagContentFilter) < 0) {
                return false;
            }
            // Checking tag content against the wildcard
            if (this.ruleAttributes.wildcard && !this.ruleAttributes.wildcard.matches(content)) {
                return false;
            }
            // All filters are passed, tag is filtered
            return true;
        };
        /**
         * Searches for parent element to delete.
         * Suitable parent elements are set by 'parent-elements' attribute.
         * If suitable element found - returns it. Otherwise - returns null.
         *
         * @param element Element evaluated against this rule
         * @return Parent element to be deleted
         */
        HtmlRuleSelector.prototype.searchForParentElement = function (element) {
            var parentElement = element.parentNode;
            for (var i = 0; i < this.ruleAttributes.parentSearchLevel; i += 1) {
                if (!parentElement) {
                    return null;
                }
                if (this.ruleAttributes.parentElements.indexOf(parentElement.tagName.toLowerCase()) > 0) {
                    return parentElement;
                }
                parentElement = parentElement.parentNode;
            }
            return null;
        };
        return HtmlRuleSelector;
    }());

    /**
     * Content filtering module
     * Handles Html filtering and replace rules
     */
    var ContentFiltering = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param modificationsListener
         */
        function ContentFiltering(modificationsListener) {
            /**
             * Document parser
             */
            this.documentParser = new DocumentParser();
            this.modificationsListener = modificationsListener;
        }
        /**
         * For correctly applying replace or content rules we have to work with the whole response content.
         * This function allows read response fully.
         * See some details here: https://mail.mozilla.org/pipermail/dev-addons/2017-April/002729.html
         *
         * @param requestContext
         * @param streamFilter
         * @param htmlRules
         * @param replaceRules
         * @param callback
         */
        // eslint-disable-next-line consistent-return
        ContentFiltering.prototype.handleResponse = function (requestContext, streamFilter, htmlRules, replaceRules, callback) {
            var _this = this;
            try {
                // eslint-disable-next-line max-len
                var contentFilter_1 = new ContentFilter(streamFilter, requestContext, htmlRules, replaceRules, function (content, context) {
                    var requestId = context.requestId, requestUrl = context.requestUrl, contentType = context.contentType;
                    _this.modificationsListener.onModificationStarted(Number(requestId));
                    try {
                        var charset = parseCharsetFromHeader(contentType);
                        if (ContentFiltering.shouldProcessRequest(context, charset)) {
                            contentFilter_1.setCharset(charset);
                            // eslint-disable-next-line no-param-reassign
                            content = callback(content, context);
                        }
                    }
                    catch (ex) {
                        exports.logger.error("Error while applying content filter to ".concat(requestUrl, ". Error: ").concat(ex));
                    }
                    finally {
                        _this.modificationsListener.onModificationFinished(Number(requestId));
                    }
                    contentFilter_1.write(content);
                });
            }
            catch (e) {
                // eslint-disable-next-line max-len
                exports.logger.error("An error has occurred in content filter for request ".concat(requestContext.requestId, " to ").concat(requestContext.requestUrl, ". Error: ").concat(e));
                callback('', null);
            }
        };
        /**
         * Checks if the request should be processed
         *
         * @param context
         * @param charset
         */
        ContentFiltering.shouldProcessRequest = function (context, charset) {
            if (!context.contentType) {
                return false;
            }
            if (context.statusCode !== 200) {
                return false;
            }
            if (charset && SUPPORTED_CHARSETS.indexOf(charset) < 0) {
                // Charset is detected and it is not supported
                exports.logger.warn("Skipping request ".concat(context.requestId, " with Content-Type ").concat(context.contentType));
                return false;
            }
            return true;
        };
        /**
         * Applies Html rules to the document.
         * If document wasn't modified then method will return null
         *
         * @param context Request context
         * @param {object} doc Document
         * @param {Array} rules Content rules
         * @returns null or document html
         */
        ContentFiltering.prototype.applyHtmlRules = function (context, doc, rules) {
            var deleted = [];
            for (var i = 0; i < rules.length; i += 1) {
                var rule = rules[i];
                var parsed = HtmlRuleParser.parse(rule);
                var elements = new HtmlRuleSelector(parsed).getMatchedElements(doc);
                if (elements) {
                    for (var j = 0; j < elements.length; j += 1) {
                        var element = elements[j];
                        if (element.parentNode && deleted.indexOf(element) < 0) {
                            element.parentNode.removeChild(element);
                            var tabId = context.tab.tabId, requestId = context.requestId, requestUrl = context.requestUrl;
                            this.modificationsListener.onHtmlRuleApplied(tabId, Number(requestId), element.innerHTML, requestUrl, rule);
                            deleted.push(element);
                        }
                    }
                }
            }
            // Add <!DOCTYPE html ... >
            // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/959
            // XMLSerializer is used to serialize doctype object
            // eslint-disable-next-line no-undef
            var doctype = doc.doctype ? "".concat(new XMLSerializer().serializeToString(doc.doctype), "\r\n") : '';
            return deleted.length > 0 ? doctype + doc.documentElement.outerHTML : null;
        };
        /**
         * Applies replace rules to content
         *
         * @param context
         * @param content
         * @param replaceRules
         */
        ContentFiltering.prototype.applyReplaceRules = function (context, content, replaceRules) {
            var modifiedContent = content;
            var appliedRules = [];
            // Sort replace rules alphabetically as noted here
            // https://github.com/AdguardTeam/CoreLibs/issues/45
            var sortedReplaceRules = replaceRules.sort(function (prev, next) {
                if (prev.getText() > next.getText()) {
                    return 1;
                }
                if (prev.getText() < next.getText()) {
                    return -1;
                }
                return 0;
            });
            for (var i = 0; i < sortedReplaceRules.length; i += 1) {
                var replaceRule = sortedReplaceRules[i];
                if (replaceRule.isAllowlist()) {
                    appliedRules.push(replaceRule);
                }
                else {
                    var advancedModifier = replaceRule.getAdvancedModifier();
                    modifiedContent = advancedModifier.getApplyFunc()(modifiedContent);
                    appliedRules.push(replaceRule);
                }
            }
            var result = content;
            if (modifiedContent) {
                result = modifiedContent;
            }
            if (appliedRules.length > 0) {
                // eslint-disable-next-line max-len
                var tabId = context.tab.tabId, requestId = context.requestId, requestUrl = context.requestUrl;
                this.modificationsListener.onReplaceRulesApplied(tabId, Number(requestId), requestUrl, appliedRules);
            }
            return result;
        };
        /**
         * Applies replace/content rules to the content
         *
         * @param context
         * @param {string} content
         * @param replaceRules
         * @param htmlRules
         * @param replaceRules
         * @param htmlRules
         * @returns {string} Modified content
         */
        ContentFiltering.prototype.applyRulesToContent = function (context, content, replaceRules, htmlRules) {
            if (!context) {
                return content;
            }
            var result = content;
            if (htmlRules && htmlRules.length > 0) {
                var doc = this.documentParser.parse(content);
                if (doc !== null) {
                    var modified = this.applyHtmlRules(context, doc, htmlRules);
                    if (modified !== null) {
                        result = modified;
                    }
                }
            }
            // response content is over 3MB, ignore it
            if (result.length > 3 * 1024 * 1024) {
                return result;
            }
            if (replaceRules) {
                result = this.applyReplaceRules(context, result, replaceRules);
            }
            return result;
        };
        /**
         * OnBeforeRequest handler
         *
         * @param streamFilter
         * @param requestContext
         * @param replaceRules
         * @param htmlRules
         */
        ContentFiltering.prototype.onBeforeRequest = function (streamFilter, requestContext, replaceRules, htmlRules) {
            var _this = this;
            if (!requestContext.requestId) {
                streamFilter.disconnect();
                return;
            }
            var method = requestContext.method, tab = requestContext.tab;
            if (!tab.tabId) {
                streamFilter.disconnect();
                return;
            }
            if (method !== 'GET' && method !== 'POST') {
                streamFilter.disconnect();
                return;
            }
            this.handleResponse(requestContext, streamFilter, htmlRules, replaceRules, function (content, context) { return _this.applyRulesToContent(context, content, replaceRules, htmlRules); });
        };
        return ContentFiltering;
    }());

    /**
     * This class stores found cosmetic css rules content in the appropriate collections
     * It is primarily used by the {@see CosmeticResult}
     */
    var CosmeticStylesResult = /** @class */ (function () {
        /**
         * Constructor
         */
        function CosmeticStylesResult() {
            this.generic = [];
            this.specific = [];
            this.genericExtCss = [];
            this.specificExtCss = [];
        }
        /**
         * Appends rule to the appropriate collection
         * @param rule
         */
        CosmeticStylesResult.prototype.append = function (rule) {
            if (rule.isGeneric()) {
                if (rule.isExtendedCss()) {
                    this.genericExtCss.push(rule);
                }
                else {
                    this.generic.push(rule);
                }
            }
            else if (rule.isExtendedCss()) {
                this.specificExtCss.push(rule);
            }
            else {
                this.specific.push(rule);
            }
        };
        return CosmeticStylesResult;
    }());

    var scriptlets_umd = {exports: {}};

    (function (factory) {
        factory();
    }((function () {
        var getWildcardSymbol = function getWildcardSymbol() {
          return '*';
        };
        function randomId() {
          return Math.random().toString(36).substr(2, 9);
        }
        function setPropertyAccess(object, property, descriptor) {
          var currentDescriptor = Object.getOwnPropertyDescriptor(object, property);
          if (currentDescriptor && !currentDescriptor.configurable) {
            return false;
          }
          Object.defineProperty(object, property, descriptor);
          return true;
        }
        function getPropertyInChain(base, chain) {
          var pos = chain.indexOf('.');
          if (pos === -1) {
            return {
              base: base,
              prop: chain
            };
          }
          var prop = chain.slice(0, pos);
          if (base === null) {
            return {
              base: base,
              prop: prop,
              chain: chain
            };
          }
          var nextBase = base[prop];
          chain = chain.slice(pos + 1);
          if (nextBase !== undefined) {
            return getPropertyInChain(nextBase, chain);
          }
          Object.defineProperty(base, prop, {
            configurable: true
          });
          return {
            base: nextBase,
            prop: prop,
            chain: chain
          };
        }
        function getWildcardPropertyInChain(base, chain) {
          var lookThrough = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
          var output = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
          var pos = chain.indexOf('.');
          if (pos === -1) {
            if (chain === getWildcardSymbol() || chain === '[]') {
              for (var key in base) {
                if (Object.prototype.hasOwnProperty.call(base, key)) {
                  output.push({
                    base: base,
                    prop: key
                  });
                }
              }
            } else {
              output.push({
                base: base,
                prop: chain
              });
            }
            return output;
          }
          var prop = chain.slice(0, pos);
          var shouldLookThrough = prop === '[]' && Array.isArray(base) || prop === getWildcardSymbol() && base instanceof Object;
          if (shouldLookThrough) {
            var nextProp = chain.slice(pos + 1);
            var baseKeys = Object.keys(base);
            baseKeys.forEach(function (key) {
              var item = base[key];
              getWildcardPropertyInChain(item, nextProp, lookThrough, output);
            });
          }
          var nextBase = base[prop];
          chain = chain.slice(pos + 1);
          if (nextBase !== undefined) {
            getWildcardPropertyInChain(nextBase, chain, lookThrough, output);
          }
          return output;
        }
        var nativeIsNaN = function nativeIsNaN(num) {
          var native = Number.isNaN || window.isNaN;
          return native(num);
        };
        var nativeIsFinite = function nativeIsFinite(num) {
          var native = Number.isFinite || window.isFinite;
          return native(num);
        };
        var getNumberFromString = function getNumberFromString(rawString) {
          var parsedDelay = parseInt(rawString, 10);
          var validDelay = nativeIsNaN(parsedDelay) ? null : parsedDelay;
          return validDelay;
        };
        var getObjectEntries = function getObjectEntries(object) {
          var keys = Object.keys(object);
          var entries = [];
          keys.forEach(function (key) {
            return entries.push([key, object[key]]);
          });
          return entries;
        };
        var getObjectFromEntries = function getObjectFromEntries(entries) {
          var output = entries.reduce(function (acc, el) {
            var key = el[0];
            var value = el[1];
            acc[key] = value;
            return acc;
          }, {});
          return output;
        };
        var isEmptyObject = function isEmptyObject(obj) {
          return Object.keys(obj).length === 0;
        };
        var safeGetDescriptor = function safeGetDescriptor(obj, prop) {
          var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
          if (descriptor && descriptor.configurable) {
            return descriptor;
          }
          return null;
        };
        var replaceAll = function replaceAll(input, substr, newSubstr) {
          return input.split(substr).join(newSubstr);
        };
        var escapeRegExp = function escapeRegExp(str) {
          return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        };
        var toRegExp = function toRegExp() {
          var input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
          var DEFAULT_VALUE = '.?';
          var FORWARD_SLASH = '/';
          if (input === '') {
            return new RegExp(DEFAULT_VALUE);
          }
          if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) {
            return new RegExp(input.slice(1, -1));
          }
          var escaped = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
          return new RegExp(escaped);
        };
        var validateStrPattern = function validateStrPattern(input) {
          var FORWARD_SLASH = '/';
          var str = input;
          if (input[0] === FORWARD_SLASH && input[input.length - 1] === FORWARD_SLASH) {
            str = input.slice(1, -1);
          }
          var isValid;
          try {
            isValid = new RegExp(str);
            isValid = true;
          } catch (e) {
            isValid = false;
          }
          return isValid;
        };
        var getBeforeRegExp = function getBeforeRegExp(str, rx) {
          var index = str.search(rx);
          return str.substring(0, index);
        };
        var startsWith = function startsWith(str, prefix) {
          return !!str && str.indexOf(prefix) === 0;
        };
        var endsWith = function endsWith(str, ending) {
          return !!str && str.indexOf(ending) === str.length - ending.length;
        };
        var substringAfter = function substringAfter(str, separator) {
          if (!str) {
            return str;
          }
          var index = str.indexOf(separator);
          return index < 0 ? '' : str.substring(index + separator.length);
        };
        var substringBefore = function substringBefore(str, separator) {
          if (!str || !separator) {
            return str;
          }
          var index = str.indexOf(separator);
          return index < 0 ? str : str.substring(0, index);
        };
        var wrapInSingleQuotes = function wrapInSingleQuotes(str) {
          if (str[0] === '\'' && str[str.length - 1] === '\'' || str[0] === '"' && str[str.length - 1] === '"') {
            str = str.substring(1, str.length - 1);
          }
          str = str.replace(/\'/g, '"');
          return "'".concat(str, "'");
        };
        var getStringInBraces = function getStringInBraces(str) {
          var firstIndex = str.indexOf('(');
          var lastIndex = str.lastIndexOf(')');
          return str.substring(firstIndex + 1, lastIndex);
        };
        var convertRtcConfigToString = function convertRtcConfigToString(config) {
          var UNDEF_STR = 'undefined';
          var str = UNDEF_STR;
          if (config === null) {
            str = 'null';
          } else if (config instanceof Object) {
            var SERVERS_PROP_NAME = 'iceServers';
            var URLS_PROP_NAME = 'urls';
            if (Object.prototype.hasOwnProperty.call(config, SERVERS_PROP_NAME) && Object.prototype.hasOwnProperty.call(config[SERVERS_PROP_NAME][0], URLS_PROP_NAME) && !!config[SERVERS_PROP_NAME][0][URLS_PROP_NAME]) {
              str = config[SERVERS_PROP_NAME][0][URLS_PROP_NAME].toString();
            }
          }
          return str;
        };
        var validateMatchStr = function validateMatchStr(match) {
          var INVERT_MARKER = '!';
          var str = match;
          if (startsWith(match, INVERT_MARKER)) {
            str = match.slice(1);
          }
          return validateStrPattern(str);
        };
        var parseMatchArg = function parseMatchArg(match) {
          var INVERT_MARKER = '!';
          var isInvertedMatch = startsWith(match, INVERT_MARKER);
          var matchValue = isInvertedMatch ? match.slice(1) : match;
          var matchRegexp = toRegExp(matchValue);
          return {
            isInvertedMatch: isInvertedMatch,
            matchRegexp: matchRegexp
          };
        };
        var parseDelayArg = function parseDelayArg(delay) {
          var INVERT_MARKER = '!';
          var isInvertedDelayMatch = startsWith(delay, INVERT_MARKER);
          var delayValue = isInvertedDelayMatch ? delay.slice(1) : delay;
          delayValue = parseInt(delayValue, 10);
          var delayMatch = nativeIsNaN(delayValue) ? null : delayValue;
          return {
            isInvertedDelayMatch: isInvertedDelayMatch,
            delayMatch: delayMatch
          };
        };
        var objectToString = function objectToString(obj) {
          return isEmptyObject(obj) ? '{}' : getObjectEntries(obj).map(function (pair) {
            var key = pair[0];
            var value = pair[1];
            var recordValueStr = value;
            if (value instanceof Object) {
              recordValueStr = "{ ".concat(objectToString(value), " }");
            }
            return "".concat(key, ":\"").concat(recordValueStr, "\"");
          }).join(' ');
        };
        var convertTypeToString = function convertTypeToString(value) {
          var output;
          if (typeof value === 'undefined') {
            output = 'undefined';
          } else if (typeof value === 'object') {
            if (value === null) {
              output = 'null';
            } else {
              output = objectToString(value);
            }
          } else {
            output = value.toString();
          }
          return output;
        };
        function createOnErrorHandler(rid) {
          var nativeOnError = window.onerror;
          return function onError(error) {
            if (typeof error === 'string' && error.indexOf(rid) !== -1) {
              return true;
            }
            if (nativeOnError instanceof Function) {
              for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
                args[_key - 1] = arguments[_key];
              }
              return nativeOnError.apply(this, [error].concat(args));
            }
            return false;
          };
        }
        var noopFunc = function noopFunc() {};
        var noopNull = function noopNull() {
          return null;
        };
        var trueFunc = function trueFunc() {
          return true;
        };
        var falseFunc = function falseFunc() {
          return false;
        };
        function noopThis() {
          return this;
        }
        var noopStr = function noopStr() {
          return '';
        };
        var noopArray = function noopArray() {
          return [];
        };
        var noopObject = function noopObject() {
          return {};
        };
        var noopPromiseReject = function noopPromiseReject() {
          return Promise.reject();
        };
        var noopPromiseResolve = function noopPromiseResolve() {
          return Promise.resolve(new Response());
        };
        var hit = function hit(source, message) {
          if (source.verbose !== true) {
            return;
          }
          try {
            var log = console.log.bind(console);
            var trace = console.trace.bind(console);
            var prefix = source.ruleText || '';
            if (source.domainName) {
              var AG_SCRIPTLET_MARKER = '#%#//';
              var UBO_SCRIPTLET_MARKER = '##+js';
              var ruleStartIndex;
              if (source.ruleText.indexOf(AG_SCRIPTLET_MARKER) > -1) {
                ruleStartIndex = source.ruleText.indexOf(AG_SCRIPTLET_MARKER);
              } else if (source.ruleText.indexOf(UBO_SCRIPTLET_MARKER) > -1) {
                ruleStartIndex = source.ruleText.indexOf(UBO_SCRIPTLET_MARKER);
              }
              var rulePart = source.ruleText.slice(ruleStartIndex);
              prefix = "".concat(source.domainName).concat(rulePart);
            }
            var LOG_MARKER = 'log: ';
            if (message) {
              if (message.indexOf(LOG_MARKER) === -1) {
                log("".concat(prefix, " message:\n").concat(message));
              } else {
                log(message.slice(LOG_MARKER.length));
              }
            }
            log("".concat(prefix, " trace start"));
            if (trace) {
              trace();
            }
            log("".concat(prefix, " trace end"));
          } catch (e) {
          }
          if (typeof window.__debug === 'function') {
            window.__debug(source);
          }
        };
        var observeDOMChanges = function observeDOMChanges(callback) {
          var observeAttrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
          var attrsToObserve = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
          var throttle = function throttle(method, delay) {
            var wait = false;
            var savedArgs;
            var wrapper = function wrapper() {
              for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
                args[_key] = arguments[_key];
              }
              if (wait) {
                savedArgs = args;
                return;
              }
              method.apply(void 0, args);
              wait = true;
              setTimeout(function () {
                wait = false;
                if (savedArgs) {
                  wrapper(savedArgs);
                  savedArgs = null;
                }
              }, delay);
            };
            return wrapper;
          };
          var THROTTLE_DELAY_MS = 20;
          var observer = new MutationObserver(throttle(callbackWrapper, THROTTLE_DELAY_MS));
          var connect = function connect() {
            if (attrsToObserve.length > 0) {
              observer.observe(document.documentElement, {
                childList: true,
                subtree: true,
                attributes: observeAttrs,
                attributeFilter: attrsToObserve
              });
            } else {
              observer.observe(document.documentElement, {
                childList: true,
                subtree: true,
                attributes: observeAttrs
              });
            }
          };
          var disconnect = function disconnect() {
            observer.disconnect();
          };
          function callbackWrapper() {
            disconnect();
            callback();
            connect();
          }
          connect();
        };
        var matchStackTrace = function matchStackTrace(stackMatch, stackTrace) {
          if (!stackMatch || stackMatch === '') {
            return true;
          }
          var stackRegexp = toRegExp(stackMatch);
          var refinedStackTrace = stackTrace.split('\n').slice(2)
          .map(function (line) {
            return line.trim();
          })
          .join('\n');
          return stackRegexp.test(refinedStackTrace);
        };
        var flatten = function flatten(input) {
          var stack = [];
          input.forEach(function (el) {
            return stack.push(el);
          });
          var res = [];
          while (stack.length) {
            var next = stack.pop();
            if (Array.isArray(next)) {
              next.forEach(function (el) {
                return stack.push(el);
              });
            } else {
              res.push(next);
            }
          }
          return res.reverse();
        };
        var findHostElements = function findHostElements(rootElement) {
          var hosts = [];
          var domElems = rootElement.querySelectorAll('*');
          domElems.forEach(function (el) {
            if (el.shadowRoot) {
              hosts.push(el);
            }
          });
          return hosts;
        };
        var pierceShadowDom = function pierceShadowDom(selector, hostElements) {
          var targets = [];
          var innerHostsAcc = [];
          hostElements.forEach(function (host) {
            var simpleElems = host.querySelectorAll(selector);
            targets = targets.concat([].slice.call(simpleElems));
            var shadowRootElem = host.shadowRoot;
            var shadowChildren = shadowRootElem.querySelectorAll(selector);
            targets = targets.concat([].slice.call(shadowChildren));
            innerHostsAcc.push(findHostElements(shadowRootElem));
          });
          var innerHosts = flatten(innerHostsAcc);
          return {
            targets: targets,
            innerHosts: innerHosts
          };
        };
        var prepareCookie = function prepareCookie(name, value) {
          if (!name || !value) {
            return null;
          }
          var valueToSet;
          if (value === 'true') {
            valueToSet = 'true';
          } else if (value === 'True') {
            valueToSet = 'True';
          } else if (value === 'false') {
            valueToSet = 'false';
          } else if (value === 'False') {
            valueToSet = 'False';
          } else if (value === 'yes') {
            valueToSet = 'yes';
          } else if (value === 'Yes') {
            valueToSet = 'Yes';
          } else if (value === 'Y') {
            valueToSet = 'Y';
          } else if (value === 'no') {
            valueToSet = 'no';
          } else if (value === 'ok') {
            valueToSet = 'ok';
          } else if (value === 'OK') {
            valueToSet = 'OK';
          } else if (/^\d+$/.test(value)) {
            valueToSet = parseFloat(value);
            if (nativeIsNaN(valueToSet)) {
              return null;
            }
            if (Math.abs(valueToSet) < 0 || Math.abs(valueToSet) > 15) {
              return null;
            }
          } else {
            return null;
          }
          var pathToSet = 'path=/;';
          var cookieData = "".concat(encodeURIComponent(name), "=").concat(encodeURIComponent(valueToSet), "; ").concat(pathToSet);
          return cookieData;
        };
        var shouldMatchAnyDelay = function shouldMatchAnyDelay(delay) {
          return delay === getWildcardSymbol();
        };
        var getMatchDelay = function getMatchDelay(delay) {
          var DEFAULT_DELAY = 1000;
          var parsedDelay = parseInt(delay, 10);
          var delayMatch = nativeIsNaN(parsedDelay) ? DEFAULT_DELAY
          : parsedDelay;
          return delayMatch;
        };
        var isDelayMatched = function isDelayMatched(inputDelay, realDelay) {
          return shouldMatchAnyDelay(inputDelay) || realDelay === getMatchDelay(inputDelay);
        };
        var getBoostMultiplier = function getBoostMultiplier(boost) {
          var DEFAULT_MULTIPLIER = 0.05;
          var MIN_MULTIPLIER = 0.02;
          var MAX_MULTIPLIER = 50;
          var parsedBoost = parseFloat(boost);
          var boostMultiplier = nativeIsNaN(parsedBoost) || !nativeIsFinite(parsedBoost) ? DEFAULT_MULTIPLIER
          : parsedBoost;
          if (boostMultiplier < MIN_MULTIPLIER) {
            boostMultiplier = MIN_MULTIPLIER;
          }
          if (boostMultiplier > MAX_MULTIPLIER) {
            boostMultiplier = MAX_MULTIPLIER;
          }
          return boostMultiplier;
        };
        var getRequestData = function getRequestData(request) {
          var REQUEST_INIT_OPTIONS = ['url', 'method', 'headers', 'body', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity'];
          var entries = REQUEST_INIT_OPTIONS.map(function (key) {
            var value = request[key];
            return [key, value];
          });
          return getObjectFromEntries(entries);
        };
        var getFetchData = function getFetchData(args) {
          var fetchPropsObj = {};
          var fetchUrl;
          var fetchInit;
          if (args[0] instanceof Request) {
            var requestData = getRequestData(args[0]);
            fetchUrl = requestData.url;
            fetchInit = requestData;
          } else {
            fetchUrl = args[0];
            fetchInit = args[1];
          }
          fetchPropsObj.url = fetchUrl;
          if (fetchInit instanceof Object) {
            Object.keys(fetchInit).forEach(function (prop) {
              fetchPropsObj[prop] = fetchInit[prop];
            });
          }
          return fetchPropsObj;
        };
        var parseMatchProps = function parseMatchProps(propsToMatchStr) {
          var PROPS_DIVIDER = ' ';
          var PAIRS_MARKER = ':';
          var propsObj = {};
          var props = propsToMatchStr.split(PROPS_DIVIDER);
          props.forEach(function (prop) {
            var dividerInd = prop.indexOf(PAIRS_MARKER);
            if (dividerInd === -1) {
              propsObj.url = prop;
            } else {
              var key = prop.slice(0, dividerInd);
              var value = prop.slice(dividerInd + 1);
              propsObj[key] = value;
            }
          });
          return propsObj;
        };
        var validateParsedData = function validateParsedData(data) {
          return Object.values(data).every(function (value) {
            return validateStrPattern(value);
          });
        };
        var getMatchPropsData = function getMatchPropsData(data) {
          var matchData = {};
          Object.keys(data).forEach(function (key) {
            matchData[key] = toRegExp(data[key]);
          });
          return matchData;
        };
        var handleOldReplacement = function handleOldReplacement(replacement) {
          var result;
          if (!replacement) {
            result = noopFunc;
          } else if (replacement === 'trueFunc') {
            result = trueFunc;
          } else if (replacement.indexOf('=') > -1) {
            var isProp = startsWith(replacement, '{') && endsWith(replacement, '}');
            if (isProp) {
              var propertyPart = replacement.slice(1, -1);
              var propertyName = substringBefore(propertyPart, '=');
              var propertyValue = substringAfter(propertyPart, '=');
              if (propertyValue === 'noopFunc') {
                result = {};
                result[propertyName] = noopFunc;
              }
            }
          }
          return result;
        };
        var createDecoy = function createDecoy(args) {
          var OBJECT_TAG_NAME = 'object';
          var OBJECT_URL_PROP_NAME = 'data';
          var IFRAME_TAG_NAME = 'iframe';
          var IFRAME_URL_PROP_NAME = 'src';
          var replacement = args.replacement,
              url = args.url,
              delay = args.delay;
          var tag;
          var urlProp;
          if (replacement === 'obj') {
            tag = OBJECT_TAG_NAME;
            urlProp = OBJECT_URL_PROP_NAME;
          } else {
            tag = IFRAME_TAG_NAME;
            urlProp = IFRAME_URL_PROP_NAME;
          }
          var decoy = document.createElement(tag);
          decoy[urlProp] = url;
          decoy.style.setProperty('height', '1px', 'important');
          decoy.style.setProperty('position', 'fixed', 'important');
          decoy.style.setProperty('top', '-1px', 'important');
          decoy.style.setProperty('width', '1px', 'important');
          document.body.appendChild(decoy);
          setTimeout(function () {
            return decoy.remove();
          }, delay * 1000);
          return decoy;
        };
        var getPreventGetter = function getPreventGetter(nativeGetter) {
          var preventGetter = function preventGetter(target, prop) {
            if (prop && prop === 'closed') {
              return false;
            }
            if (typeof nativeGetter === 'function') {
              return noopFunc;
            }
            return prop && target[prop];
          };
          return preventGetter;
        };
        var validateType = function validateType(type) {
          return typeof type !== 'undefined';
        };
        var validateListener = function validateListener(listener) {
          return typeof listener !== 'undefined' && (typeof listener === 'function' || typeof listener === 'object'
          && listener !== null && typeof listener.handleEvent === 'function');
        };
        var listenerToString = function listenerToString(listener) {
          return typeof listener === 'function' ? listener.toString() : listener.handleEvent.toString();
        };
        var dependencies = Object.freeze({
            __proto__: null,
            getWildcardSymbol: getWildcardSymbol,
            randomId: randomId,
            setPropertyAccess: setPropertyAccess,
            getPropertyInChain: getPropertyInChain,
            getWildcardPropertyInChain: getWildcardPropertyInChain,
            replaceAll: replaceAll,
            escapeRegExp: escapeRegExp,
            toRegExp: toRegExp,
            validateStrPattern: validateStrPattern,
            getBeforeRegExp: getBeforeRegExp,
            startsWith: startsWith,
            endsWith: endsWith,
            substringAfter: substringAfter,
            substringBefore: substringBefore,
            wrapInSingleQuotes: wrapInSingleQuotes,
            getStringInBraces: getStringInBraces,
            convertRtcConfigToString: convertRtcConfigToString,
            validateMatchStr: validateMatchStr,
            parseMatchArg: parseMatchArg,
            parseDelayArg: parseDelayArg,
            objectToString: objectToString,
            convertTypeToString: convertTypeToString,
            createOnErrorHandler: createOnErrorHandler,
            noopFunc: noopFunc,
            noopNull: noopNull,
            trueFunc: trueFunc,
            falseFunc: falseFunc,
            noopThis: noopThis,
            noopStr: noopStr,
            noopArray: noopArray,
            noopObject: noopObject,
            noopPromiseReject: noopPromiseReject,
            noopPromiseResolve: noopPromiseResolve,
            hit: hit,
            observeDOMChanges: observeDOMChanges,
            matchStackTrace: matchStackTrace,
            findHostElements: findHostElements,
            pierceShadowDom: pierceShadowDom,
            flatten: flatten,
            prepareCookie: prepareCookie,
            nativeIsNaN: nativeIsNaN,
            nativeIsFinite: nativeIsFinite,
            getNumberFromString: getNumberFromString,
            shouldMatchAnyDelay: shouldMatchAnyDelay,
            getMatchDelay: getMatchDelay,
            isDelayMatched: isDelayMatched,
            getBoostMultiplier: getBoostMultiplier,
            getRequestData: getRequestData,
            getFetchData: getFetchData,
            parseMatchProps: parseMatchProps,
            validateParsedData: validateParsedData,
            getMatchPropsData: getMatchPropsData,
            getObjectEntries: getObjectEntries,
            getObjectFromEntries: getObjectFromEntries,
            isEmptyObject: isEmptyObject,
            safeGetDescriptor: safeGetDescriptor,
            handleOldReplacement: handleOldReplacement,
            createDecoy: createDecoy,
            getPreventGetter: getPreventGetter,
            validateType: validateType,
            validateListener: validateListener,
            listenerToString: listenerToString
        });
        function attachDependencies(scriptlet) {
          var _scriptlet$injections = scriptlet.injections,
              injections = _scriptlet$injections === void 0 ? [] : _scriptlet$injections;
          return injections.reduce(function (accum, dep) {
            return "".concat(accum, "\n").concat(dependencies[dep.name]);
          }, scriptlet.toString());
        }
        function addCall(scriptlet, code) {
          return "".concat(code, ";\n        const updatedArgs = args ? [].concat(source).concat(args) : [source];\n        try {\n            ").concat(scriptlet.name, ".apply(this, updatedArgs);\n        } catch (e) {\n            console.log(e);\n        }\n    ");
        }
        function passSourceAndProps(source, code) {
          if (source.hit) {
            source.hit = source.hit.toString();
          }
          var sourceString = JSON.stringify(source);
          var argsString = source.args ? "[".concat(source.args.map(JSON.stringify), "]") : undefined;
          var params = argsString ? "".concat(sourceString, ", ").concat(argsString) : sourceString;
          return "(function(source, args){\n".concat(code, "\n})(").concat(params, ");");
        }
        function wrapInNonameFunc(code) {
          return "function(source, args){\n".concat(code, "\n}");
        }
        function _defineProperty(obj, key, value) {
          if (key in obj) {
            Object.defineProperty(obj, key, {
              value: value,
              enumerable: true,
              configurable: true,
              writable: true
            });
          } else {
            obj[key] = value;
          }
          return obj;
        }
        var defineProperty = _defineProperty;
        function iterateWithTransitions(iterable, transitions, init, args) {
          var state = init || Object.keys(transitions)[0];
          for (var i = 0; i < iterable.length; i += 1) {
            state = transitions[state](iterable, i, args);
          }
          return state;
        }
        var ADG_SCRIPTLET_MASK = '#//scriptlet';
        var wordSaver = function wordSaver() {
          var str = '';
          var strs = [];
          var saveSymb = function saveSymb(s) {
            str += s;
            return str;
          };
          var saveStr = function saveStr() {
            strs.push(str);
            str = '';
          };
          var getAll = function getAll() {
            return [].concat(strs);
          };
          return {
            saveSymb: saveSymb,
            saveStr: saveStr,
            getAll: getAll
          };
        };
        var substringAfter$1 = function substringAfter(str, separator) {
          if (!str) {
            return str;
          }
          var index = str.indexOf(separator);
          return index < 0 ? '' : str.substring(index + separator.length);
        };
        var parseRule = function parseRule(ruleText) {
          var _transitions;
          ruleText = substringAfter$1(ruleText, ADG_SCRIPTLET_MASK);
          var TRANSITION = {
            OPENED: 'opened',
            PARAM: 'param',
            CLOSED: 'closed'
          };
          var opened = function opened(rule, index, _ref) {
            var sep = _ref.sep;
            var char = rule[index];
            var transition;
            switch (char) {
              case ' ':
              case '(':
              case ',':
                {
                  transition = TRANSITION.OPENED;
                  break;
                }
              case '\'':
              case '"':
                {
                  sep.symb = char;
                  transition = TRANSITION.PARAM;
                  break;
                }
              case ')':
                {
                  transition = index === rule.length - 1 ? TRANSITION.CLOSED : TRANSITION.OPENED;
                  break;
                }
              default:
                {
                  throw new Error('The rule is not a scriptlet');
                }
            }
            return transition;
          };
          var param = function param(rule, index, _ref2) {
            var saver = _ref2.saver,
                sep = _ref2.sep;
            var char = rule[index];
            switch (char) {
              case '\'':
              case '"':
                {
                  var preIndex = index - 1;
                  var before = rule[preIndex];
                  if (char === sep.symb && before !== '\\') {
                    sep.symb = null;
                    saver.saveStr();
                    return TRANSITION.OPENED;
                  }
                }
              default:
                {
                  saver.saveSymb(char);
                  return TRANSITION.PARAM;
                }
            }
          };
          var transitions = (_transitions = {}, defineProperty(_transitions, TRANSITION.OPENED, opened), defineProperty(_transitions, TRANSITION.PARAM, param), defineProperty(_transitions, TRANSITION.CLOSED, function () {}), _transitions);
          var sep = {
            symb: null
          };
          var saver = wordSaver();
          var state = iterateWithTransitions(ruleText, transitions, TRANSITION.OPENED, {
            sep: sep,
            saver: saver
          });
          if (state !== 'closed') {
            throw new Error("Invalid scriptlet rule ".concat(ruleText));
          }
          var args = saver.getAll();
          return {
            name: args[0],
            args: args.slice(1)
          };
        };
        function abortOnPropertyRead(source, property) {
          if (!property) {
            return;
          }
          var rid = randomId();
          var abort = function abort() {
            hit(source);
            throw new ReferenceError(rid);
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            setPropertyAccess(base, prop, {
              get: abort,
              set: function set() {}
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        abortOnPropertyRead.names = ['abort-on-property-read',
        'abort-on-property-read.js', 'ubo-abort-on-property-read.js', 'aopr.js', 'ubo-aopr.js', 'ubo-abort-on-property-read', 'ubo-aopr', 'abp-abort-on-property-read'];
        abortOnPropertyRead.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];
        function abortOnPropertyWrite(source, property) {
          if (!property) {
            return;
          }
          var rid = randomId();
          var abort = function abort() {
            hit(source);
            throw new ReferenceError(rid);
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            setPropertyAccess(base, prop, {
              set: abort
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        abortOnPropertyWrite.names = ['abort-on-property-write',
        'abort-on-property-write.js', 'ubo-abort-on-property-write.js', 'aopw.js', 'ubo-aopw.js', 'ubo-abort-on-property-write', 'ubo-aopw', 'abp-abort-on-property-write'];
        abortOnPropertyWrite.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];
        function preventSetTimeout(source, match, delay) {
          var isProxySupported = typeof Proxy !== 'undefined';
          var nativeTimeout = window.setTimeout;
          var log = console.log.bind(console);
          var shouldLog = typeof match === 'undefined' && typeof delay === 'undefined';
          var _parseMatchArg = parseMatchArg(match),
              isInvertedMatch = _parseMatchArg.isInvertedMatch,
              matchRegexp = _parseMatchArg.matchRegexp;
          var _parseDelayArg = parseDelayArg(delay),
              isInvertedDelayMatch = _parseDelayArg.isInvertedDelayMatch,
              delayMatch = _parseDelayArg.delayMatch;
          var getShouldPrevent = function getShouldPrevent(callbackStr, timeout) {
            var shouldPrevent = false;
            if (!delayMatch) {
              shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch;
            } else if (!match) {
              shouldPrevent = timeout === delayMatch !== isInvertedDelayMatch;
            } else {
              shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch && timeout === delayMatch !== isInvertedDelayMatch;
            }
            return shouldPrevent;
          };
          var legacyTimeoutWrapper = function legacyTimeoutWrapper(callback, timeout) {
            var shouldPrevent = false;
            var cbString = String(callback);
            if (shouldLog) {
              hit(source);
              log("setTimeout(".concat(cbString, ", ").concat(timeout, ")"));
            } else {
              shouldPrevent = getShouldPrevent(cbString, timeout);
            }
            if (shouldPrevent) {
              hit(source);
              return nativeTimeout(noopFunc, timeout);
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeTimeout.apply(window, [callback, timeout].concat(args));
          };
          var handlerWrapper = function handlerWrapper(target, thisArg, args) {
            var callback = args[0];
            var timeout = args[1];
            var shouldPrevent = false;
            var cbString = String(callback);
            if (shouldLog) {
              hit(source);
              log("setTimeout(".concat(cbString, ", ").concat(timeout, ")"));
            } else {
              shouldPrevent = getShouldPrevent(cbString, timeout);
            }
            if (shouldPrevent) {
              hit(source);
              args[0] = noopFunc;
            }
            return target.apply(thisArg, args);
          };
          var setTimeoutHandler = {
            apply: handlerWrapper
          };
          window.setTimeout = isProxySupported ? new Proxy(window.setTimeout, setTimeoutHandler) : legacyTimeoutWrapper;
        }
        preventSetTimeout.names = ['prevent-setTimeout',
        'no-setTimeout-if.js',
        'ubo-no-setTimeout-if.js', 'nostif.js',
        'ubo-nostif.js', 'ubo-no-setTimeout-if', 'ubo-nostif',
        'setTimeout-defuser.js', 'ubo-setTimeout-defuser.js', 'ubo-setTimeout-defuser', 'std.js', 'ubo-std.js', 'ubo-std'];
        preventSetTimeout.injections = [hit, noopFunc, parseMatchArg, parseDelayArg, toRegExp, startsWith, nativeIsNaN];
        function preventSetInterval(source, match, delay) {
          var isProxySupported = typeof Proxy !== 'undefined';
          var nativeInterval = window.setInterval;
          var log = console.log.bind(console);
          var shouldLog = typeof match === 'undefined' && typeof delay === 'undefined';
          var _parseMatchArg = parseMatchArg(match),
              isInvertedMatch = _parseMatchArg.isInvertedMatch,
              matchRegexp = _parseMatchArg.matchRegexp;
          var _parseDelayArg = parseDelayArg(delay),
              isInvertedDelayMatch = _parseDelayArg.isInvertedDelayMatch,
              delayMatch = _parseDelayArg.delayMatch;
          var getShouldPrevent = function getShouldPrevent(callbackStr, interval) {
            var shouldPrevent = false;
            if (!delayMatch) {
              shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch;
            } else if (!match) {
              shouldPrevent = interval === delayMatch !== isInvertedDelayMatch;
            } else {
              shouldPrevent = matchRegexp.test(callbackStr) !== isInvertedMatch && interval === delayMatch !== isInvertedDelayMatch;
            }
            return shouldPrevent;
          };
          var legacyIntervalWrapper = function legacyIntervalWrapper(callback, interval) {
            var shouldPrevent = false;
            var cbString = String(callback);
            if (shouldLog) {
              hit(source);
              log("setInterval(".concat(cbString, ", ").concat(interval, ")"));
            } else {
              shouldPrevent = getShouldPrevent(cbString, interval);
            }
            if (shouldPrevent) {
              hit(source);
              return nativeInterval(noopFunc, interval);
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeInterval.apply(window, [callback, interval].concat(args));
          };
          var handlerWrapper = function handlerWrapper(target, thisArg, args) {
            var callback = args[0];
            var interval = args[1];
            var shouldPrevent = false;
            var cbString = String(callback);
            if (shouldLog) {
              hit(source);
              log("setInterval(".concat(cbString, ", ").concat(interval, ")"));
            } else {
              shouldPrevent = getShouldPrevent(cbString, interval);
            }
            if (shouldPrevent) {
              hit(source);
              args[0] = noopFunc;
            }
            return target.apply(thisArg, args);
          };
          var setIntervalHandler = {
            apply: handlerWrapper
          };
          window.setInterval = isProxySupported ? new Proxy(window.setInterval, setIntervalHandler) : legacyIntervalWrapper;
        }
        preventSetInterval.names = ['prevent-setInterval',
        'no-setInterval-if.js',
        'ubo-no-setInterval-if.js', 'setInterval-defuser.js',
        'ubo-setInterval-defuser.js', 'nosiif.js',
        'ubo-nosiif.js', 'sid.js',
        'ubo-sid.js', 'ubo-no-setInterval-if', 'ubo-setInterval-defuser', 'ubo-nosiif', 'ubo-sid'];
        preventSetInterval.injections = [hit, noopFunc, parseMatchArg, parseDelayArg, toRegExp, startsWith, nativeIsNaN];
        function preventWindowOpen(source) {
          var match = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getWildcardSymbol();
          var delay = arguments.length > 2 ? arguments[2] : undefined;
          var replacement = arguments.length > 3 ? arguments[3] : undefined;
          var nativeOpen = window.open;
          var isNewSyntax = match !== '0' && match !== '1';
          var oldOpenWrapper = function oldOpenWrapper(str) {
            match = Number(match) > 0;
            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
              args[_key - 1] = arguments[_key];
            }
            if (!validateStrPattern(delay)) {
              console.log("Invalid parameter: ".concat(delay));
              return nativeOpen.apply(window, [str].concat(args));
            }
            var searchRegexp = toRegExp(delay);
            if (match !== searchRegexp.test(str)) {
              return nativeOpen.apply(window, [str].concat(args));
            }
            hit(source);
            return handleOldReplacement(replacement);
          };
          var newOpenWrapper = function newOpenWrapper(url) {
            var shouldLog = replacement && replacement.indexOf('log') > -1;
            for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
              args[_key2 - 1] = arguments[_key2];
            }
            if (shouldLog) {
              var argsStr = args && args.length > 0 ? ", ".concat(args.join(', ')) : '';
              var logMessage = "log: window-open: ".concat(url).concat(argsStr);
              hit(source, logMessage);
            }
            var shouldPrevent = false;
            if (match === getWildcardSymbol()) {
              shouldPrevent = true;
            } else if (validateMatchStr(match)) {
              var _parseMatchArg = parseMatchArg(match),
                  isInvertedMatch = _parseMatchArg.isInvertedMatch,
                  matchRegexp = _parseMatchArg.matchRegexp;
              shouldPrevent = matchRegexp.test(url) !== isInvertedMatch;
            } else {
              console.log("Invalid parameter: ".concat(match));
              shouldPrevent = false;
            }
            if (shouldPrevent) {
              var parsedDelay = parseInt(delay, 10);
              var result;
              if (nativeIsNaN(parsedDelay)) {
                result = noopNull();
              } else {
                var decoyArgs = {
                  replacement: replacement,
                  url: url,
                  delay: parsedDelay
                };
                var decoy = createDecoy(decoyArgs);
                var popup = decoy.contentWindow;
                if (typeof popup === 'object' && popup !== null) {
                  Object.defineProperty(popup, 'closed', {
                    value: false
                  });
                  Object.defineProperty(popup, 'opener', {
                    value: window
                  });
                  Object.defineProperty(popup, 'frameElement', {
                    value: null
                  });
                } else {
                  var nativeGetter = decoy.contentWindow && decoy.contentWindow.get;
                  Object.defineProperty(decoy, 'contentWindow', {
                    get: getPreventGetter(nativeGetter)
                  });
                  popup = decoy.contentWindow;
                }
                result = popup;
              }
              hit(source);
              return result;
            }
            return nativeOpen.apply(window, [url].concat(args));
          };
          window.open = isNewSyntax ? newOpenWrapper : oldOpenWrapper;
          window.open.toString = nativeOpen.toString.bind(nativeOpen);
        }
        preventWindowOpen.names = ['prevent-window-open',
        'window.open-defuser.js', 'ubo-window.open-defuser.js', 'ubo-window.open-defuser', 'nowoif.js', 'ubo-nowoif.js', 'ubo-nowoif'];
        preventWindowOpen.injections = [hit, validateStrPattern, validateMatchStr, toRegExp, nativeIsNaN, parseMatchArg, handleOldReplacement, createDecoy, getPreventGetter, noopNull, getWildcardSymbol, noopFunc, trueFunc, startsWith, endsWith, substringBefore, substringAfter];
        function abortCurrentInlineScript(source, property, search) {
          var searchRegexp = toRegExp(search);
          var rid = randomId();
          var SRC_DATA_MARKER = 'data:text/javascript;base64,';
          var getCurrentScript = function getCurrentScript() {
            if ('currentScript' in document) {
              return document.currentScript;
            }
            var scripts = document.getElementsByTagName('script');
            return scripts[scripts.length - 1];
          };
          var ourScript = getCurrentScript();
          var abort = function abort() {
            var scriptEl = getCurrentScript();
            if (!scriptEl) {
              return;
            }
            var content = scriptEl.textContent;
            try {
              var textContentGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').get;
              content = textContentGetter.call(scriptEl);
            } catch (e) {}
            if (content.length === 0 && typeof scriptEl.src !== 'undefined' && startsWith(scriptEl.src, SRC_DATA_MARKER)) {
              var encodedContent = scriptEl.src.slice(SRC_DATA_MARKER.length);
              content = window.atob(encodedContent);
            }
            if (scriptEl instanceof HTMLScriptElement && content.length > 0 && scriptEl !== ourScript && searchRegexp.test(content)) {
              hit(source);
              throw new ReferenceError(rid);
            }
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (base instanceof Object === false && base === null) {
              var props = property.split('.');
              var propIndex = props.indexOf(prop);
              var baseName = props[propIndex - 1];
              console.log("The scriptlet had been executed before the ".concat(baseName, " was loaded."));
              return;
            }
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            var currentValue = base[prop];
            var origDescriptor = Object.getOwnPropertyDescriptor(base, prop);
            if (origDescriptor instanceof Object === false || origDescriptor.get instanceof Function === false) {
              currentValue = base[prop];
              origDescriptor = undefined;
            }
            setPropertyAccess(base, prop, {
              set: function set(value) {
                abort();
                if (origDescriptor instanceof Object) {
                  origDescriptor.set.call(base, value);
                } else {
                  currentValue = value;
                }
              },
              get: function get() {
                abort();
                if (origDescriptor instanceof Object) {
                  return origDescriptor.get.call(base);
                }
                return currentValue;
              }
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        abortCurrentInlineScript.names = ['abort-current-inline-script',
        'abort-current-script.js', 'ubo-abort-current-script.js', 'acs.js', 'ubo-acs.js',
        'ubo-abort-current-script', 'ubo-acs',
        'abort-current-inline-script.js', 'ubo-abort-current-inline-script.js', 'acis.js', 'ubo-acis.js', 'ubo-abort-current-inline-script', 'ubo-acis', 'abp-abort-current-inline-script'];
        abortCurrentInlineScript.injections = [randomId, setPropertyAccess, getPropertyInChain, toRegExp, startsWith, createOnErrorHandler, hit];
        function setConstant(source, property, value, stack) {
          if (!property || !matchStackTrace(stack, new Error().stack)) {
            return;
          }
          var log = console.log.bind(console);
          var emptyArr = noopArray();
          var emptyObj = noopObject();
          var constantValue;
          if (value === 'undefined') {
            constantValue = undefined;
          } else if (value === 'false') {
            constantValue = false;
          } else if (value === 'true') {
            constantValue = true;
          } else if (value === 'null') {
            constantValue = null;
          } else if (value === 'emptyArr') {
            constantValue = emptyArr;
          } else if (value === 'emptyObj') {
            constantValue = emptyObj;
          } else if (value === 'noopFunc') {
            constantValue = noopFunc;
          } else if (value === 'trueFunc') {
            constantValue = trueFunc;
          } else if (value === 'falseFunc') {
            constantValue = falseFunc;
          } else if (value === 'noopPromiseResolve') {
            constantValue = noopPromiseResolve;
          } else if (value === 'noopPromiseReject') {
            constantValue = noopPromiseReject;
          } else if (/^\d+$/.test(value)) {
            constantValue = parseFloat(value);
            if (nativeIsNaN(constantValue)) {
              return;
            }
            if (Math.abs(constantValue) > 0x7FFF) {
              return;
            }
          } else if (value === '-1') {
            constantValue = -1;
          } else if (value === '') {
            constantValue = '';
          } else if (value === 'yes') {
            constantValue = 'yes';
          } else if (value === 'no') {
            constantValue = 'no';
          } else {
            return;
          }
          var getCurrentScript = function getCurrentScript() {
            if ('currentScript' in document) {
              return document.currentScript;
            }
            var scripts = document.getElementsByTagName('script');
            return scripts[scripts.length - 1];
          };
          var ourScript = getCurrentScript();
          var canceled = false;
          var mustCancel = function mustCancel(value) {
            if (canceled) {
              return canceled;
            }
            canceled = value !== undefined && constantValue !== undefined && typeof value !== typeof constantValue;
            return canceled;
          };
          var trapProp = function trapProp(base, prop, configurable, handler) {
            if (!handler.init(base[prop])) {
              return false;
            }
            var origDescriptor = Object.getOwnPropertyDescriptor(base, prop);
            var prevGetter;
            var prevSetter;
            if (origDescriptor instanceof Object) {
              if (!origDescriptor.configurable) {
                if (source.verbose) {
                  log("set-constant: property '".concat(prop, "' is not configurable"));
                }
                return false;
              }
              base[prop] = constantValue;
              if (origDescriptor.get instanceof Function) {
                prevGetter = origDescriptor.get;
              }
              if (origDescriptor.set instanceof Function) {
                prevSetter = origDescriptor.set;
              }
            }
            Object.defineProperty(base, prop, {
              configurable: configurable,
              get: function get() {
                if (prevGetter !== undefined) {
                  prevGetter();
                }
                return handler.get();
              },
              set: function set(a) {
                if (prevSetter !== undefined) {
                  prevSetter(a);
                }
                handler.set(a);
              }
            });
            return true;
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            var undefPropHandler = {
              factValue: undefined,
              init: function init(a) {
                this.factValue = a;
                return true;
              },
              get: function get() {
                return this.factValue;
              },
              set: function set(a) {
                if (this.factValue === a) {
                  return;
                }
                this.factValue = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              }
            };
            var endPropHandler = {
              factValue: undefined,
              init: function init(a) {
                if (mustCancel(a)) {
                  return false;
                }
                this.factValue = a;
                return true;
              },
              get: function get() {
                return document.currentScript === ourScript ? this.factValue : constantValue;
              },
              set: function set(a) {
                if (!mustCancel(a)) {
                  return;
                }
                constantValue = a;
              }
            };
            if (!chain) {
              var isTrapped = trapProp(base, prop, false, endPropHandler);
              if (isTrapped) {
                hit(source);
              }
              return;
            }
            var propValue = owner[prop];
            if (propValue instanceof Object || typeof propValue === 'object' && propValue !== null) {
              setChainPropAccess(propValue, chain);
            }
            trapProp(owner, prop, true, undefPropHandler);
          };
          setChainPropAccess(window, property);
        }
        setConstant.names = ['set-constant',
        'set-constant.js', 'ubo-set-constant.js', 'set.js', 'ubo-set.js', 'ubo-set-constant', 'ubo-set', 'abp-override-property-read'];
        setConstant.injections = [hit, noopArray, noopObject, noopFunc, trueFunc, falseFunc, noopPromiseReject, noopPromiseResolve, getPropertyInChain, setPropertyAccess, toRegExp, matchStackTrace, nativeIsNaN];
        function removeCookie(source, match) {
          var matchRegexp = toRegExp(match);
          var removeCookieFromHost = function removeCookieFromHost(cookieName, hostName) {
            var cookieSpec = "".concat(cookieName, "=");
            var domain1 = "; domain=".concat(hostName);
            var domain2 = "; domain=.".concat(hostName);
            var path = '; path=/';
            var expiration = '; expires=Thu, 01 Jan 1970 00:00:00 GMT';
            document.cookie = cookieSpec + expiration;
            document.cookie = cookieSpec + domain1 + expiration;
            document.cookie = cookieSpec + domain2 + expiration;
            document.cookie = cookieSpec + path + expiration;
            document.cookie = cookieSpec + domain1 + path + expiration;
            document.cookie = cookieSpec + domain2 + path + expiration;
            hit(source);
          };
          var rmCookie = function rmCookie() {
            document.cookie.split(';').forEach(function (cookieStr) {
              var pos = cookieStr.indexOf('=');
              if (pos === -1) {
                return;
              }
              var cookieName = cookieStr.slice(0, pos).trim();
              if (!matchRegexp.test(cookieName)) {
                return;
              }
              var hostParts = document.location.hostname.split('.');
              for (var i = 0; i <= hostParts.length - 1; i += 1) {
                var hostName = hostParts.slice(i).join('.');
                if (hostName) {
                  removeCookieFromHost(cookieName, hostName);
                }
              }
            });
          };
          rmCookie();
          window.addEventListener('beforeunload', rmCookie);
        }
        removeCookie.names = ['remove-cookie',
        'cookie-remover.js', 'ubo-cookie-remover.js', 'ubo-cookie-remover'];
        removeCookie.injections = [toRegExp, hit];
        function preventAddEventListener(source, typeSearch, listenerSearch) {
          var typeSearchRegexp = toRegExp(typeSearch);
          var listenerSearchRegexp = toRegExp(listenerSearch);
          var nativeAddEventListener = window.EventTarget.prototype.addEventListener;
          function addEventListenerWrapper(type, listener) {
            var shouldPrevent = false;
            if (validateType(type) && validateListener(listener)) {
              shouldPrevent = typeSearchRegexp.test(type.toString()) && listenerSearchRegexp.test(listenerToString(listener));
            }
            if (shouldPrevent) {
              hit(source);
              return undefined;
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeAddEventListener.apply(this, [type, listener].concat(args));
          }
          window.EventTarget.prototype.addEventListener = addEventListenerWrapper;
          window.addEventListener = addEventListenerWrapper;
          document.addEventListener = addEventListenerWrapper;
        }
        preventAddEventListener.names = ['prevent-addEventListener',
        'addEventListener-defuser.js', 'ubo-addEventListener-defuser.js', 'aeld.js', 'ubo-aeld.js', 'ubo-addEventListener-defuser', 'ubo-aeld'];
        preventAddEventListener.injections = [hit, toRegExp, validateType, validateListener, listenerToString];
        function preventBab(source) {
          var nativeSetTimeout = window.setTimeout;
          var babRegex = /\.bab_elementid.$/;
          var timeoutWrapper = function timeoutWrapper(callback) {
            if (typeof callback !== 'string' || !babRegex.test(callback)) {
              for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
                args[_key - 1] = arguments[_key];
              }
              return nativeSetTimeout.apply(window, [callback].concat(args));
            }
            hit(source);
          };
          window.setTimeout = timeoutWrapper;
          var signatures = [['blockadblock'], ['babasbm'], [/getItem\('babn'\)/], ['getElementById', 'String.fromCharCode', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'charAt', 'DOMContentLoaded', 'AdBlock', 'addEventListener', 'doScroll', 'fromCharCode', '<<2|r>>4', 'sessionStorage', 'clientWidth', 'localStorage', 'Math', 'random']];
          var check = function check(str) {
            if (typeof str !== 'string') {
              return false;
            }
            for (var i = 0; i < signatures.length; i += 1) {
              var tokens = signatures[i];
              var match = 0;
              for (var j = 0; j < tokens.length; j += 1) {
                var token = tokens[j];
                var found = token instanceof RegExp ? token.test(str) : str.indexOf(token) > -1;
                if (found) {
                  match += 1;
                }
              }
              if (match / tokens.length >= 0.8) {
                return true;
              }
            }
            return false;
          };
          var nativeEval = window.eval;
          var evalWrapper = function evalWrapper(str) {
            if (!check(str)) {
              return nativeEval(str);
            }
            hit(source);
            var bodyEl = document.body;
            if (bodyEl) {
              bodyEl.style.removeProperty('visibility');
            }
            var el = document.getElementById('babasbmsgx');
            if (el) {
              el.parentNode.removeChild(el);
            }
          };
          window.eval = evalWrapper.bind(window);
        }
        preventBab.names = ['prevent-bab',
        'nobab.js', 'ubo-nobab.js', 'bab-defuser.js', 'ubo-bab-defuser.js', 'ubo-nobab', 'ubo-bab-defuser'];
        preventBab.injections = [hit];
        function nowebrtc(source) {
          var propertyName = '';
          if (window.RTCPeerConnection) {
            propertyName = 'RTCPeerConnection';
          } else if (window.webkitRTCPeerConnection) {
            propertyName = 'webkitRTCPeerConnection';
          }
          if (propertyName === '') {
            return;
          }
          var rtcReplacement = function rtcReplacement(config) {
            hit(source, "Document tried to create an RTCPeerConnection: ".concat(convertRtcConfigToString(config)));
          };
          rtcReplacement.prototype = {
            close: noopFunc,
            createDataChannel: noopFunc,
            createOffer: noopFunc,
            setRemoteDescription: noopFunc
          };
          var rtc = window[propertyName];
          window[propertyName] = rtcReplacement;
          if (rtc.prototype) {
            rtc.prototype.createDataChannel = function (a, b) {
              return {
                close: noopFunc,
                send: noopFunc
              };
            }.bind(null);
          }
        }
        nowebrtc.names = ['nowebrtc',
        'nowebrtc.js', 'ubo-nowebrtc.js', 'ubo-nowebrtc'];
        nowebrtc.injections = [hit, noopFunc, convertRtcConfigToString];
        function logAddEventListener(source) {
          var log = console.log.bind(console);
          var nativeAddEventListener = window.EventTarget.prototype.addEventListener;
          function addEventListenerWrapper(type, listener) {
            if (validateType(type) && validateListener(listener)) {
              var logMessage = "addEventListener(\"".concat(type, "\", ").concat(listenerToString(listener), ")");
              log(logMessage);
              hit(source);
            } else if (source.verbose) {
              var _logMessage = "Invalid event type or listener passed to addEventListener:\ntype: ".concat(convertTypeToString(type), "\nlistener: ").concat(convertTypeToString(listener));
              log(_logMessage);
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeAddEventListener.apply(this, [type, listener].concat(args));
          }
          window.EventTarget.prototype.addEventListener = addEventListenerWrapper;
        }
        logAddEventListener.names = ['log-addEventListener',
        'addEventListener-logger.js', 'ubo-addEventListener-logger.js', 'aell.js', 'ubo-aell.js', 'ubo-addEventListener-logger', 'ubo-aell'];
        logAddEventListener.injections = [hit, validateType, validateListener, listenerToString, convertTypeToString, objectToString, isEmptyObject, getObjectEntries];
        function logEval(source) {
          var log = console.log.bind(console);
          var nativeEval = window.eval;
          function evalWrapper(str) {
            hit(source);
            log("eval(\"".concat(str, "\")"));
            return nativeEval(str);
          }
          window.eval = evalWrapper;
          var nativeFunction = window.Function;
          function FunctionWrapper() {
            hit(source);
            for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
              args[_key] = arguments[_key];
            }
            log("new Function(".concat(args.join(', '), ")"));
            return nativeFunction.apply(this, [].concat(args));
          }
          FunctionWrapper.prototype = Object.create(nativeFunction.prototype);
          FunctionWrapper.prototype.constructor = FunctionWrapper;
          window.Function = FunctionWrapper;
        }
        logEval.names = ['log-eval'];
        logEval.injections = [hit];
        function log() {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }
          console.log(args);
        }
        log.names = ['log'];
        function noeval(source) {
          window.eval = function evalWrapper(s) {
            hit(source, "AdGuard has prevented eval:\n".concat(s));
          }.bind();
        }
        noeval.names = ['noeval',
        'noeval.js', 'silent-noeval.js', 'ubo-noeval.js', 'ubo-silent-noeval.js', 'ubo-noeval', 'ubo-silent-noeval'];
        noeval.injections = [hit];
        function preventEvalIf(source, search) {
          var searchRegexp = toRegExp(search);
          var nativeEval = window.eval;
          window.eval = function (payload) {
            if (!searchRegexp.test(payload.toString())) {
              return nativeEval.call(window, payload);
            }
            hit(source, payload);
            return undefined;
          }.bind(window);
        }
        preventEvalIf.names = ['prevent-eval-if',
        'noeval-if.js', 'ubo-noeval-if.js', 'ubo-noeval-if'];
        preventEvalIf.injections = [toRegExp, hit];
        function preventFab(source) {
          hit(source);
          var Fab = function Fab() {};
          Fab.prototype.check = noopFunc;
          Fab.prototype.clearEvent = noopFunc;
          Fab.prototype.emitEvent = noopFunc;
          Fab.prototype.on = function (a, b) {
            if (!a) {
              b();
            }
            return this;
          };
          Fab.prototype.onDetected = noopThis;
          Fab.prototype.onNotDetected = function (a) {
            a();
            return this;
          };
          Fab.prototype.setOption = noopFunc;
          Fab.prototype.options = {
            set: noopFunc,
            get: noopFunc
          };
          var fab = new Fab();
          var getSetFab = {
            get: function get() {
              return Fab;
            },
            set: function set() {}
          };
          var getsetfab = {
            get: function get() {
              return fab;
            },
            set: function set() {}
          };
          if (Object.prototype.hasOwnProperty.call(window, 'FuckAdBlock')) {
            window.FuckAdBlock = Fab;
          } else {
            Object.defineProperty(window, 'FuckAdBlock', getSetFab);
          }
          if (Object.prototype.hasOwnProperty.call(window, 'BlockAdBlock')) {
            window.BlockAdBlock = Fab;
          } else {
            Object.defineProperty(window, 'BlockAdBlock', getSetFab);
          }
          if (Object.prototype.hasOwnProperty.call(window, 'SniffAdBlock')) {
            window.SniffAdBlock = Fab;
          } else {
            Object.defineProperty(window, 'SniffAdBlock', getSetFab);
          }
          if (Object.prototype.hasOwnProperty.call(window, 'fuckAdBlock')) {
            window.fuckAdBlock = fab;
          } else {
            Object.defineProperty(window, 'fuckAdBlock', getsetfab);
          }
          if (Object.prototype.hasOwnProperty.call(window, 'blockAdBlock')) {
            window.blockAdBlock = fab;
          } else {
            Object.defineProperty(window, 'blockAdBlock', getsetfab);
          }
          if (Object.prototype.hasOwnProperty.call(window, 'sniffAdBlock')) {
            window.sniffAdBlock = fab;
          } else {
            Object.defineProperty(window, 'sniffAdBlock', getsetfab);
          }
        }
        preventFab.names = ['prevent-fab-3.2.0',
        'nofab.js', 'ubo-nofab.js', 'fuckadblock.js-3.2.0', 'ubo-fuckadblock.js-3.2.0', 'ubo-nofab'];
        preventFab.injections = [hit, noopFunc, noopThis];
        function setPopadsDummy(source) {
          delete window.PopAds;
          delete window.popns;
          Object.defineProperties(window, {
            PopAds: {
              get: function get() {
                hit(source);
                return {};
              }
            },
            popns: {
              get: function get() {
                hit(source);
                return {};
              }
            }
          });
        }
        setPopadsDummy.names = ['set-popads-dummy',
        'popads-dummy.js', 'ubo-popads-dummy.js', 'ubo-popads-dummy'];
        setPopadsDummy.injections = [hit];
        function preventPopadsNet(source) {
          var rid = randomId();
          var throwError = function throwError() {
            throw new ReferenceError(rid);
          };
          delete window.PopAds;
          delete window.popns;
          Object.defineProperties(window, {
            PopAds: {
              set: throwError
            },
            popns: {
              set: throwError
            }
          });
          window.onerror = createOnErrorHandler(rid).bind();
          hit(source);
        }
        preventPopadsNet.names = ['prevent-popads-net',
        'popads.net.js', 'ubo-popads.net.js', 'ubo-popads.net'];
        preventPopadsNet.injections = [createOnErrorHandler, randomId, hit];
        function preventAdfly(source) {
          var isDigit = function isDigit(data) {
            return /^\d$/.test(data);
          };
          var handler = function handler(encodedURL) {
            var evenChars = '';
            var oddChars = '';
            for (var i = 0; i < encodedURL.length; i += 1) {
              if (i % 2 === 0) {
                evenChars += encodedURL.charAt(i);
              } else {
                oddChars = encodedURL.charAt(i) + oddChars;
              }
            }
            var data = (evenChars + oddChars).split('');
            for (var _i = 0; _i < data.length; _i += 1) {
              if (isDigit(data[_i])) {
                for (var ii = _i + 1; ii < data.length; ii += 1) {
                  if (isDigit(data[ii])) {
                    var temp = parseInt(data[_i], 10) ^ parseInt(data[ii], 10);
                    if (temp < 10) {
                      data[_i] = temp.toString();
                    }
                    _i = ii;
                    break;
                  }
                }
              }
            }
            data = data.join('');
            var decodedURL = window.atob(data).slice(16, -16);
            if (window.stop) {
              window.stop();
            }
            window.onbeforeunload = null;
            window.location.href = decodedURL;
          };
          var val;
          var applyHandler = true;
          var result = setPropertyAccess(window, 'ysmm', {
            configurable: false,
            set: function set(value) {
              if (applyHandler) {
                applyHandler = false;
                try {
                  if (typeof value === 'string') {
                    handler(value);
                  }
                } catch (err) {}
              }
              val = value;
            },
            get: function get() {
              return val;
            }
          });
          if (result) {
            hit(source);
          } else {
            window.console.error('Failed to set up prevent-adfly scriptlet');
          }
        }
        preventAdfly.names = ['prevent-adfly',
        'adfly-defuser.js', 'ubo-adfly-defuser.js', 'ubo-adfly-defuser'];
        preventAdfly.injections = [setPropertyAccess, hit];
        function debugOnPropertyRead(source, property) {
          if (!property) {
            return;
          }
          var rid = randomId();
          var abort = function abort() {
            hit(source);
            debugger;
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            setPropertyAccess(base, prop, {
              get: abort,
              set: noopFunc
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        debugOnPropertyRead.names = ['debug-on-property-read'];
        debugOnPropertyRead.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit, noopFunc];
        function debugOnPropertyWrite(source, property) {
          if (!property) {
            return;
          }
          var rid = randomId();
          var abort = function abort() {
            hit(source);
            debugger;
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            setPropertyAccess(base, prop, {
              set: abort
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        debugOnPropertyWrite.names = ['debug-on-property-write'];
        debugOnPropertyWrite.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit];
        function debugCurrentInlineScript(source, property, search) {
          var searchRegexp = toRegExp(search);
          var rid = randomId();
          var getCurrentScript = function getCurrentScript() {
            if ('currentScript' in document) {
              return document.currentScript;
            }
            var scripts = document.getElementsByTagName('script');
            return scripts[scripts.length - 1];
          };
          var ourScript = getCurrentScript();
          var abort = function abort() {
            var scriptEl = getCurrentScript();
            if (!scriptEl) {
              return;
            }
            var content = scriptEl.textContent;
            try {
              var textContentGetter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').get;
              content = textContentGetter.call(scriptEl);
            } catch (e) {}
            if (scriptEl instanceof HTMLScriptElement && content.length > 0 && scriptEl !== ourScript && searchRegexp.test(content)) {
              hit(source);
              debugger;
            }
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (base instanceof Object === false && base === null) {
              var props = property.split('.');
              var propIndex = props.indexOf(prop);
              var baseName = props[propIndex - 1];
              console.log("The scriptlet had been executed before the ".concat(baseName, " was loaded."));
              return;
            }
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            var currentValue = base[prop];
            setPropertyAccess(base, prop, {
              set: function set(value) {
                abort();
                currentValue = value;
              },
              get: function get() {
                abort();
                return currentValue;
              }
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        debugCurrentInlineScript.names = ['debug-current-inline-script'];
        debugCurrentInlineScript.injections = [randomId, setPropertyAccess, getPropertyInChain, toRegExp, createOnErrorHandler, hit];
        function removeAttr(source, attrs, selector) {
          var applying = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'asap stay';
          if (!attrs) {
            return;
          }
          attrs = attrs.split(/\s*\|\s*/);
          if (!selector) {
            selector = "[".concat(attrs.join('],['), "]");
          }
          var rmattr = function rmattr() {
            var nodes = [];
            try {
              nodes = [].slice.call(document.querySelectorAll(selector));
            } catch (e) {
              console.log("Invalid remove-attr selector arg: '".concat(selector, "'"));
            }
            var removed = false;
            nodes.forEach(function (node) {
              attrs.forEach(function (attr) {
                node.removeAttribute(attr);
                removed = true;
              });
            });
            if (removed) {
              hit(source);
            }
          };
          var FLAGS_DIVIDER = ' ';
          var ASAP_FLAG = 'asap';
          var COMPLETE_FLAG = 'complete';
          var STAY_FLAG = 'stay';
          var VALID_FLAGS = [STAY_FLAG, ASAP_FLAG, COMPLETE_FLAG];
          var passedFlags = applying.trim().split(FLAGS_DIVIDER).filter(function (f) {
            return VALID_FLAGS.indexOf(f) !== -1;
          });
          var run = function run() {
            rmattr();
            if (!passedFlags.indexOf(STAY_FLAG) !== -1) {
              return;
            }
            observeDOMChanges(rmattr, true);
          };
          if (passedFlags.indexOf(ASAP_FLAG) !== -1) {
            rmattr();
          }
          if (document.readyState !== 'complete' && passedFlags.indexOf(COMPLETE_FLAG) !== -1) {
            window.addEventListener('load', run, {
              once: true
            });
          } else if (passedFlags.indexOf(STAY_FLAG) !== -1) {
            if (passedFlags.length === 1) {
              rmattr();
            }
            observeDOMChanges(rmattr, true);
          }
        }
        removeAttr.names = ['remove-attr',
        'remove-attr.js', 'ubo-remove-attr.js', 'ra.js', 'ubo-ra.js', 'ubo-remove-attr', 'ubo-ra'];
        removeAttr.injections = [hit, observeDOMChanges];
        function setAttr(source, selector, attr) {
          var value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
          if (!selector || !attr) {
            return;
          }
          if (value.length !== 0 && (nativeIsNaN(parseInt(value, 10)) || parseInt(value, 10) < 0 || parseInt(value, 10) > 0x7FFF)) {
            return;
          }
          var setAttr = function setAttr() {
            var nodes = [].slice.call(document.querySelectorAll(selector));
            var set = false;
            nodes.forEach(function (node) {
              node.setAttribute(attr, value);
              set = true;
            });
            if (set) {
              hit(source);
            }
          };
          setAttr();
          observeDOMChanges(setAttr, true);
        }
        setAttr.names = ['set-attr'];
        setAttr.injections = [hit, observeDOMChanges, nativeIsNaN];
        function removeClass(source, classNames, selector) {
          var applying = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'asap stay';
          if (!classNames) {
            return;
          }
          classNames = classNames.split(/\s*\|\s*/);
          var selectors = [];
          if (!selector) {
            selectors = classNames.map(function (className) {
              return ".".concat(className);
            });
          }
          var removeClassHandler = function removeClassHandler() {
            var nodes = new Set();
            if (selector) {
              var foundNodes = [];
              try {
                foundNodes = [].slice.call(document.querySelectorAll(selector));
              } catch (e) {
                console.log("Invalid remove-class selector arg: '".concat(selector, "'"));
              }
              foundNodes.forEach(function (n) {
                return nodes.add(n);
              });
            } else if (selectors.length > 0) {
              selectors.forEach(function (s) {
                var elements = document.querySelectorAll(s);
                for (var i = 0; i < elements.length; i += 1) {
                  var element = elements[i];
                  nodes.add(element);
                }
              });
            }
            var removed = false;
            nodes.forEach(function (node) {
              classNames.forEach(function (className) {
                if (node.classList.contains(className)) {
                  node.classList.remove(className);
                  removed = true;
                }
              });
            });
            if (removed) {
              hit(source);
            }
          };
          var CLASS_ATTR_NAME = ['class'];
          var FLAGS_DIVIDER = ' ';
          var ASAP_FLAG = 'asap';
          var COMPLETE_FLAG = 'complete';
          var STAY_FLAG = 'stay';
          var VALID_FLAGS = [STAY_FLAG, ASAP_FLAG, COMPLETE_FLAG];
          var passedFlags = applying.trim().split(FLAGS_DIVIDER).filter(function (f) {
            return VALID_FLAGS.indexOf(f) !== -1;
          });
          var run = function run() {
            removeClassHandler();
            if (!passedFlags.indexOf(STAY_FLAG) !== -1) {
              return;
            }
            observeDOMChanges(removeClassHandler, true, CLASS_ATTR_NAME);
          };
          if (passedFlags.indexOf(ASAP_FLAG) !== -1) {
            removeClassHandler();
          }
          if (document.readyState !== 'complete' && passedFlags.indexOf(COMPLETE_FLAG) !== -1) {
            window.addEventListener('load', run, {
              once: true
            });
          } else if (passedFlags.indexOf(STAY_FLAG) !== -1) {
            if (passedFlags.length === 1) {
              removeClassHandler();
            }
            observeDOMChanges(removeClassHandler, true, CLASS_ATTR_NAME);
          }
        }
        removeClass.names = ['remove-class',
        'remove-class.js', 'ubo-remove-class.js', 'rc.js', 'ubo-rc.js', 'ubo-remove-class', 'ubo-rc'];
        removeClass.injections = [hit, observeDOMChanges];
        function disableNewtabLinks(source) {
          document.addEventListener('click', function (ev) {
            var target = ev.target;
            while (target !== null) {
              if (target.localName === 'a' && target.hasAttribute('target')) {
                ev.stopPropagation();
                ev.preventDefault();
                hit(source);
                break;
              }
              target = target.parentNode;
            }
          });
        }
        disableNewtabLinks.names = ['disable-newtab-links',
        'disable-newtab-links.js', 'ubo-disable-newtab-links.js', 'ubo-disable-newtab-links'];
        disableNewtabLinks.injections = [hit];
        function adjustSetInterval(source, match, interval, boost) {
          var nativeSetInterval = window.setInterval;
          var matchRegexp = toRegExp(match);
          var intervalWrapper = function intervalWrapper(cb, d) {
            if (matchRegexp.test(cb.toString()) && isDelayMatched(interval, d)) {
              d *= getBoostMultiplier(boost);
              hit(source);
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeSetInterval.apply(window, [cb, d].concat(args));
          };
          window.setInterval = intervalWrapper;
        }
        adjustSetInterval.names = ['adjust-setInterval',
        'nano-setInterval-booster.js', 'ubo-nano-setInterval-booster.js', 'nano-sib.js', 'ubo-nano-sib.js', 'ubo-nano-setInterval-booster', 'ubo-nano-sib'];
        adjustSetInterval.injections = [hit, toRegExp, getBoostMultiplier, isDelayMatched, nativeIsNaN, nativeIsFinite, getMatchDelay, getWildcardSymbol, shouldMatchAnyDelay];
        function adjustSetTimeout(source, match, timeout, boost) {
          var nativeSetTimeout = window.setTimeout;
          var matchRegexp = toRegExp(match);
          var timeoutWrapper = function timeoutWrapper(cb, d) {
            if (matchRegexp.test(cb.toString()) && isDelayMatched(timeout, d)) {
              d *= getBoostMultiplier(boost);
              hit(source);
            }
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return nativeSetTimeout.apply(window, [cb, d].concat(args));
          };
          window.setTimeout = timeoutWrapper;
        }
        adjustSetTimeout.names = ['adjust-setTimeout',
        'nano-setTimeout-booster.js', 'ubo-nano-setTimeout-booster.js', 'nano-stb.js', 'ubo-nano-stb.js', 'ubo-nano-setTimeout-booster', 'ubo-nano-stb'];
        adjustSetTimeout.injections = [hit, toRegExp, getBoostMultiplier, isDelayMatched, nativeIsNaN, nativeIsFinite, getMatchDelay, getWildcardSymbol, shouldMatchAnyDelay];
        function dirString(source, times) {
          var _console = console,
              dir = _console.dir;
          times = parseInt(times, 10);
          function dirWrapper(object) {
            var temp;
            for (var i = 0; i < times; i += 1) {
              temp = "".concat(object);
            }
            if (typeof dir === 'function') {
              dir.call(this, object);
            }
            hit(source, temp);
          }
          console.dir = dirWrapper;
        }
        dirString.names = ['dir-string', 'abp-dir-string'];
        dirString.injections = [hit];
        function jsonPrune(source, propsToRemove, requiredInitialProps, stack) {
          if (!!stack && !matchStackTrace(stack, new Error().stack)) {
            return;
          }
          var log = console.log.bind(console);
          var prunePaths = propsToRemove !== undefined && propsToRemove !== '' ? propsToRemove.split(/ +/) : [];
          var requiredPaths = requiredInitialProps !== undefined && requiredInitialProps !== '' ? requiredInitialProps.split(/ +/) : [];
          function isPruningNeeded(root) {
            if (!root) {
              return false;
            }
            var shouldProcess;
            if (prunePaths.length === 0 && requiredPaths.length > 0) {
              var rootString = JSON.stringify(root);
              var matchRegex = toRegExp(requiredPaths.join(''));
              var shouldLog = matchRegex.test(rootString);
              if (shouldLog) {
                log(window.location.hostname, root);
                shouldProcess = false;
                return shouldProcess;
              }
            }
            for (var i = 0; i < requiredPaths.length; i += 1) {
              var requiredPath = requiredPaths[i];
              var lastNestedPropName = requiredPath.split('.').pop();
              var hasWildcard = requiredPath.indexOf('.*.') > -1 || requiredPath.indexOf('*.') > -1 || requiredPath.indexOf('.*') > -1 || requiredPath.indexOf('.[].') > -1 || requiredPath.indexOf('[].') > -1 || requiredPath.indexOf('.[]') > -1;
              var details = getWildcardPropertyInChain(root, requiredPath, hasWildcard);
              shouldProcess = !hasWildcard;
              for (var _i = 0; _i < details.length; _i += 1) {
                if (hasWildcard) {
                  shouldProcess = !(details[_i].base[lastNestedPropName] === undefined) || shouldProcess;
                } else {
                  shouldProcess = !(details[_i].base[lastNestedPropName] === undefined) && shouldProcess;
                }
              }
            }
            return shouldProcess;
          }
          var jsonPruner = function jsonPruner(root) {
            if (prunePaths.length === 0 && requiredPaths.length === 0) {
              log(window.location.hostname, root);
              return root;
            }
            try {
              if (isPruningNeeded(root) === false) {
                return root;
              }
              prunePaths.forEach(function (path) {
                var ownerObjArr = getWildcardPropertyInChain(root, path, true);
                ownerObjArr.forEach(function (ownerObj) {
                  if (ownerObj !== undefined && ownerObj.base) {
                    delete ownerObj.base[ownerObj.prop];
                    hit(source);
                  }
                });
              });
            } catch (e) {
              log(e.toString());
            }
            return root;
          };
          var nativeJSONParse = JSON.parse;
          var jsonParseWrapper = function jsonParseWrapper() {
            for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
              args[_key] = arguments[_key];
            }
            var root = nativeJSONParse.apply(JSON, args);
            return jsonPruner(root);
          };
          jsonParseWrapper.toString = nativeJSONParse.toString.bind(nativeJSONParse);
          JSON.parse = jsonParseWrapper;
          var nativeResponseJson = Response.prototype.json;
          var responseJsonWrapper = function responseJsonWrapper() {
            var promise = nativeResponseJson.apply(this);
            return promise.then(function (obj) {
              return jsonPruner(obj);
            });
          };
          if (typeof Response === 'undefined') {
            return;
          }
          Response.prototype.json = responseJsonWrapper;
        }
        jsonPrune.names = ['json-prune',
        'json-prune.js', 'ubo-json-prune.js', 'ubo-json-prune', 'abp-json-prune'];
        jsonPrune.injections = [hit, matchStackTrace, getWildcardPropertyInChain, toRegExp, getWildcardSymbol];
        function preventRequestAnimationFrame(source, match) {
          var nativeRequestAnimationFrame = window.requestAnimationFrame;
          var shouldLog = typeof match === 'undefined';
          var _parseMatchArg = parseMatchArg(match),
              isInvertedMatch = _parseMatchArg.isInvertedMatch,
              matchRegexp = _parseMatchArg.matchRegexp;
          var rafWrapper = function rafWrapper(callback) {
            var shouldPrevent = false;
            if (shouldLog) {
              var logMessage = "log: requestAnimationFrame(\"".concat(callback.toString(), "\")");
              hit(source, logMessage);
            } else if (validateStrPattern(match)) {
              shouldPrevent = matchRegexp.test(callback.toString()) !== isInvertedMatch;
            }
            if (shouldPrevent) {
              hit(source);
              return nativeRequestAnimationFrame(noopFunc);
            }
            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
              args[_key - 1] = arguments[_key];
            }
            return nativeRequestAnimationFrame.apply(window, [callback].concat(args));
          };
          window.requestAnimationFrame = rafWrapper;
        }
        preventRequestAnimationFrame.names = ['prevent-requestAnimationFrame',
        'no-requestAnimationFrame-if.js', 'ubo-no-requestAnimationFrame-if.js', 'norafif.js', 'ubo-norafif.js', 'ubo-no-requestAnimationFrame-if', 'ubo-norafif'];
        preventRequestAnimationFrame.injections = [hit, noopFunc, parseMatchArg, validateStrPattern, toRegExp, startsWith];
        function setCookie(source, name, value) {
          var cookieData = prepareCookie(name, value);
          if (cookieData) {
            hit(source);
            document.cookie = cookieData;
          }
        }
        setCookie.names = ['set-cookie'];
        setCookie.injections = [hit, nativeIsNaN, prepareCookie];
        function setCookieReload(source, name, value) {
          var isCookieAlreadySet = document.cookie.split(';').some(function (cookieStr) {
            var pos = cookieStr.indexOf('=');
            if (pos === -1) {
              return false;
            }
            var cookieName = cookieStr.slice(0, pos).trim();
            var cookieValue = cookieStr.slice(pos + 1).trim();
            return name === cookieName && value === cookieValue;
          });
          var shouldReload = !isCookieAlreadySet;
          var cookieData = prepareCookie(name, value);
          if (cookieData) {
            hit(source);
            document.cookie = cookieData;
            if (shouldReload) {
              window.location.reload();
            }
          }
        }
        setCookieReload.names = ['set-cookie-reload'];
        setCookieReload.injections = [hit, nativeIsNaN, prepareCookie];
        function hideInShadowDom(source, selector, baseSelector) {
          if (!Element.prototype.attachShadow) {
            return;
          }
          var hideElement = function hideElement(targetElement) {
            var DISPLAY_NONE_CSS = 'display:none!important;';
            targetElement.style.cssText = DISPLAY_NONE_CSS;
          };
          var hideHandler = function hideHandler() {
            var hostElements = !baseSelector ? findHostElements(document.documentElement) : document.querySelectorAll(baseSelector);
            while (hostElements.length !== 0) {
              var isHidden = false;
              var _pierceShadowDom = pierceShadowDom(selector, hostElements),
                  targets = _pierceShadowDom.targets,
                  innerHosts = _pierceShadowDom.innerHosts;
              targets.forEach(function (targetEl) {
                hideElement(targetEl);
                isHidden = true;
              });
              if (isHidden) {
                hit(source);
              }
              hostElements = innerHosts;
            }
          };
          hideHandler();
          observeDOMChanges(hideHandler, true);
        }
        hideInShadowDom.names = ['hide-in-shadow-dom'];
        hideInShadowDom.injections = [hit, observeDOMChanges, flatten, findHostElements, pierceShadowDom];
        function removeInShadowDom(source, selector, baseSelector) {
          if (!Element.prototype.attachShadow) {
            return;
          }
          var removeElement = function removeElement(targetElement) {
            targetElement.remove();
          };
          var removeHandler = function removeHandler() {
            var hostElements = !baseSelector ? findHostElements(document.documentElement) : document.querySelectorAll(baseSelector);
            while (hostElements.length !== 0) {
              var isRemoved = false;
              var _pierceShadowDom = pierceShadowDom(selector, hostElements),
                  targets = _pierceShadowDom.targets,
                  innerHosts = _pierceShadowDom.innerHosts;
              targets.forEach(function (targetEl) {
                removeElement(targetEl);
                isRemoved = true;
              });
              if (isRemoved) {
                hit(source);
              }
              hostElements = innerHosts;
            }
          };
          removeHandler();
          observeDOMChanges(removeHandler, true);
        }
        removeInShadowDom.names = ['remove-in-shadow-dom'];
        removeInShadowDom.injections = [hit, observeDOMChanges, flatten, findHostElements, pierceShadowDom];
        function preventFetch(source, propsToMatch) {
          if (typeof fetch === 'undefined' || typeof Proxy === 'undefined') {
            return;
          }
          var handlerWrapper = function handlerWrapper(target, thisArg, args) {
            var shouldPrevent = false;
            var fetchData = getFetchData(args);
            if (typeof propsToMatch === 'undefined') {
              var logMessage = "log: fetch( ".concat(objectToString(fetchData), " )");
              hit(source, logMessage);
            } else if (propsToMatch === '' || propsToMatch === getWildcardSymbol()) {
              shouldPrevent = true;
            } else {
              var parsedData = parseMatchProps(propsToMatch);
              if (!validateParsedData(parsedData)) {
                console.log("Invalid parameter: ".concat(propsToMatch));
                shouldPrevent = false;
              } else {
                var matchData = getMatchPropsData(parsedData);
                shouldPrevent = Object.keys(matchData).every(function (matchKey) {
                  var matchValue = matchData[matchKey];
                  return Object.prototype.hasOwnProperty.call(fetchData, matchKey) && matchValue.test(fetchData[matchKey]);
                });
              }
            }
            if (shouldPrevent) {
              hit(source);
              return noopPromiseResolve();
            }
            return Reflect.apply(target, thisArg, args);
          };
          var fetchHandler = {
            apply: handlerWrapper
          };
          fetch = new Proxy(fetch, fetchHandler);
        }
        preventFetch.names = ['prevent-fetch',
        'no-fetch-if.js', 'ubo-no-fetch-if.js', 'ubo-no-fetch-if'];
        preventFetch.injections = [hit, getFetchData, objectToString, parseMatchProps, validateParsedData, getMatchPropsData, noopPromiseResolve, getWildcardSymbol, toRegExp, validateStrPattern, isEmptyObject, getRequestData, getObjectEntries, getObjectFromEntries];
        function setLocalStorageItem(source, key, value) {
          if (!key || !value && value !== '') {
            return;
          }
          var keyValue;
          if (value === 'undefined') {
            keyValue = undefined;
          } else if (value === 'false') {
            keyValue = false;
          } else if (value === 'true') {
            keyValue = true;
          } else if (value === 'null') {
            keyValue = null;
          } else if (value === 'emptyArr') {
            keyValue = '[]';
          } else if (value === 'emptyObj') {
            keyValue = '{}';
          } else if (value === '') {
            keyValue = '';
          } else if (/^\d+$/.test(value)) {
            keyValue = parseFloat(value);
            if (nativeIsNaN(keyValue)) {
              return;
            }
            if (Math.abs(keyValue) > 0x7FFF) {
              return;
            }
          } else if (value === 'yes') {
            keyValue = 'yes';
          } else if (value === 'no') {
            keyValue = 'no';
          } else {
            return;
          }
          var setItem = function setItem(key, value) {
            var _window = window,
                localStorage = _window.localStorage;
            try {
              localStorage.setItem(key, value);
              hit(source);
            } catch (e) {
              if (source.verbose) {
                console.log("Was unable to set localStorage item due to: ".concat(e.message));
              }
            }
          };
          setItem(key, keyValue);
        }
        setLocalStorageItem.names = ['set-local-storage-item'];
        setLocalStorageItem.injections = [hit, nativeIsNaN];
        function setSessionStorageItem(source, key, value) {
          if (!key || !value && value !== '') {
            return;
          }
          var keyValue;
          if (value === 'undefined') {
            keyValue = undefined;
          } else if (value === 'false') {
            keyValue = false;
          } else if (value === 'true') {
            keyValue = true;
          } else if (value === 'null') {
            keyValue = null;
          } else if (value === 'emptyArr') {
            keyValue = '[]';
          } else if (value === 'emptyObj') {
            keyValue = '{}';
          } else if (value === '') {
            keyValue = '';
          } else if (/^\d+$/.test(value)) {
            keyValue = parseFloat(value);
            if (nativeIsNaN(keyValue)) {
              return;
            }
            if (Math.abs(keyValue) > 0x7FFF) {
              return;
            }
          } else if (value === 'yes') {
            keyValue = 'yes';
          } else if (value === 'no') {
            keyValue = 'no';
          } else {
            return;
          }
          var setItem = function setItem(key, value) {
            var _window = window,
                sessionStorage = _window.sessionStorage;
            try {
              sessionStorage.setItem(key, value);
              hit(source);
            } catch (e) {
              if (source.verbose) {
                console.log("Was unable to set sessionStorage item due to: ".concat(e.message));
              }
            }
          };
          setItem(key, keyValue);
        }
        setSessionStorageItem.names = ['set-session-storage-item'];
        setSessionStorageItem.injections = [hit, nativeIsNaN];
        function abortOnStackTrace(source, property, stack) {
          if (!property || !stack) {
            return;
          }
          var rid = randomId();
          var abort = function abort() {
            hit(source);
            throw new ReferenceError(rid);
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            var value = base[prop];
            if (!validateStrPattern(stack)) {
              console.log("Invalid parameter: ".concat(stack));
              return;
            }
            setPropertyAccess(base, prop, {
              get: function get() {
                if (matchStackTrace(stack, new Error().stack)) {
                  abort();
                }
                return value;
              },
              set: function set(newValue) {
                if (matchStackTrace(stack, new Error().stack)) {
                  abort();
                }
                value = newValue;
              }
            });
          };
          setChainPropAccess(window, property);
          window.onerror = createOnErrorHandler(rid).bind();
        }
        abortOnStackTrace.names = ['abort-on-stack-trace',
        'abort-on-stack-trace.js', 'ubo-abort-on-stack-trace.js', 'aost.js', 'ubo-aost.js', 'ubo-abort-on-stack-trace', 'ubo-aost', 'abp-abort-on-stack-trace'];
        abortOnStackTrace.injections = [randomId, setPropertyAccess, getPropertyInChain, createOnErrorHandler, hit, validateStrPattern, matchStackTrace, toRegExp];
        function logOnStacktrace(source, property) {
          if (!property) {
            return;
          }
          var refineStackTrace = function refineStackTrace(stackString) {
            var stackSteps = stackString.split('\n').slice(2).map(function (line) {
              return line.replace(/ {4}at /, '');
            });
            var logInfoArray = stackSteps.map(function (line) {
              var funcName;
              var funcFullPath;
              var reg = /\(([^\)]+)\)/;
              if (line.match(reg)) {
                funcName = line.split(' ').slice(0, -1).join(' ');
                funcFullPath = line.match(reg)[1];
              } else {
                funcName = 'function name is not available';
                funcFullPath = line;
              }
              return [funcName, funcFullPath];
            });
            var logInfoObject = {};
            logInfoArray.forEach(function (pair) {
              logInfoObject[pair[0]] = pair[1];
            });
            return logInfoObject;
          };
          var setChainPropAccess = function setChainPropAccess(owner, property) {
            var chainInfo = getPropertyInChain(owner, property);
            var base = chainInfo.base;
            var prop = chainInfo.prop,
                chain = chainInfo.chain;
            if (chain) {
              var setter = function setter(a) {
                base = a;
                if (a instanceof Object) {
                  setChainPropAccess(a, chain);
                }
              };
              Object.defineProperty(owner, prop, {
                get: function get() {
                  return base;
                },
                set: setter
              });
              return;
            }
            var value = base[prop];
            setPropertyAccess(base, prop, {
              get: function get() {
                hit(source);
                console.log("%cGet %c".concat(prop), 'color:red;', 'color:green;');
                console.table(refineStackTrace(new Error().stack));
                return value;
              },
              set: function set(newValue) {
                hit(source);
                console.log("%cSet %c".concat(prop), 'color:red;', 'color:green;');
                console.table(refineStackTrace(new Error().stack));
                value = newValue;
              }
            });
          };
          setChainPropAccess(window, property);
        }
        logOnStacktrace.names = ['log-on-stack-trace'];
        logOnStacktrace.injections = [getPropertyInChain, setPropertyAccess, hit];
        function preventXHR(source, propsToMatch, randomize) {
          if (typeof Proxy === 'undefined') {
            return;
          }
          var shouldPrevent = false;
          var responseText = '';
          var responseUrl;
          var openWrapper = function openWrapper(target, thisArg, args) {
            var xhrData = {
              method: args[0],
              url: args[1]
            };
            responseUrl = xhrData.url;
            if (typeof propsToMatch === 'undefined') {
              var logMessage = "log: xhr( ".concat(objectToString(xhrData), " )");
              hit(source, logMessage);
            } else if (propsToMatch === '' || propsToMatch === getWildcardSymbol()) {
              shouldPrevent = true;
            } else {
              var parsedData = parseMatchProps(propsToMatch);
              if (!validateParsedData(parsedData)) {
                console.log("Invalid parameter: ".concat(propsToMatch));
                shouldPrevent = false;
              } else {
                var matchData = getMatchPropsData(parsedData);
                shouldPrevent = Object.keys(matchData).every(function (matchKey) {
                  var matchValue = matchData[matchKey];
                  return Object.prototype.hasOwnProperty.call(xhrData, matchKey) && matchValue.test(xhrData[matchKey]);
                });
              }
            }
            return Reflect.apply(target, thisArg, args);
          };
          var sendWrapper = function sendWrapper(target, thisArg, args) {
            if (!shouldPrevent) {
              return Reflect.apply(target, thisArg, args);
            }
            if (randomize === 'true') {
              responseText = Math.random().toString(36).slice(-10);
            }
            Object.defineProperties(thisArg, {
              readyState: {
                value: 4,
                writable: false
              },
              response: {
                value: '',
                writable: false
              },
              responseText: {
                value: responseText,
                writable: false
              },
              responseURL: {
                value: responseUrl,
                writable: false
              },
              responseXML: {
                value: '',
                writable: false
              },
              status: {
                value: 200,
                writable: false
              },
              statusText: {
                value: 'OK',
                writable: false
              }
            });
            setTimeout(function () {
              var stateEvent = new Event('readystatechange');
              thisArg.dispatchEvent(stateEvent);
              var loadEvent = new Event('load');
              thisArg.dispatchEvent(loadEvent);
              var loadEndEvent = new Event('loadend');
              thisArg.dispatchEvent(loadEndEvent);
            }, 1);
            hit(source);
            return undefined;
          };
          var openHandler = {
            apply: openWrapper
          };
          var sendHandler = {
            apply: sendWrapper
          };
          XMLHttpRequest.prototype.open = new Proxy(XMLHttpRequest.prototype.open, openHandler);
          XMLHttpRequest.prototype.send = new Proxy(XMLHttpRequest.prototype.send, sendHandler);
        }
        preventXHR.names = ['prevent-xhr',
        'no-xhr-if.js', 'ubo-no-xhr-if.js', 'ubo-no-xhr-if'];
        preventXHR.injections = [hit, objectToString, getWildcardSymbol, parseMatchProps, validateParsedData, getMatchPropsData, toRegExp, validateStrPattern, isEmptyObject, getObjectEntries];
        function forceWindowClose(source) {
          var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
          var log = console.log.bind(console);
          if (typeof window.close !== 'function') {
            if (source.verbose) {
              log('window.close() is not a function so \'close-window\' scriptlet is unavailable');
            }
            return;
          }
          var closeImmediately = function closeImmediately() {
            try {
              hit(source);
              window.close();
            } catch (e) {
              log(e);
            }
          };
          if (path === '') {
            closeImmediately();
          } else {
            var pathRegexp = toRegExp(path);
            var currentPath = "".concat(window.location.pathname).concat(window.location.search);
            if (pathRegexp.test(currentPath)) {
              closeImmediately();
            }
          }
        }
        forceWindowClose.names = ['close-window', 'window-close-if.js', 'ubo-window-close-if.js', 'ubo-window-close-if'];
        forceWindowClose.injections = [hit, toRegExp];
        function preventRefresh(source, delaySec) {
          var getMetaElements = function getMetaElements() {
            var metaNodes = [];
            try {
              metaNodes = document.querySelectorAll('meta[http-equiv="refresh" i][content]');
            } catch (e) {
              try {
                metaNodes = document.querySelectorAll('meta[http-equiv="refresh"][content]');
              } catch (e) {
                if (source.verbose) {
                  console.log(e);
                }
              }
            }
            return Array.from(metaNodes);
          };
          var getMetaContentDelay = function getMetaContentDelay(metaElements) {
            var delays = metaElements.map(function (meta) {
              var contentString = meta.getAttribute('content');
              if (contentString.length === 0) {
                return null;
              }
              var contentDelay;
              var limiterIndex = contentString.indexOf(';');
              if (limiterIndex !== -1) {
                var delaySubstring = contentString.substring(0, limiterIndex);
                contentDelay = getNumberFromString(delaySubstring);
              } else {
                contentDelay = getNumberFromString(contentString);
              }
              return contentDelay;
            }).filter(function (delay) {
              return delay !== null;
            });
            var minDelay = delays.reduce(function (a, b) {
              return Math.min(a, b);
            });
            return minDelay;
          };
          var stop = function stop() {
            var metaElements = getMetaElements();
            if (metaElements.length === 0) {
              return;
            }
            var secondsToRun = getNumberFromString(delaySec);
            if (!secondsToRun) {
              secondsToRun = getMetaContentDelay(metaElements);
            }
            if (!secondsToRun) {
              return;
            }
            var delayMs = secondsToRun * 1000;
            setTimeout(function () {
              window.stop();
              hit(source);
            }, delayMs);
          };
          if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', stop, {
              once: true
            });
          } else {
            stop();
          }
        }
        preventRefresh.names = ['prevent-refresh',
        'refresh-defuser.js', 'refresh-defuser',
        'ubo-refresh-defuser.js', 'ubo-refresh-defuser'];
        preventRefresh.injections = [hit, getNumberFromString, nativeIsNaN];
        function preventElementSrcLoading(source, tagName, match) {
          if (typeof Proxy === 'undefined' || typeof Reflect === 'undefined') {
            return;
          }
          var srcMockData = {
            script: 'data:text/javascript;base64,KCk9Pnt9',
            img: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==',
            iframe: 'data:text/html;base64, PGRpdj48L2Rpdj4='
          };
          var instance;
          if (tagName === 'script') {
            instance = HTMLScriptElement;
          } else if (tagName === 'img') {
            instance = HTMLImageElement;
          } else if (tagName === 'iframe') {
            instance = HTMLIFrameElement;
          } else {
            return;
          }
          var hasTrustedTypes = window.trustedTypes && typeof window.trustedTypes.createPolicy === 'function';
          var policy;
          if (hasTrustedTypes) {
            policy = window.trustedTypes.createPolicy('mock', {
              createScriptURL: function createScriptURL(arg) {
                return arg;
              }
            });
          }
          var SOURCE_PROPERTY_NAME = 'src';
          var searchRegexp = toRegExp(match);
          var setAttributeWrapper = function setAttributeWrapper(target, thisArg, args) {
            if (!args[0] || !args[1]) {
              return Reflect.apply(target, thisArg, args);
            }
            var nodeName = thisArg.nodeName.toLowerCase();
            var attrName = args[0].toLowerCase();
            var attrValue = args[1];
            var isMatched = attrName === SOURCE_PROPERTY_NAME && tagName.toLowerCase() === nodeName && srcMockData[nodeName] && searchRegexp.test(attrValue);
            if (!isMatched) {
              return Reflect.apply(target, thisArg, args);
            }
            hit(source);
            return Reflect.apply(target, thisArg, [attrName, srcMockData[nodeName]]);
          };
          var setAttributeHandler = {
            apply: setAttributeWrapper
          };
          instance.prototype.setAttribute = new Proxy(Element.prototype.setAttribute, setAttributeHandler);
          var origDescriptor = safeGetDescriptor(instance.prototype, SOURCE_PROPERTY_NAME);
          if (!origDescriptor) {
            return;
          }
          Object.defineProperty(instance.prototype, SOURCE_PROPERTY_NAME, {
            enumerable: true,
            configurable: true,
            get: function get() {
              return origDescriptor.get.call(this);
            },
            set: function set(urlValue) {
              var nodeName = this.nodeName.toLowerCase();
              var isMatched = tagName.toLowerCase() === nodeName && srcMockData[nodeName] && searchRegexp.test(urlValue);
              if (!isMatched) {
                origDescriptor.set.call(this, urlValue);
                return;
              }
              if (policy && urlValue instanceof TrustedScriptURL) {
                var trustedSrc = policy.createScriptURL(urlValue);
                origDescriptor.set.call(this, trustedSrc);
                hit(source);
                return;
              }
              origDescriptor.set.call(this, srcMockData[nodeName]);
              hit(source);
            }
          });
        }
        preventElementSrcLoading.names = ['prevent-element-src-loading'];
        preventElementSrcLoading.injections = [hit, toRegExp, safeGetDescriptor];
        var scriptletList = Object.freeze({
            __proto__: null,
            abortOnPropertyRead: abortOnPropertyRead,
            abortOnPropertyWrite: abortOnPropertyWrite,
            preventSetTimeout: preventSetTimeout,
            preventSetInterval: preventSetInterval,
            preventWindowOpen: preventWindowOpen,
            abortCurrentInlineScript: abortCurrentInlineScript,
            setConstant: setConstant,
            removeCookie: removeCookie,
            preventAddEventListener: preventAddEventListener,
            preventBab: preventBab,
            nowebrtc: nowebrtc,
            logAddEventListener: logAddEventListener,
            logEval: logEval,
            log: log,
            noeval: noeval,
            preventEvalIf: preventEvalIf,
            preventFab: preventFab,
            setPopadsDummy: setPopadsDummy,
            preventPopadsNet: preventPopadsNet,
            preventAdfly: preventAdfly,
            debugOnPropertyRead: debugOnPropertyRead,
            debugOnPropertyWrite: debugOnPropertyWrite,
            debugCurrentInlineScript: debugCurrentInlineScript,
            removeAttr: removeAttr,
            setAttr: setAttr,
            removeClass: removeClass,
            disableNewtabLinks: disableNewtabLinks,
            adjustSetInterval: adjustSetInterval,
            adjustSetTimeout: adjustSetTimeout,
            dirString: dirString,
            jsonPrune: jsonPrune,
            preventRequestAnimationFrame: preventRequestAnimationFrame,
            setCookie: setCookie,
            setCookieReload: setCookieReload,
            hideInShadowDom: hideInShadowDom,
            removeInShadowDom: removeInShadowDom,
            preventFetch: preventFetch,
            setLocalStorageItem: setLocalStorageItem,
            setSessionStorageItem: setSessionStorageItem,
            abortOnStackTrace: abortOnStackTrace,
            logOnStacktrace: logOnStacktrace,
            preventXHR: preventXHR,
            forceWindowClose: forceWindowClose,
            preventRefresh: preventRefresh,
            preventElementSrcLoading: preventElementSrcLoading
        });
        var redirects = [{
          adg: '1x1-transparent.gif',
          ubo: '1x1.gif',
          abp: '1x1-transparent-gif'
        }, {
          adg: '2x2-transparent.png',
          ubo: '2x2.png',
          abp: '2x2-transparent-png'
        }, {
          adg: '3x2-transparent.png',
          ubo: '3x2.png',
          abp: '3x2-transparent-png'
        }, {
          adg: '32x32-transparent.png',
          ubo: '32x32.png',
          abp: '32x32-transparent-png'
        }, {
          adg: 'amazon-apstag',
          ubo: 'amazon_apstag.js'
        }, {
          adg: 'ati-smarttag'
        }, {
          adg: 'didomi-loader'
        }, {
          adg: 'click2load.html',
          ubo: 'click2load.html'
        }, {
          adg: 'fingerprintjs2',
          ubo: 'fingerprint2.js'
        }, {
          adg: 'fingerprintjs3',
          ubo: 'fingerprint3.js'
        }, {
          adg: 'google-analytics',
          ubo: 'google-analytics_analytics.js'
        }, {
          adg: 'google-analytics-ga',
          ubo: 'google-analytics_ga.js'
        }, {
          adg: 'googlesyndication-adsbygoogle',
          ubo: 'googlesyndication_adsbygoogle.js'
        }, {
          adg: 'googlesyndication-adsbygoogle',
          ubo: 'googlesyndication.com/adsbygoogle.js'
        }, {
          adg: 'googletagmanager-gtm',
          ubo: 'google-analytics_ga.js'
        }, {
          adg: 'googletagservices-gpt',
          ubo: 'googletagservices_gpt.js'
        }, {
          adg: 'google-ima3'
        }, {
          adg: 'gemius'
        }, {
          adg: 'matomo'
        }, {
          adg: 'metrika-yandex-watch'
        }, {
          adg: 'metrika-yandex-tag'
        }, {
          adg: 'naver-wcslog'
        }, {
          adg: 'noeval',
          ubo: 'noeval-silent.js'
        }, {
          adg: 'noopcss',
          abp: 'blank-css'
        }, {
          adg: 'noopframe',
          ubo: 'noop.html',
          abp: 'blank-html'
        }, {
          adg: 'noopjs',
          ubo: 'noop.js',
          abp: 'blank-js'
        }, {
          adg: 'noopjson'
        }, {
          adg: 'nooptext',
          ubo: 'noop.txt',
          abp: 'blank-text'
        }, {
          adg: 'noopmp3-0.1s',
          ubo: 'noop-0.1s.mp3',
          abp: 'blank-mp3'
        }, {
          adg: 'noopmp4-1s',
          ubo: 'noop-1s.mp4',
          abp: 'blank-mp4'
        }, {
          adg: 'noopvmap-1.0',
          ubo: 'noop-vmap1.0.xml'
        }, {
          adg: 'noopvast-2.0'
        }, {
          adg: 'noopvast-3.0'
        }, {
          adg: 'prebid'
        }, {
          adg: 'prevent-bab',
          ubo: 'nobab.js'
        }, {
          adg: 'prevent-bab2',
          ubo: 'nobab2.js'
        }, {
          adg: 'prevent-fab-3.2.0',
          ubo: 'nofab.js'
        }, {
          adg: 'prevent-popads-net',
          ubo: 'popads.js'
        }, {
          adg: 'scorecardresearch-beacon',
          ubo: 'scorecardresearch_beacon.js'
        }, {
          adg: 'set-popads-dummy',
          ubo: 'popads-dummy.js'
        }, {
          adg: 'empty',
          ubo: 'empty'
        }, {
          adg: 'prebid-ads',
          ubo: 'prebid-ads.js'
        }];
        var JS_RULE_MARKER = '#%#';
        var COMMENT_MARKER = '!';
        var isComment = function isComment(rule) {
          return startsWith(rule, COMMENT_MARKER);
        };
        var UBO_SCRIPTLET_MASK_REG = /#@?#script:inject|#@?#\s*\+js/;
        var UBO_SCRIPTLET_MASK_1 = '##+js';
        var UBO_SCRIPTLET_MASK_2 = '##script:inject';
        var UBO_SCRIPTLET_EXCEPTION_MASK_1 = '#@#+js';
        var UBO_SCRIPTLET_EXCEPTION_MASK_2 = '#@#script:inject';
        var ABP_SCRIPTLET_MASK = '#$#';
        var ABP_SCRIPTLET_EXCEPTION_MASK = '#@$#';
        var ADG_CSS_MASK_REG = /#@?\$#.+?\s*\{.*\}\s*$/g;
        var isAdgScriptletRule = function isAdgScriptletRule(rule) {
          return !isComment(rule) && rule.indexOf(ADG_SCRIPTLET_MASK) > -1;
        };
        var isUboScriptletRule = function isUboScriptletRule(rule) {
          return (rule.indexOf(UBO_SCRIPTLET_MASK_1) > -1 || rule.indexOf(UBO_SCRIPTLET_MASK_2) > -1 || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_1) > -1 || rule.indexOf(UBO_SCRIPTLET_EXCEPTION_MASK_2) > -1) && UBO_SCRIPTLET_MASK_REG.test(rule) && !isComment(rule);
        };
        var isAbpSnippetRule = function isAbpSnippetRule(rule) {
          return (rule.indexOf(ABP_SCRIPTLET_MASK) > -1 || rule.indexOf(ABP_SCRIPTLET_EXCEPTION_MASK) > -1) && rule.search(ADG_CSS_MASK_REG) === -1 && !isComment(rule);
        };
        var getScriptletByName = function getScriptletByName(name) {
          var scriptlets = Object.keys(scriptletList).map(function (key) {
            return scriptletList[key];
          });
          return scriptlets.find(function (s) {
            return s.names
            && (s.names.indexOf(name) > -1
            || !endsWith(name, '.js') && s.names.indexOf("".concat(name, ".js")) > -1);
          });
        };
        var isValidScriptletName = function isValidScriptletName(name) {
          if (!name) {
            return false;
          }
          var scriptlet = getScriptletByName(name);
          if (!scriptlet) {
            return false;
          }
          return true;
        };
        var ADG_UBO_REDIRECT_MARKER = 'redirect=';
        var ADG_UBO_REDIRECT_RULE_MARKER = 'redirect-rule=';
        var ABP_REDIRECT_MARKER = 'rewrite=abp-resource:';
        var EMPTY_REDIRECT_MARKER = 'empty';
        var VALID_SOURCE_TYPES = ['image', 'media', 'subdocument', 'stylesheet', 'script', 'xmlhttprequest', 'other'];
        var ABSENT_SOURCE_TYPE_REPLACEMENT = [{
          NAME: 'nooptext',
          TYPES: VALID_SOURCE_TYPES
        }, {
          NAME: 'noopjs',
          TYPES: ['script']
        }, {
          NAME: 'noopframe',
          TYPES: ['subdocument']
        }, {
          NAME: '1x1-transparent.gif',
          TYPES: ['image']
        }, {
          NAME: 'noopmp3-0.1s',
          TYPES: ['media']
        }, {
          NAME: 'noopmp4-1s',
          TYPES: ['media']
        }, {
          NAME: 'googlesyndication-adsbygoogle',
          TYPES: ['xmlhttprequest', 'script']
        }, {
          NAME: 'google-analytics',
          TYPES: ['script']
        }, {
          NAME: 'googletagservices-gpt',
          TYPES: ['script']
        }];
        var validAdgRedirects = redirects.filter(function (el) {
          return el.adg;
        });
        var uboToAdgCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
          return el.ubo;
        }).map(function (el) {
          return [el.ubo, el.adg];
        }));
        var abpToAdgCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
          return el.abp;
        }).map(function (el) {
          return [el.abp, el.adg];
        }));
        var adgToUboCompatibility = getObjectFromEntries(validAdgRedirects.filter(function (el) {
          return el.ubo;
        }).map(function (el) {
          return [el.adg, el.ubo];
        }));
        var validAdgCompatibility = getObjectFromEntries(validAdgRedirects.map(function (el) {
          return [el.adg, 'valid adg redirect'];
        }));
        var REDIRECT_RULE_TYPES = {
          VALID_ADG: {
            redirectMarker: ADG_UBO_REDIRECT_MARKER,
            redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
            compatibility: validAdgCompatibility
          },
          ADG: {
            redirectMarker: ADG_UBO_REDIRECT_MARKER,
            redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
            compatibility: adgToUboCompatibility
          },
          UBO: {
            redirectMarker: ADG_UBO_REDIRECT_MARKER,
            redirectRuleMarker: ADG_UBO_REDIRECT_RULE_MARKER,
            compatibility: uboToAdgCompatibility
          },
          ABP: {
            redirectMarker: ABP_REDIRECT_MARKER,
            compatibility: abpToAdgCompatibility
          }
        };
        var parseModifiers = function parseModifiers(rule) {
          return substringAfter(rule, '$').split(',');
        };
        var getRedirectName = function getRedirectName(rule, marker) {
          var ruleModifiers = parseModifiers(rule);
          var redirectNamePart = ruleModifiers.find(function (el) {
            return el.indexOf(marker) > -1;
          });
          return substringAfter(redirectNamePart, marker);
        };
        var isAdgRedirectRule = function isAdgRedirectRule(rule) {
          var MARKER_IN_BASE_PART_MASK = '/((?!\\$|\\,).{1})redirect((-rule)?)=(.{0,}?)\\$(popup)?/';
          return !isComment(rule) && (rule.indexOf(REDIRECT_RULE_TYPES.ADG.redirectMarker) > -1 || rule.indexOf(REDIRECT_RULE_TYPES.ADG.redirectRuleMarker) > -1)
          && rule.indexOf(JS_RULE_MARKER) === -1
          && !toRegExp(MARKER_IN_BASE_PART_MASK).test(rule);
        };
        var isRedirectRuleByType = function isRedirectRuleByType(rule, type) {
          var _REDIRECT_RULE_TYPES$ = REDIRECT_RULE_TYPES[type],
              redirectMarker = _REDIRECT_RULE_TYPES$.redirectMarker,
              redirectRuleMarker = _REDIRECT_RULE_TYPES$.redirectRuleMarker,
              compatibility = _REDIRECT_RULE_TYPES$.compatibility;
          if (rule && !isComment(rule)) {
            var marker;
            var markerIndex = redirectRuleMarker ? rule.indexOf(redirectRuleMarker) : -1;
            if (markerIndex > -1) {
              marker = redirectRuleMarker;
            } else {
              markerIndex = rule.indexOf(redirectMarker);
              if (markerIndex > -1) {
                marker = redirectMarker;
              } else {
                return false;
              }
            }
            var redirectName = getRedirectName(rule, marker);
            if (!redirectName) {
              return false;
            }
            return redirectName === Object.keys(compatibility).find(function (el) {
              return el === redirectName;
            });
          }
          return false;
        };
        var isValidAdgRedirectRule = function isValidAdgRedirectRule(rule) {
          return isRedirectRuleByType(rule, 'VALID_ADG');
        };
        var isAdgRedirectCompatibleWithUbo = function isAdgRedirectCompatibleWithUbo(rule) {
          return isAdgRedirectRule(rule) && isRedirectRuleByType(rule, 'ADG');
        };
        var isUboRedirectCompatibleWithAdg = function isUboRedirectCompatibleWithAdg(rule) {
          return isRedirectRuleByType(rule, 'UBO');
        };
        var isAbpRedirectCompatibleWithAdg = function isAbpRedirectCompatibleWithAdg(rule) {
          return isRedirectRuleByType(rule, 'ABP');
        };
        var hasValidContentType = function hasValidContentType(rule) {
          var ruleModifiers = parseModifiers(rule);
          var sourceTypes = ruleModifiers.filter(function (el) {
            return VALID_SOURCE_TYPES.indexOf(el) > -1;
          });
          var isSourceTypeSpecified = sourceTypes.length > 0;
          var isEmptyRedirect = ruleModifiers.indexOf("".concat(ADG_UBO_REDIRECT_MARKER).concat(EMPTY_REDIRECT_MARKER)) > -1 || ruleModifiers.indexOf("".concat(ADG_UBO_REDIRECT_RULE_MARKER).concat(EMPTY_REDIRECT_MARKER)) > -1;
          if (isEmptyRedirect) {
            return true;
          }
          return isSourceTypeSpecified;
        };
        var validator = {
          UBO_SCRIPTLET_MASK_REG: UBO_SCRIPTLET_MASK_REG,
          ABP_SCRIPTLET_MASK: ABP_SCRIPTLET_MASK,
          ABP_SCRIPTLET_EXCEPTION_MASK: ABP_SCRIPTLET_EXCEPTION_MASK,
          isComment: isComment,
          isAdgScriptletRule: isAdgScriptletRule,
          isUboScriptletRule: isUboScriptletRule,
          isAbpSnippetRule: isAbpSnippetRule,
          getScriptletByName: getScriptletByName,
          isValidScriptletName: isValidScriptletName,
          ADG_UBO_REDIRECT_RULE_MARKER: ADG_UBO_REDIRECT_RULE_MARKER,
          REDIRECT_RULE_TYPES: REDIRECT_RULE_TYPES,
          ABSENT_SOURCE_TYPE_REPLACEMENT: ABSENT_SOURCE_TYPE_REPLACEMENT,
          isAdgRedirectRule: isAdgRedirectRule,
          isValidAdgRedirectRule: isValidAdgRedirectRule,
          isAdgRedirectCompatibleWithUbo: isAdgRedirectCompatibleWithUbo,
          isUboRedirectCompatibleWithAdg: isUboRedirectCompatibleWithAdg,
          isAbpRedirectCompatibleWithAdg: isAbpRedirectCompatibleWithAdg,
          parseModifiers: parseModifiers,
          getRedirectName: getRedirectName,
          hasValidContentType: hasValidContentType
        };
        function _arrayLikeToArray(arr, len) {
          if (len == null || len > arr.length) len = arr.length;
          for (var i = 0, arr2 = new Array(len); i < len; i++) {
            arr2[i] = arr[i];
          }
          return arr2;
        }
        var arrayLikeToArray = _arrayLikeToArray;
        function _arrayWithoutHoles(arr) {
          if (Array.isArray(arr)) return arrayLikeToArray(arr);
        }
        var arrayWithoutHoles = _arrayWithoutHoles;
        function _iterableToArray(iter) {
          if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
        }
        var iterableToArray = _iterableToArray;
        function _unsupportedIterableToArray(o, minLen) {
          if (!o) return;
          if (typeof o === "string") return arrayLikeToArray(o, minLen);
          var n = Object.prototype.toString.call(o).slice(8, -1);
          if (n === "Object" && o.constructor) n = o.constructor.name;
          if (n === "Map" || n === "Set") return Array.from(o);
          if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
        }
        var unsupportedIterableToArray = _unsupportedIterableToArray;
        function _nonIterableSpread() {
          throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
        }
        var nonIterableSpread = _nonIterableSpread;
        function _toConsumableArray(arr) {
          return arrayWithoutHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableSpread();
        }
        var toConsumableArray = _toConsumableArray;
        function _arrayWithHoles(arr) {
          if (Array.isArray(arr)) return arr;
        }
        var arrayWithHoles = _arrayWithHoles;
        function _nonIterableRest() {
          throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
        }
        var nonIterableRest = _nonIterableRest;
        function _toArray(arr) {
          return arrayWithHoles(arr) || iterableToArray(arr) || unsupportedIterableToArray(arr) || nonIterableRest();
        }
        var toArray = _toArray;
        var ADGUARD_SCRIPTLET_MASK_REG = /#@?%#\/\/scriptlet\(.+\)/;
        var ADGUARD_SCRIPTLET_TEMPLATE = '${domains}#%#//scriptlet(${args})';
        var ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE = '${domains}#@%#//scriptlet(${args})';
        var UBO_SCRIPTLET_TEMPLATE = '${domains}##+js(${args})';
        var UBO_SCRIPTLET_EXCEPTION_TEMPLATE = '${domains}#@#+js(${args})';
        var UBO_ALIAS_NAME_MARKER = 'ubo-';
        var UBO_SCRIPTLET_JS_ENDING = '.js';
        var UBO_XHR_TYPE = 'xhr';
        var ADG_XHR_TYPE = 'xmlhttprequest';
        var ADG_SET_CONSTANT_NAME = 'set-constant';
        var ADG_SET_CONSTANT_EMPTY_STRING = '';
        var UBO_SET_CONSTANT_EMPTY_STRING = '\'\'';
        var ADG_PREVENT_FETCH_NAME = 'prevent-fetch';
        var ADG_PREVENT_FETCH_EMPTY_STRING = '';
        var ADG_PREVENT_FETCH_WILDCARD = getWildcardSymbol();
        var UBO_NO_FETCH_IF_WILDCARD = '/^/';
        var ESCAPED_COMMA_SEPARATOR = '\\,';
        var COMMA_SEPARATOR = ',';
        var REMOVE_ATTR_METHOD = 'removeAttr';
        var REMOVE_CLASS_METHOD = 'removeClass';
        var REMOVE_ATTR_ALIASES = scriptletList[REMOVE_ATTR_METHOD].names;
        var REMOVE_CLASS_ALIASES = scriptletList[REMOVE_CLASS_METHOD].names;
        var ADG_REMOVE_ATTR_NAME = REMOVE_ATTR_ALIASES[0];
        var ADG_REMOVE_CLASS_NAME = REMOVE_CLASS_ALIASES[0];
        var REMOVE_ATTR_CLASS_APPLYING = ['asap', 'stay', 'complete'];
        var getSentences = function getSentences(str) {
          var reg = /'.*?'|".*?"|\S+/g;
          return str.match(reg);
        };
        var replacePlaceholders = function replacePlaceholders(str, data) {
          return Object.keys(data).reduce(function (acc, key) {
            var reg = new RegExp("\\$\\{".concat(key, "\\}"), 'g');
            acc = acc.replace(reg, data[key]);
            return acc;
          }, str);
        };
        var splitArgs = function splitArgs(str) {
          var args = [];
          var prevArgStart = 0;
          for (var i = 0; i < str.length; i += 1) {
            if (str[i] === COMMA_SEPARATOR && str[i - 1] !== '\\') {
              args.push(str.slice(prevArgStart, i).trim());
              prevArgStart = i + 1;
            }
          }
          args.push(str.slice(prevArgStart, str.length).trim());
          return args;
        };
        var validateRemoveAttrClassArgs = function validateRemoveAttrClassArgs(parsedArgs) {
          var lastArg = parsedArgs.pop();
          var _parsedArgs = toArray(parsedArgs),
              name = _parsedArgs[0],
              value = _parsedArgs[1],
              restArgs = _parsedArgs.slice(2);
          var applying;
          if (REMOVE_ATTR_CLASS_APPLYING.some(function (el) {
            return lastArg.indexOf(el) > -1;
          })) {
            applying = lastArg;
          } else {
            restArgs.push(lastArg);
          }
          var selector = replaceAll(restArgs.join(', '), ESCAPED_COMMA_SEPARATOR, COMMA_SEPARATOR);
          if (selector.length > 0 && typeof document !== 'undefined') {
            document.querySelectorAll(selector);
          }
          var validArgs = applying ? [name, value, selector, applying] : [name, value, selector];
          return validArgs;
        };
        var convertUboScriptletToAdg = function convertUboScriptletToAdg(rule) {
          var domains = getBeforeRegExp(rule, validator.UBO_SCRIPTLET_MASK_REG);
          var mask = rule.match(validator.UBO_SCRIPTLET_MASK_REG)[0];
          var template;
          if (mask.indexOf('@') > -1) {
            template = ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE;
          } else {
            template = ADGUARD_SCRIPTLET_TEMPLATE;
          }
          var argsStr = getStringInBraces(rule);
          var parsedArgs = splitArgs(argsStr);
          var scriptletName = parsedArgs[0].indexOf(UBO_SCRIPTLET_JS_ENDING) > -1 ? "ubo-".concat(parsedArgs[0]) : "ubo-".concat(parsedArgs[0]).concat(UBO_SCRIPTLET_JS_ENDING);
          if (REMOVE_ATTR_ALIASES.indexOf(scriptletName) > -1 || REMOVE_CLASS_ALIASES.indexOf(scriptletName) > -1) {
            parsedArgs = validateRemoveAttrClassArgs(parsedArgs);
          }
          var args = parsedArgs.map(function (arg, index) {
            var outputArg = arg;
            if (index === 0) {
              outputArg = scriptletName;
            }
            if (arg === '$') {
              outputArg = '$$';
            }
            return outputArg;
          }).map(function (arg) {
            return wrapInSingleQuotes(arg);
          }).join("".concat(COMMA_SEPARATOR, " "));
          var adgRule = replacePlaceholders(template, {
            domains: domains,
            args: args
          });
          return [adgRule];
        };
        var convertAbpSnippetToAdg = function convertAbpSnippetToAdg(rule) {
          var SEMICOLON_DIVIDER = /;(?=(?:(?:[^"]*"){2})*[^"]*$)/g;
          var mask = rule.indexOf(validator.ABP_SCRIPTLET_MASK) > -1 ? validator.ABP_SCRIPTLET_MASK : validator.ABP_SCRIPTLET_EXCEPTION_MASK;
          var template = mask === validator.ABP_SCRIPTLET_MASK ? ADGUARD_SCRIPTLET_TEMPLATE : ADGUARD_SCRIPTLET_EXCEPTION_TEMPLATE;
          var domains = substringBefore(rule, mask);
          var args = substringAfter(rule, mask);
          return args.split(SEMICOLON_DIVIDER).map(function (args) {
            return getSentences(args).filter(function (arg) {
              return arg;
            }).map(function (arg, index) {
              return index === 0 ? "abp-".concat(arg) : arg;
            }).map(function (arg) {
              return wrapInSingleQuotes(arg);
            }).join("".concat(COMMA_SEPARATOR, " "));
          }).map(function (args) {
            return replacePlaceholders(template, {
              domains: domains,
              args: args
            });
          });
        };
        var convertScriptletToAdg = function convertScriptletToAdg(rule) {
          var result;
          if (validator.isUboScriptletRule(rule)) {
            result = convertUboScriptletToAdg(rule);
          } else if (validator.isAbpSnippetRule(rule)) {
            result = convertAbpSnippetToAdg(rule);
          } else if (validator.isAdgScriptletRule(rule) || validator.isComment(rule)) {
            result = [rule];
          }
          return result;
        };
        var convertAdgScriptletToUbo = function convertAdgScriptletToUbo(rule) {
          var res;
          if (validator.isAdgScriptletRule(rule)) {
            var _parseRule = parseRule(rule),
                parsedName = _parseRule.name,
                parsedParams = _parseRule.args;
            var preparedParams;
            if (parsedName === ADG_SET_CONSTANT_NAME && parsedParams[1] === ADG_SET_CONSTANT_EMPTY_STRING) {
              preparedParams = [parsedParams[0], UBO_SET_CONSTANT_EMPTY_STRING];
            } else if (parsedName === ADG_PREVENT_FETCH_NAME
            && (parsedParams[0] === ADG_PREVENT_FETCH_WILDCARD || parsedParams[0] === ADG_PREVENT_FETCH_EMPTY_STRING)) {
              preparedParams = [UBO_NO_FETCH_IF_WILDCARD];
            } else if ((parsedName === ADG_REMOVE_ATTR_NAME || parsedName === ADG_REMOVE_CLASS_NAME) && parsedParams[1] && parsedParams[1].indexOf(COMMA_SEPARATOR) > -1) {
              preparedParams = [parsedParams[0], replaceAll(parsedParams[1], COMMA_SEPARATOR, ESCAPED_COMMA_SEPARATOR)];
            } else {
              preparedParams = parsedParams;
            }
            var adgScriptletObject = Object.keys(scriptletList).map(function (el) {
              return scriptletList[el];
            }).map(function (s) {
              var _s$names = toArray(s.names),
                  name = _s$names[0],
                  aliases = _s$names.slice(1);
              return {
                name: name,
                aliases: aliases
              };
            }).find(function (el) {
              return el.name === parsedName || el.aliases.indexOf(parsedName) >= 0;
            });
            var aliases = adgScriptletObject.aliases;
            if (aliases.length > 0) {
              var uboAlias = adgScriptletObject.aliases
              .find(function (alias) {
                return alias.includes(UBO_ALIAS_NAME_MARKER);
              });
              if (uboAlias) {
                var mask = rule.match(ADGUARD_SCRIPTLET_MASK_REG)[0];
                var template;
                if (mask.indexOf('@') > -1) {
                  template = UBO_SCRIPTLET_EXCEPTION_TEMPLATE;
                } else {
                  template = UBO_SCRIPTLET_TEMPLATE;
                }
                var domains = getBeforeRegExp(rule, ADGUARD_SCRIPTLET_MASK_REG);
                var uboName = uboAlias.replace(UBO_ALIAS_NAME_MARKER, '')
                .replace(UBO_SCRIPTLET_JS_ENDING, '');
                var args = preparedParams.length > 0 ? "".concat(uboName, ", ").concat(preparedParams.join("".concat(COMMA_SEPARATOR, " "))) : uboName;
                var uboRule = replacePlaceholders(template, {
                  domains: domains,
                  args: args
                });
                res = uboRule;
              }
            }
          }
          return res;
        };
        var isValidScriptletRule = function isValidScriptletRule(input) {
          if (!input) {
            return false;
          }
          var rulesArray = convertScriptletToAdg(input);
          var isValid = rulesArray.every(function (rule) {
            var parsedRule = parseRule(rule);
            return validator.isValidScriptletName(parsedRule.name);
          });
          return isValid;
        };
        var getMarkerData = function getMarkerData(modifiers, redirectsData, rule) {
          var marker;
          var index = modifiers.findIndex(function (m) {
            return m.indexOf(redirectsData.redirectRuleMarker) > -1;
          });
          if (index > -1) {
            marker = redirectsData.redirectRuleMarker;
          } else {
            index = modifiers.findIndex(function (m) {
              return m.indexOf(redirectsData.redirectMarker) > -1;
            });
            if (index > -1) {
              marker = redirectsData.redirectMarker;
            } else {
              throw new Error("No redirect resource modifier found in rule: ".concat(rule));
            }
          }
          return {
            index: index,
            marker: marker
          };
        };
        var convertUboRedirectToAdg = function convertUboRedirectToAdg(rule) {
          var firstPartOfRule = substringBefore(rule, '$');
          var uboModifiers = validator.parseModifiers(rule);
          var uboMarkerData = getMarkerData(uboModifiers, validator.REDIRECT_RULE_TYPES.UBO, rule);
          var adgModifiers = uboModifiers.map(function (modifier, index) {
            if (index === uboMarkerData.index) {
              var uboName = substringAfter(modifier, uboMarkerData.marker);
              var adgName = validator.REDIRECT_RULE_TYPES.UBO.compatibility[uboName];
              var adgMarker = uboMarkerData.marker === validator.ADG_UBO_REDIRECT_RULE_MARKER ? validator.REDIRECT_RULE_TYPES.ADG.redirectRuleMarker : validator.REDIRECT_RULE_TYPES.ADG.redirectMarker;
              return "".concat(adgMarker).concat(adgName);
            }
            if (modifier === UBO_XHR_TYPE) {
              return ADG_XHR_TYPE;
            }
            return modifier;
          }).join(COMMA_SEPARATOR);
          return "".concat(firstPartOfRule, "$").concat(adgModifiers);
        };
        var convertAbpRedirectToAdg = function convertAbpRedirectToAdg(rule) {
          var firstPartOfRule = substringBefore(rule, '$');
          var abpModifiers = validator.parseModifiers(rule);
          var adgModifiers = abpModifiers.map(function (modifier) {
            if (modifier.indexOf(validator.REDIRECT_RULE_TYPES.ABP.redirectMarker) > -1) {
              var abpName = substringAfter(modifier, validator.REDIRECT_RULE_TYPES.ABP.redirectMarker);
              var adgName = validator.REDIRECT_RULE_TYPES.ABP.compatibility[abpName];
              return "".concat(validator.REDIRECT_RULE_TYPES.ADG.redirectMarker).concat(adgName);
            }
            return modifier;
          }).join(COMMA_SEPARATOR);
          return "".concat(firstPartOfRule, "$").concat(adgModifiers);
        };
        var convertRedirectToAdg = function convertRedirectToAdg(rule) {
          var result;
          if (validator.isUboRedirectCompatibleWithAdg(rule)) {
            result = convertUboRedirectToAdg(rule);
          } else if (validator.isAbpRedirectCompatibleWithAdg(rule)) {
            result = convertAbpRedirectToAdg(rule);
          } else if (validator.isValidAdgRedirectRule(rule)) {
            result = rule;
          }
          return result;
        };
        var convertAdgRedirectToUbo = function convertAdgRedirectToUbo(rule) {
          if (!validator.isAdgRedirectCompatibleWithUbo(rule)) {
            throw new Error("Unable to convert for uBO - unsupported redirect in rule: ".concat(rule));
          }
          var basePart = substringBefore(rule, '$');
          var adgModifiers = validator.parseModifiers(rule);
          var adgMarkerData = getMarkerData(adgModifiers, validator.REDIRECT_RULE_TYPES.ADG, rule);
          var adgRedirectName = adgModifiers[adgMarkerData.index].slice(adgMarkerData.marker.length);
          if (!validator.hasValidContentType(rule)) {
            var sourceTypesData = validator.ABSENT_SOURCE_TYPE_REPLACEMENT.find(function (el) {
              return el.NAME === adgRedirectName;
            });
            if (typeof sourceTypesData === 'undefined') {
              throw new Error("Unable to convert for uBO - no types to add for specific redirect in rule: ".concat(rule));
            }
            var additionModifiers = sourceTypesData.TYPES;
            adgModifiers.push.apply(adgModifiers, toConsumableArray(additionModifiers));
          }
          var uboModifiers = adgModifiers.map(function (el, index) {
            if (index === adgMarkerData.index) {
              var uboMarker = adgMarkerData.marker === validator.ADG_UBO_REDIRECT_RULE_MARKER ? validator.REDIRECT_RULE_TYPES.UBO.redirectRuleMarker : validator.REDIRECT_RULE_TYPES.UBO.redirectMarker;
              var uboRedirectName = validator.REDIRECT_RULE_TYPES.ADG.compatibility[adgRedirectName];
              return "".concat(uboMarker).concat(uboRedirectName);
            }
            return el;
          }).join(COMMA_SEPARATOR);
          return "".concat(basePart, "$").concat(uboModifiers);
        };
        function GoogleAnalytics(source) {
          var Tracker = function Tracker() {};
          var proto = Tracker.prototype;
          proto.get = noopFunc;
          proto.set = noopFunc;
          proto.send = noopFunc;
          var googleAnalyticsName = window.GoogleAnalyticsObject || 'ga';
          function ga(a) {
            var len = arguments.length;
            if (len === 0) {
              return;
            }
            var lastArg = arguments[len - 1];
            var replacer;
            if (lastArg instanceof Object && lastArg !== null && typeof lastArg.hitCallback === 'function') {
              replacer = lastArg.hitCallback;
            } else if (typeof lastArg === 'function') {
              replacer = function replacer() {
                lastArg(ga.create());
              };
            }
            try {
              setTimeout(replacer, 1);
            } catch (ex) {}
          }
          ga.create = function () {
            return new Tracker();
          };
          ga.getByName = function () {
            return new Tracker();
          };
          ga.getAll = function () {
            return [new Tracker()];
          };
          ga.remove = noopFunc;
          ga.loaded = true;
          window[googleAnalyticsName] = ga;
          var _window = window,
              dataLayer = _window.dataLayer,
              google_optimize = _window.google_optimize;
          if (dataLayer instanceof Object === false) {
            return;
          }
          if (dataLayer.hide instanceof Object && typeof dataLayer.hide.end === 'function') {
            dataLayer.hide.end();
          }
          var handleCallback = function handleCallback(dataObj, funcName) {
            if (dataObj && typeof dataObj[funcName] === 'function') {
              setTimeout(dataObj[funcName]);
            }
          };
          if (typeof dataLayer.push === 'function') {
            dataLayer.push = function (data) {
              if (data instanceof Object) {
                handleCallback(data, 'eventCallback');
                for (var key in data) {
                  handleCallback(data[key], 'event_callback');
                }
                if (!data.hasOwnProperty('eventCallback') && !data.hasOwnProperty('eventCallback')) {
                  [].push.call(window.dataLayer, data);
                }
              }
              if (Array.isArray(data)) {
                data.forEach(function (arg) {
                  handleCallback(arg, 'callback');
                });
              }
              return noopFunc;
            };
          }
          if (google_optimize instanceof Object && typeof google_optimize.get === 'function') {
            var googleOptimizeWrapper = {
              get: noopFunc
            };
            window.google_optimize = googleOptimizeWrapper;
          }
          hit(source);
        }
        GoogleAnalytics.names = ['google-analytics', 'ubo-google-analytics_analytics.js', 'google-analytics_analytics.js',
        'googletagmanager-gtm', 'ubo-googletagmanager_gtm.js', 'googletagmanager_gtm.js'];
        GoogleAnalytics.injections = [hit, noopFunc, noopNull, noopArray];
        function GoogleAnalyticsGa(source) {
          function Gaq() {}
          Gaq.prototype.Na = noopFunc;
          Gaq.prototype.O = noopFunc;
          Gaq.prototype.Sa = noopFunc;
          Gaq.prototype.Ta = noopFunc;
          Gaq.prototype.Va = noopFunc;
          Gaq.prototype._createAsyncTracker = noopFunc;
          Gaq.prototype._getAsyncTracker = noopFunc;
          Gaq.prototype._getPlugin = noopFunc;
          Gaq.prototype.push = function (data) {
            if (typeof data === 'function') {
              data();
              return;
            }
            if (Array.isArray(data) === false) {
              return;
            }
            if (typeof data[0] === 'string' && /(^|\.)_link$/.test(data[0]) && typeof data[1] === 'string') {
              window.location.assign(data[1]);
            }
            if (data[0] === '_set' && data[1] === 'hitCallback' && typeof data[2] === 'function') {
              data[2]();
            }
          };
          var gaq = new Gaq();
          var asyncTrackers = window._gaq || [];
          if (Array.isArray(asyncTrackers)) {
            while (asyncTrackers[0]) {
              gaq.push(asyncTrackers.shift());
            }
          }
          window._gaq = gaq.qf = gaq;
          function Gat() {}
          var api = ['_addIgnoredOrganic', '_addIgnoredRef', '_addItem', '_addOrganic', '_addTrans', '_clearIgnoredOrganic', '_clearIgnoredRef', '_clearOrganic', '_cookiePathCopy', '_deleteCustomVar', '_getName', '_setAccount', '_getAccount', '_getClientInfo', '_getDetectFlash', '_getDetectTitle', '_getLinkerUrl', '_getLocalGifPath', '_getServiceMode', '_getVersion', '_getVisitorCustomVar', '_initData', '_link', '_linkByPost', '_setAllowAnchor', '_setAllowHash', '_setAllowLinker', '_setCampContentKey', '_setCampMediumKey', '_setCampNameKey', '_setCampNOKey', '_setCampSourceKey', '_setCampTermKey', '_setCampaignCookieTimeout', '_setCampaignTrack', '_setClientInfo', '_setCookiePath', '_setCookiePersistence', '_setCookieTimeout', '_setCustomVar', '_setDetectFlash', '_setDetectTitle', '_setDomainName', '_setLocalGifPath', '_setLocalRemoteServerMode', '_setLocalServerMode', '_setReferrerOverride', '_setRemoteServerMode', '_setSampleRate', '_setSessionTimeout', '_setSiteSpeedSampleRate', '_setSessionCookieTimeout', '_setVar', '_setVisitorCookieTimeout', '_trackEvent', '_trackPageLoadTime', '_trackPageview', '_trackSocial', '_trackTiming', '_trackTrans', '_visitCode'];
          var tracker = api.reduce(function (res, funcName) {
            res[funcName] = noopFunc;
            return res;
          }, {});
          tracker._getLinkerUrl = function (a) {
            return a;
          };
          tracker._link = function (url) {
            if (typeof url !== 'string') {
              return;
            }
            try {
              window.location.assign(url);
            } catch (e) {
              if (source.verbose) {
                console.log(e);
              }
            }
          };
          Gat.prototype._anonymizeIP = noopFunc;
          Gat.prototype._createTracker = noopFunc;
          Gat.prototype._forceSSL = noopFunc;
          Gat.prototype._getPlugin = noopFunc;
          Gat.prototype._getTracker = function () {
            return tracker;
          };
          Gat.prototype._getTrackerByName = function () {
            return tracker;
          };
          Gat.prototype._getTrackers = noopFunc;
          Gat.prototype.aa = noopFunc;
          Gat.prototype.ab = noopFunc;
          Gat.prototype.hb = noopFunc;
          Gat.prototype.la = noopFunc;
          Gat.prototype.oa = noopFunc;
          Gat.prototype.pa = noopFunc;
          Gat.prototype.u = noopFunc;
          var gat = new Gat();
          window._gat = gat;
          hit(source);
        }
        GoogleAnalyticsGa.names = ['google-analytics-ga', 'ubo-google-analytics_ga.js', 'google-analytics_ga.js'];
        GoogleAnalyticsGa.injections = [hit, noopFunc];
        function GoogleSyndicationAdsByGoogle(source) {
          window.adsbygoogle = {
            loaded: true,
            push: function push(arg) {
              if (typeof this.length === 'undefined') {
                this.length = 0;
                this.length += 1;
              }
              if (arg !== null && arg instanceof Object && arg.constructor.name === 'Object') {
                for (var _i = 0, _Object$keys = Object.keys(arg); _i < _Object$keys.length; _i++) {
                  var key = _Object$keys[_i];
                  if (typeof arg[key] === 'function') {
                    try {
                      arg[key].call();
                    } catch (_unused) {
                    }
                  }
                }
              }
            }
          };
          var adElems = document.querySelectorAll('.adsbygoogle');
          var css = 'height:1px!important;max-height:1px!important;max-width:1px!important;width:1px!important;';
          var statusAttrName = 'data-adsbygoogle-status';
          var ASWIFT_IFRAME_MARKER = 'aswift_';
          var GOOGLE_ADS_IFRAME_MARKER = 'google_ads_iframe_';
          var executed = false;
          for (var i = 0; i < adElems.length; i += 1) {
            var adElemChildNodes = adElems[i].childNodes;
            var childNodesQuantity = adElemChildNodes.length;
            var areIframesDefined = false;
            if (childNodesQuantity > 0) {
              areIframesDefined = childNodesQuantity === 2
              && adElemChildNodes[0].nodeName.toLowerCase() === 'iframe' && adElemChildNodes[0].id.indexOf(ASWIFT_IFRAME_MARKER) > -1
              && adElemChildNodes[1].nodeName.toLowerCase() === 'iframe' && adElemChildNodes[1].id.indexOf(GOOGLE_ADS_IFRAME_MARKER) > -1;
            }
            if (!areIframesDefined) {
              adElems[i].setAttribute(statusAttrName, 'done');
              var aswiftIframe = document.createElement('iframe');
              aswiftIframe.id = "".concat(ASWIFT_IFRAME_MARKER).concat(i);
              aswiftIframe.style = css;
              adElems[i].appendChild(aswiftIframe);
              var innerAswiftIframe = document.createElement('iframe');
              aswiftIframe.contentWindow.document.body.appendChild(innerAswiftIframe);
              var googleadsIframe = document.createElement('iframe');
              googleadsIframe.id = "".concat(GOOGLE_ADS_IFRAME_MARKER).concat(i);
              googleadsIframe.style = css;
              adElems[i].appendChild(googleadsIframe);
              var innerGoogleadsIframe = document.createElement('iframe');
              googleadsIframe.contentWindow.document.body.appendChild(innerGoogleadsIframe);
              executed = true;
            }
          }
          if (executed) {
            hit(source);
          }
        }
        GoogleSyndicationAdsByGoogle.names = ['googlesyndication-adsbygoogle', 'ubo-googlesyndication_adsbygoogle.js', 'googlesyndication_adsbygoogle.js'];
        GoogleSyndicationAdsByGoogle.injections = [hit];
        function GoogleTagServicesGpt(source) {
          var companionAdsService = {
            addEventListener: noopThis,
            removeEventListener: noopThis,
            enableSyncLoading: noopFunc,
            setRefreshUnfilledSlots: noopFunc,
            getSlots: noopArray
          };
          var contentService = {
            addEventListener: noopThis,
            setContent: noopFunc
          };
          function PassbackSlot() {}
          PassbackSlot.prototype.display = noopFunc;
          PassbackSlot.prototype.get = noopNull;
          PassbackSlot.prototype.set = noopThis;
          PassbackSlot.prototype.setClickUrl = noopThis;
          PassbackSlot.prototype.setTagForChildDirectedTreatment = noopThis;
          PassbackSlot.prototype.setTargeting = noopThis;
          PassbackSlot.prototype.updateTargetingFromMap = noopThis;
          function SizeMappingBuilder() {}
          SizeMappingBuilder.prototype.addSize = noopThis;
          SizeMappingBuilder.prototype.build = noopNull;
          function Slot() {}
          Slot.prototype.addService = noopThis;
          Slot.prototype.clearCategoryExclusions = noopThis;
          Slot.prototype.clearTargeting = noopThis;
          Slot.prototype.defineSizeMapping = noopThis;
          Slot.prototype.get = noopNull;
          Slot.prototype.getAdUnitPath = noopStr;
          Slot.prototype.getAttributeKeys = noopArray;
          Slot.prototype.getCategoryExclusions = noopArray;
          Slot.prototype.getDomId = noopStr;
          Slot.prototype.getSlotElementId = noopStr;
          Slot.prototype.getSlotId = noopThis;
          Slot.prototype.getTargeting = noopArray;
          Slot.prototype.getTargetingKeys = noopArray;
          Slot.prototype.set = noopThis;
          Slot.prototype.setCategoryExclusion = noopThis;
          Slot.prototype.setClickUrl = noopThis;
          Slot.prototype.setCollapseEmptyDiv = noopThis;
          Slot.prototype.setTargeting = noopThis;
          var pubAdsService = {
            addEventListener: noopThis,
            removeEventListener: noopThis,
            clear: noopFunc,
            clearCategoryExclusions: noopThis,
            clearTagForChildDirectedTreatment: noopThis,
            clearTargeting: noopThis,
            collapseEmptyDivs: noopFunc,
            defineOutOfPagePassback: function defineOutOfPagePassback() {
              return new PassbackSlot();
            },
            definePassback: function definePassback() {
              return new PassbackSlot();
            },
            disableInitialLoad: noopFunc,
            display: noopFunc,
            enableAsyncRendering: noopFunc,
            enableLazyLoad: noopFunc,
            enableSingleRequest: noopFunc,
            enableSyncRendering: noopFunc,
            enableVideoAds: noopFunc,
            get: noopNull,
            getAttributeKeys: noopArray,
            getTargeting: noopArray,
            getTargetingKeys: noopArray,
            getSlots: noopArray,
            refresh: noopFunc,
            set: noopThis,
            setCategoryExclusion: noopThis,
            setCentering: noopFunc,
            setCookieOptions: noopThis,
            setForceSafeFrame: noopThis,
            setLocation: noopThis,
            setPublisherProvidedId: noopThis,
            setRequestNonPersonalizedAds: noopThis,
            setSafeFrameConfig: noopThis,
            setTagForChildDirectedTreatment: noopThis,
            setTargeting: noopThis,
            setVideoContent: noopThis,
            updateCorrelator: noopFunc
          };
          var _window = window,
              _window$googletag = _window.googletag,
              googletag = _window$googletag === void 0 ? {} : _window$googletag;
          var _googletag$cmd = googletag.cmd,
              cmd = _googletag$cmd === void 0 ? [] : _googletag$cmd;
          googletag.apiReady = true;
          googletag.cmd = [];
          googletag.cmd.push = function (a) {
            try {
              a();
            } catch (ex) {}
            return 1;
          };
          googletag.companionAds = function () {
            return companionAdsService;
          };
          googletag.content = function () {
            return contentService;
          };
          googletag.defineOutOfPageSlot = function () {
            return new Slot();
          };
          googletag.defineSlot = function () {
            return new Slot();
          };
          googletag.destroySlots = noopFunc;
          googletag.disablePublisherConsole = noopFunc;
          googletag.display = noopFunc;
          googletag.enableServices = noopFunc;
          googletag.getVersion = noopStr;
          googletag.pubads = function () {
            return pubAdsService;
          };
          googletag.pubadsReady = true;
          googletag.setAdIframeTitle = noopFunc;
          googletag.sizeMapping = function () {
            return new SizeMappingBuilder();
          };
          window.googletag = googletag;
          while (cmd.length !== 0) {
            googletag.cmd.push(cmd.shift());
          }
          hit(source);
        }
        GoogleTagServicesGpt.names = ['googletagservices-gpt', 'ubo-googletagservices_gpt.js', 'googletagservices_gpt.js'];
        GoogleTagServicesGpt.injections = [hit, noopFunc, noopThis, noopNull, noopArray, noopStr];
        function ScoreCardResearchBeacon(source) {
          window.COMSCORE = {
            purge: function purge() {
              window._comscore = [];
            },
            beacon: function beacon() {}
          };
          hit(source);
        }
        ScoreCardResearchBeacon.names = ['scorecardresearch-beacon', 'ubo-scorecardresearch_beacon.js', 'scorecardresearch_beacon.js'];
        ScoreCardResearchBeacon.injections = [hit];
        function metrikaYandexTag(source) {
          var asyncCallbackFromOptions = function asyncCallbackFromOptions(id, param) {
            var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
            var callback = options.callback;
            var ctx = options.ctx;
            if (typeof callback === 'function') {
              callback = ctx !== undefined ? callback.bind(ctx) : callback;
              setTimeout(function () {
                return callback();
              });
            }
          };
          var addFileExtension = noopFunc;
          var extLink = asyncCallbackFromOptions;
          var file = asyncCallbackFromOptions;
          var getClientID = function getClientID(id, cb) {
            if (!cb) {
              return;
            }
            setTimeout(cb(null));
          };
          var hitFunc = asyncCallbackFromOptions;
          var notBounce = asyncCallbackFromOptions;
          var params = noopFunc;
          var reachGoal = function reachGoal(id, target, params, callback, ctx) {
            asyncCallbackFromOptions(null, null, {
              callback: callback,
              ctx: ctx
            });
          };
          var setUserID = noopFunc;
          var userParams = noopFunc;
          var destruct = noopFunc;
          var api = {
            addFileExtension: addFileExtension,
            extLink: extLink,
            file: file,
            getClientID: getClientID,
            hit: hitFunc,
            notBounce: notBounce,
            params: params,
            reachGoal: reachGoal,
            setUserID: setUserID,
            userParams: userParams,
            destruct: destruct
          };
          function ym(id, funcName) {
            for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
              args[_key - 2] = arguments[_key];
            }
            return api[funcName] && api[funcName].apply(api, [id].concat(args));
          }
          ym.a = [];
          function init(id) {
            window["yaCounter".concat(id)] = api;
            document.dispatchEvent(new Event("yacounter".concat(id, "inited")));
          }
          if (typeof window.ym === 'undefined') {
            window.ym = ym;
          } else if (window.ym && window.ym.a) {
            var counters = window.ym.a;
            window.ym = ym;
            counters.forEach(function (params) {
              var id = params[0];
              init(id);
            });
          }
          hit(source);
        }
        metrikaYandexTag.names = ['metrika-yandex-tag'];
        metrikaYandexTag.injections = [hit, noopFunc];
        function metrikaYandexWatch(source) {
          var cbName = 'yandex_metrika_callbacks';
          var asyncCallbackFromOptions = function asyncCallbackFromOptions() {
            var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
            var callback = options.callback;
            var ctx = options.ctx;
            if (typeof callback === 'function') {
              callback = ctx !== undefined ? callback.bind(ctx) : callback;
              setTimeout(function () {
                return callback();
              });
            }
          };
          function Metrika() {}
          Metrika.prototype.addFileExtension = noopFunc;
          Metrika.prototype.getClientID = noopFunc;
          Metrika.prototype.setUserID = noopFunc;
          Metrika.prototype.userParams = noopFunc;
          Metrika.prototype.params = noopFunc;
          Metrika.prototype.extLink = function (url, options) {
            asyncCallbackFromOptions(options);
          };
          Metrika.prototype.file = function (url, options) {
            asyncCallbackFromOptions(options);
          };
          Metrika.prototype.hit = function (url, options) {
            asyncCallbackFromOptions(options);
          };
          Metrika.prototype.reachGoal = function (target, params, cb, ctx) {
            asyncCallbackFromOptions({
              callback: cb,
              ctx: ctx
            });
          };
          Metrika.prototype.notBounce = asyncCallbackFromOptions;
          if (window.Ya) {
            window.Ya.Metrika = Metrika;
          } else {
            window.Ya = {
              Metrika: Metrika
            };
          }
          if (window[cbName] && Array.isArray(window[cbName])) {
            window[cbName].forEach(function (func) {
              if (typeof func === 'function') {
                func();
              }
            });
          }
          hit(source);
        }
        metrikaYandexWatch.names = ['metrika-yandex-watch'];
        metrikaYandexWatch.injections = [hit, noopFunc];
        function AmazonApstag(source) {
          var apstagWrapper = {
            fetchBids: function fetchBids(a, b) {
              if (typeof b === 'function') {
                b([]);
              }
            },
            init: noopFunc,
            setDisplayBids: noopFunc,
            targetingKeys: noopFunc
          };
          window.apstag = apstagWrapper;
          hit(source);
        }
        AmazonApstag.names = ['amazon-apstag', 'ubo-amazon_apstag.js', 'amazon_apstag.js'];
        AmazonApstag.injections = [hit, noopFunc];
        function Matomo(source) {
          var Tracker = function Tracker() {};
          Tracker.prototype.setDoNotTrack = noopFunc;
          Tracker.prototype.setDomains = noopFunc;
          Tracker.prototype.setCustomDimension = noopFunc;
          Tracker.prototype.trackPageView = noopFunc;
          var AsyncTracker = function AsyncTracker() {};
          AsyncTracker.prototype.addListener = noopFunc;
          var matomoWrapper = {
            getTracker: function getTracker() {
              return new Tracker();
            },
            getAsyncTracker: function getAsyncTracker() {
              return new AsyncTracker();
            }
          };
          window.Piwik = matomoWrapper;
          hit(source);
        }
        Matomo.names = ['matomo'];
        Matomo.injections = [hit, noopFunc];
        function Fingerprintjs2(source) {
          var browserId = '';
          for (var i = 0; i < 8; i += 1) {
            browserId += (Math.random() * 0x10000 + 0x1000).toString(16).slice(-4);
          }
          var Fingerprint2 = function Fingerprint2() {};
          Fingerprint2.get = function (options, callback) {
            if (!callback) {
              callback = options;
            }
            setTimeout(function () {
              if (callback) {
                callback(browserId, []);
              }
            }, 1);
          };
          Fingerprint2.prototype = {
            get: Fingerprint2.get
          };
          window.Fingerprint2 = Fingerprint2;
          hit(source);
        }
        Fingerprintjs2.names = ['fingerprintjs2',
        'ubo-fingerprint2.js',
        'fingerprint2.js'];
        Fingerprintjs2.injections = [hit];
        function Fingerprintjs3(source) {
          var visitorId = function () {
            var id = '';
            for (var i = 0; i < 8; i += 1) {
              id += (Math.random() * 0x10000 + 0x1000).toString(16).slice(-4);
            }
            return id;
          }();
          var FingerprintJS = function FingerprintJS() {};
          FingerprintJS.prototype = {
            load: function load() {
              return Promise.resolve(new FingerprintJS());
            },
            get: function get() {
              return Promise.resolve({
                visitorId: visitorId
              });
            },
            hashComponents: noopStr
          };
          window.FingerprintJS = new FingerprintJS();
          hit(source);
        }
        Fingerprintjs3.names = ['fingerprintjs3',
        'ubo-fingerprint3.js',
        'fingerprint3.js'];
        Fingerprintjs3.injections = [hit, noopStr];
        function Gemius(source) {
          var GemiusPlayer = function GemiusPlayer() {};
          GemiusPlayer.prototype = {
            setVideoObject: noopFunc,
            newProgram: noopFunc,
            programEvent: noopFunc,
            newAd: noopFunc,
            adEvent: noopFunc
          };
          window.GemiusPlayer = GemiusPlayer;
          hit(source);
        }
        Gemius.names = ['gemius'];
        Gemius.injections = [hit, noopFunc];
        function ATInternetSmartTag(source) {
          var setNoopFuncWrapper = {
            set: noopFunc
          };
          var sendNoopFuncWrapper = {
            send: noopFunc
          };
          var ecommerceWrapper = {
            displayCart: {
              products: setNoopFuncWrapper,
              cart: setNoopFuncWrapper
            },
            updateCart: {
              cart: setNoopFuncWrapper
            },
            displayProduct: {
              products: setNoopFuncWrapper
            },
            displayPageProduct: {
              products: setNoopFuncWrapper
            },
            addProduct: {
              products: setNoopFuncWrapper
            },
            removeProduct: {
              products: setNoopFuncWrapper
            }
          };
          var tag = function tag() {};
          tag.prototype = {
            setConfig: noopFunc,
            setParam: noopFunc,
            dispatch: noopFunc,
            customVars: setNoopFuncWrapper,
            publisher: setNoopFuncWrapper,
            order: setNoopFuncWrapper,
            click: sendNoopFuncWrapper,
            clickListener: sendNoopFuncWrapper,
            internalSearch: {
              set: noopFunc,
              send: noopFunc
            },
            ecommerce: ecommerceWrapper,
            identifiedVisitor: {
              unset: noopFunc
            },
            page: {
              set: noopFunc,
              send: noopFunc
            },
            selfPromotion: {
              add: noopFunc,
              send: noopFunc
            },
            privacy: {
              setVisitorMode: noopFunc,
              getVisitorMode: noopFunc,
              hit: noopFunc
            },
            richMedia: {
              add: noopFunc,
              send: noopFunc,
              remove: noopFunc,
              removeAll: noopFunc
            }
          };
          var smartTagWrapper = {
            Tracker: {
              Tag: function Tag() {
                return new tag();
              }
            }
          };
          window.ATInternet = smartTagWrapper;
          hit(source);
        }
        ATInternetSmartTag.names = ['ati-smarttag'];
        ATInternetSmartTag.injections = [hit, noopFunc];
        function preventBab2(source) {
          var script = document.currentScript;
          if (script === null) {
            return;
          }
          var url = script.src;
          if (typeof url !== 'string') {
            return;
          }
          var domainsStr = ['adclixx\\.net', 'adnetasia\\.com', 'adtrackers\\.net', 'bannertrack\\.net'].join('|');
          var matchStr = "^https?://[\\w-]+\\.(".concat(domainsStr, ")/.");
          var domainsRegex = new RegExp(matchStr);
          if (domainsRegex.test(url) === false) {
            return;
          }
          window.nH7eXzOsG = 858;
          hit(source);
        }
        preventBab2.names = ['prevent-bab2',
        'nobab2.js'];
        preventBab2.injections = [hit];
        function GoogleIma3(source) {
          var _this = this;
          var VERSION = '3.453.0';
          var ima = {};
          var AdDisplayContainer = function AdDisplayContainer() {};
          AdDisplayContainer.prototype.destroy = noopFunc;
          AdDisplayContainer.prototype.initialize = noopFunc;
          var ImaSdkSettings = function ImaSdkSettings() {};
          ImaSdkSettings.CompanionBackfillMode = {
            ALWAYS: 'always',
            ON_MASTER_AD: 'on_master_ad'
          };
          ImaSdkSettings.VpaidMode = {
            DISABLED: 0,
            ENABLED: 1,
            INSECURE: 2
          };
          ImaSdkSettings.prototype = {
            c: true,
            f: {},
            i: false,
            l: '',
            p: '',
            r: 0,
            t: '',
            v: '',
            getCompanionBackfill: noopFunc,
            getDisableCustomPlaybackForIOS10Plus: function getDisableCustomPlaybackForIOS10Plus() {
              return _this.i;
            },
            getDisabledFlashAds: function getDisabledFlashAds() {
              return true;
            },
            getFeatureFlags: function getFeatureFlags() {
              return _this.f;
            },
            getLocale: function getLocale() {
              return _this.l;
            },
            getNumRedirects: function getNumRedirects() {
              return _this.r;
            },
            getPlayerType: function getPlayerType() {
              return _this.t;
            },
            getPlayerVersion: function getPlayerVersion() {
              return _this.v;
            },
            getPpid: function getPpid() {
              return _this.p;
            },
            getVpaidMode: function getVpaidMode() {
              return _this.C;
            },
            isCookiesEnabled: function isCookiesEnabled() {
              return _this.c;
            },
            isVpaidAdapter: function isVpaidAdapter() {
              return _this.M;
            },
            setCompanionBackfill: noopFunc,
            setAutoPlayAdBreaks: function setAutoPlayAdBreaks(a) {
              _this.K = a;
            },
            setCookiesEnabled: function setCookiesEnabled(c) {
              _this.c = !!c;
            },
            setDisableCustomPlaybackForIOS10Plus: function setDisableCustomPlaybackForIOS10Plus(i) {
              _this.i = !!i;
            },
            setDisableFlashAds: noopFunc,
            setFeatureFlags: function setFeatureFlags(f) {
              _this.f = !!f;
            },
            setIsVpaidAdapter: function setIsVpaidAdapter(a) {
              _this.M = a;
            },
            setLocale: function setLocale(l) {
              _this.l = !!l;
            },
            setNumRedirects: function setNumRedirects(r) {
              _this.r = !!r;
            },
            setPageCorrelator: function setPageCorrelator(a) {
              _this.R = a;
            },
            setPlayerType: function setPlayerType(t) {
              _this.t = !!t;
            },
            setPlayerVersion: function setPlayerVersion(v) {
              _this.v = !!v;
            },
            setPpid: function setPpid(p) {
              _this.p = !!p;
            },
            setVpaidMode: function setVpaidMode(a) {
              _this.C = a;
            },
            setSessionId: noopFunc,
            setStreamCorrelator: noopFunc,
            setVpaidAllowed: noopFunc,
            CompanionBackfillMode: {
              ALWAYS: 'always',
              ON_MASTER_AD: 'on_master_ad'
            },
            VpaidMode: {
              DISABLED: 0,
              ENABLED: 1,
              INSECURE: 2
            }
          };
          var managerLoaded = false;
          var EventHandler = function EventHandler() {};
          EventHandler.prototype = {
            listeners: new Map(),
            _dispatch: function _dispatch(e) {
              var listeners = this.listeners.get(e.type) || [];
              for (var _i = 0, _Array$from = Array.from(listeners); _i < _Array$from.length; _i++) {
                var listener = _Array$from[_i];
                try {
                  listener(e);
                } catch (r) {
                  console.error(r);
                }
              }
            },
            addEventListener: function addEventListener(t, c) {
              if (!this.listeners.has(t)) {
                this.listeners.set(t, new Set());
              }
              this.listeners.get(t).add(c);
            },
            removeEventListener: function removeEventListener(t, c) {
              var _this$listeners$get;
              (_this$listeners$get = this.listeners.get(t)) === null || _this$listeners$get === void 0 ? void 0 : _this$listeners$get.delete(c);
            }
          };
          var AdsManager = EventHandler;
          AdsManager.prototype.volume = 1;
          AdsManager.prototype.collapse = noopFunc;
          AdsManager.prototype.configureAdsManager = noopFunc;
          AdsManager.prototype.destroy = noopFunc;
          AdsManager.prototype.discardAdBreak = noopFunc;
          AdsManager.prototype.expand = noopFunc;
          AdsManager.prototype.focus = noopFunc;
          AdsManager.prototype.getAdSkippableState = function () {
            return false;
          };
          AdsManager.prototype.getCuePoints = function () {
            return [0];
          };
          AdsManager.prototype.getCurrentAd = function () {
            return currentAd;
          };
          AdsManager.prototype.getCurrentAdCuePoints = function () {
            return [];
          };
          AdsManager.prototype.getRemainingTime = function () {
            return 0;
          };
          AdsManager.prototype.getVolume = function () {
            return _this.volume;
          };
          AdsManager.prototype.init = noopFunc;
          AdsManager.prototype.isCustomClickTrackingUsed = function () {
            return false;
          };
          AdsManager.prototype.isCustomPlaybackUsed = function () {
            return false;
          };
          AdsManager.prototype.pause = noopFunc;
          AdsManager.prototype.requestNextAdBreak = noopFunc;
          AdsManager.prototype.resize = noopFunc;
          AdsManager.prototype.resume = noopFunc;
          AdsManager.prototype.setVolume = function (v) {
            _this.volume = v;
          };
          AdsManager.prototype.skip = noopFunc;
          AdsManager.prototype.start = function () {
            for (var _i2 = 0, _arr = [AdEvent.Type.LOADED, AdEvent.Type.STARTED, AdEvent.Type.AD_BUFFERING, AdEvent.Type.FIRST_QUARTILE, AdEvent.Type.MIDPOINT, AdEvent.Type.THIRD_QUARTILE, AdEvent.Type.COMPLETE, AdEvent.Type.ALL_ADS_COMPLETED]; _i2 < _arr.length; _i2++) {
              var type = _arr[_i2];
              try {
                _this._dispatch(new ima.AdEvent(type));
              } catch (e) {
                console.error(e);
              }
            }
          };
          AdsManager.prototype.stop = noopFunc;
          AdsManager.prototype.updateAdsRenderingSettings = noopFunc;
          var manager = Object.create(AdsManager);
          var AdsManagerLoadedEvent = function AdsManagerLoadedEvent() {};
          AdsManagerLoadedEvent.prototype = {
            constructor: function constructor(type) {
              _this.type = type;
            },
            getAdsManager: function getAdsManager() {
              return manager;
            },
            getUserRequestContext: noopFunc
          };
          AdsManagerLoadedEvent.Type = {
            ADS_MANAGER_LOADED: 'adsManagerLoaded'
          };
          var AdsLoader = EventHandler;
          AdsLoader.prototype.settings = new ImaSdkSettings();
          AdsLoader.prototype.contentComplete = noopFunc;
          AdsLoader.prototype.destroy = noopFunc;
          AdsLoader.prototype.getSettings = function () {
            return this.settings;
          };
          AdsLoader.prototype.getVersion = function () {
            return VERSION;
          };
          AdsLoader.prototype.requestAds = function () {
            var _this2 = this;
            if (!managerLoaded) {
              managerLoaded = true;
              requestAnimationFrame(function () {
                var ADS_MANAGER_LOADED = AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED;
                _this2._dispatch(new ima.AdsManagerLoadedEvent(ADS_MANAGER_LOADED));
              });
            }
          };
          var AdsRenderingSettings = noopFunc;
          var AdsRequest = function AdsRequest() {};
          AdsRequest.prototype = {
            setAdWillAutoPlay: noopFunc,
            setAdWillPlayMuted: noopFunc,
            setContinuousPlayback: noopFunc
          };
          var AdPodInfo = function AdPodInfo() {};
          AdPodInfo.prototype = {
            getAdPosition: function getAdPosition() {
              return 1;
            },
            getIsBumper: function getIsBumper() {
              return false;
            },
            getMaxDuration: function getMaxDuration() {
              return -1;
            },
            getPodIndex: function getPodIndex() {
              return 1;
            },
            getTimeOffset: function getTimeOffset() {
              return 0;
            },
            getTotalAds: function getTotalAds() {
              return 1;
            }
          };
          var Ad = function Ad() {};
          Ad.prototype = {
            pi: new AdPodInfo(),
            getAdId: function getAdId() {
              return '';
            },
            getAdPodInfo: function getAdPodInfo() {
              return _this.pi;
            },
            getAdSystem: function getAdSystem() {
              return '';
            },
            getAdvertiserName: function getAdvertiserName() {
              return '';
            },
            getApiFramework: function getApiFramework() {
              return null;
            },
            getCompanionAds: function getCompanionAds() {
              return [];
            },
            getContentType: function getContentType() {
              return '';
            },
            getCreativeAdId: function getCreativeAdId() {
              return '';
            },
            getDealId: function getDealId() {
              return '';
            },
            getDescription: function getDescription() {
              return '';
            },
            getDuration: function getDuration() {
              return 8.5;
            },
            getHeight: function getHeight() {
              return 0;
            },
            getMediaUrl: function getMediaUrl() {
              return null;
            },
            getMinSuggestedDuration: function getMinSuggestedDuration() {
              return -2;
            },
            getSkipTimeOffset: function getSkipTimeOffset() {
              return -1;
            },
            getSurveyUrl: function getSurveyUrl() {
              return null;
            },
            getTitle: function getTitle() {
              return '';
            },
            getTraffickingParametersString: function getTraffickingParametersString() {
              return '';
            },
            getUiElements: function getUiElements() {
              return [''];
            },
            getUniversalAdIdRegistry: function getUniversalAdIdRegistry() {
              return 'unknown';
            },
            getUniversalAdIds: function getUniversalAdIds() {
              return [''];
            },
            getUniversalAdIdValue: function getUniversalAdIdValue() {
              return 'unknown';
            },
            getVastMediaBitrate: function getVastMediaBitrate() {
              return 0;
            },
            getVastMediaHeight: function getVastMediaHeight() {
              return 0;
            },
            getVastMediaWidth: function getVastMediaWidth() {
              return 0;
            },
            getWidth: function getWidth() {
              return 0;
            },
            getWrapperAdIds: function getWrapperAdIds() {
              return [''];
            },
            getWrapperAdSystems: function getWrapperAdSystems() {
              return [''];
            },
            getWrapperCreativeIds: function getWrapperCreativeIds() {
              return [''];
            },
            isLinear: function isLinear() {
              return true;
            }
          };
          var CompanionAd = function CompanionAd() {};
          CompanionAd.prototype = {
            getAdSlotId: function getAdSlotId() {
              return '';
            },
            getContent: function getContent() {
              return '';
            },
            getContentType: function getContentType() {
              return '';
            },
            getHeight: function getHeight() {
              return 1;
            },
            getWidth: function getWidth() {
              return 1;
            }
          };
          var AdError = function AdError() {};
          AdError.prototype = {
            getErrorCode: function getErrorCode() {
              return 0;
            },
            getInnerError: noopFunc,
            getMessage: function getMessage() {
              return '';
            },
            getType: function getType() {
              return 1;
            },
            getVastErrorCode: function getVastErrorCode() {
              return 0;
            },
            toString: function toString() {
              return '';
            }
          };
          AdError.ErrorCode = {};
          AdError.Type = {};
          var isEngadget = function isEngadget() {
            try {
              for (var _i3 = 0, _Object$values = Object.values(window.vidible._getContexts()); _i3 < _Object$values.length; _i3++) {
                var _ctx$getPlayer, _ctx$getPlayer$div;
                var ctx = _Object$values[_i3];
                if ((_ctx$getPlayer = ctx.getPlayer()) !== null && _ctx$getPlayer !== void 0 && (_ctx$getPlayer$div = _ctx$getPlayer.div) !== null && _ctx$getPlayer$div !== void 0 && _ctx$getPlayer$div.innerHTML.includes('www.engadget.com')) {
                  return true;
                }
              }
            } catch (e) {}
            return false;
          };
          var currentAd = isEngadget() ? undefined : new Ad();
          var AdEvent = function AdEvent() {};
          AdEvent.prototype = {
            constructor: function constructor(type) {
              _this.type = type;
            },
            getAd: function getAd() {
              return currentAd;
            },
            getAdData: function getAdData() {}
          };
          AdEvent.Type = {
            AD_BREAK_READY: 'adBreakReady',
            AD_BUFFERING: 'adBuffering',
            AD_CAN_PLAY: 'adCanPlay',
            AD_METADATA: 'adMetadata',
            AD_PROGRESS: 'adProgress',
            ALL_ADS_COMPLETED: 'allAdsCompleted',
            CLICK: 'click',
            COMPLETE: 'complete',
            CONTENT_PAUSE_REQUESTED: 'contentPauseRequested',
            CONTENT_RESUME_REQUESTED: 'contentResumeRequested',
            DURATION_CHANGE: 'durationChange',
            EXPANDED_CHANGED: 'expandedChanged',
            FIRST_QUARTILE: 'firstQuartile',
            IMPRESSION: 'impression',
            INTERACTION: 'interaction',
            LINEAR_CHANGE: 'linearChange',
            LINEAR_CHANGED: 'linearChanged',
            LOADED: 'loaded',
            LOG: 'log',
            MIDPOINT: 'midpoint',
            PAUSED: 'pause',
            RESUMED: 'resume',
            SKIPPABLE_STATE_CHANGED: 'skippableStateChanged',
            SKIPPED: 'skip',
            STARTED: 'start',
            THIRD_QUARTILE: 'thirdQuartile',
            USER_CLOSE: 'userClose',
            VIDEO_CLICKED: 'videoClicked',
            VIDEO_ICON_CLICKED: 'videoIconClicked',
            VIEWABLE_IMPRESSION: 'viewable_impression',
            VOLUME_CHANGED: 'volumeChange',
            VOLUME_MUTED: 'mute'
          };
          var AdErrorEvent = function AdErrorEvent() {};
          AdErrorEvent.prototype = {
            getError: noopFunc,
            getUserRequestContext: function getUserRequestContext() {}
          };
          AdErrorEvent.Type = {
            AD_ERROR: 'adError'
          };
          var CustomContentLoadedEvent = function CustomContentLoadedEvent() {};
          CustomContentLoadedEvent.Type = {
            CUSTOM_CONTENT_LOADED: 'deprecated-event'
          };
          var CompanionAdSelectionSettings = function CompanionAdSelectionSettings() {};
          CompanionAdSelectionSettings.CreativeType = {
            ALL: 'All',
            FLASH: 'Flash',
            IMAGE: 'Image'
          };
          CompanionAdSelectionSettings.ResourceType = {
            ALL: 'All',
            HTML: 'Html',
            IFRAME: 'IFrame',
            STATIC: 'Static'
          };
          CompanionAdSelectionSettings.SizeCriteria = {
            IGNORE: 'IgnoreSize',
            SELECT_EXACT_MATCH: 'SelectExactMatch',
            SELECT_NEAR_MATCH: 'SelectNearMatch'
          };
          var AdCuePoints = function AdCuePoints() {};
          AdCuePoints.prototype = {
            getCuePoints: function getCuePoints() {
              return [];
            },
            getAdIdRegistry: function getAdIdRegistry() {
              return '';
            },
            getAdIsValue: function getAdIsValue() {
              return '';
            }
          };
          var AdProgressData = noopFunc;
          var UniversalAdIdInfo = function UniversalAdIdInfo() {};
          Object.assign(ima, {
            AdCuePoints: AdCuePoints,
            AdDisplayContainer: AdDisplayContainer,
            AdError: AdError,
            AdErrorEvent: AdErrorEvent,
            AdEvent: AdEvent,
            AdPodInfo: AdPodInfo,
            AdProgressData: AdProgressData,
            AdsLoader: AdsLoader,
            AdsManager: manager,
            AdsManagerLoadedEvent: AdsManagerLoadedEvent,
            AdsRenderingSettings: AdsRenderingSettings,
            AdsRequest: AdsRequest,
            CompanionAd: CompanionAd,
            CompanionAdSelectionSettings: CompanionAdSelectionSettings,
            CustomContentLoadedEvent: CustomContentLoadedEvent,
            gptProxyInstance: {},
            ImaSdkSettings: ImaSdkSettings,
            OmidAccessMode: {
              DOMAIN: 'domain',
              FULL: 'full',
              LIMITED: 'limited'
            },
            settings: new ImaSdkSettings(),
            UiElements: {
              AD_ATTRIBUTION: 'adAttribution',
              COUNTDOWN: 'countdown'
            },
            UniversalAdIdInfo: UniversalAdIdInfo,
            VERSION: VERSION,
            ViewMode: {
              FULLSCREEN: 'fullscreen',
              NORMAL: 'normal'
            }
          });
          if (!window.google) {
            window.google = {};
          }
          window.google.ima = ima;
          hit(source);
        }
        GoogleIma3.names = ['google-ima3'];
        GoogleIma3.injections = [hit, noopFunc];
        function DidomiLoader(source) {
          function UserConsentStatusForVendorSubscribe() {}
          UserConsentStatusForVendorSubscribe.prototype.filter = function () {
            return new UserConsentStatusForVendorSubscribe();
          };
          UserConsentStatusForVendorSubscribe.prototype.subscribe = noopFunc;
          function UserConsentStatusForVendor() {}
          UserConsentStatusForVendor.prototype.first = function () {
            return new UserConsentStatusForVendorSubscribe();
          };
          UserConsentStatusForVendor.prototype.filter = function () {
            return new UserConsentStatusForVendorSubscribe();
          };
          UserConsentStatusForVendor.prototype.subscribe = noopFunc;
          var DidomiWrapper = {
            isConsentRequired: falseFunc,
            getUserConsentStatusForPurpose: trueFunc,
            getUserConsentStatus: trueFunc,
            getUserStatus: noopFunc,
            getRequiredPurposes: noopArray,
            getUserConsentStatusForVendor: trueFunc,
            Purposes: {
              Cookies: 'cookies'
            },
            notice: {
              configure: noopFunc,
              hide: noopFunc,
              isVisible: falseFunc,
              show: noopFunc,
              showDataProcessing: trueFunc
            },
            isUserConsentStatusPartial: falseFunc,
            on: function on() {
              return {
                actions: {},
                emitter: {},
                services: {},
                store: {}
              };
            },
            shouldConsentBeCollected: falseFunc,
            getUserConsentStatusForAll: noopFunc,
            getObservableOnUserConsentStatusForVendor: function getObservableOnUserConsentStatusForVendor() {
              return new UserConsentStatusForVendor();
            }
          };
          window.Didomi = DidomiWrapper;
          var didomiStateWrapper = {
            didomiExperimentId: '',
            didomiExperimentUserGroup: '',
            didomiGDPRApplies: 1,
            didomiIABConsent: '',
            didomiPurposesConsent: '',
            didomiPurposesConsentDenied: '',
            didomiPurposesConsentUnknown: '',
            didomiVendorsConsent: '',
            didomiVendorsConsentDenied: '',
            didomiVendorsConsentUnknown: '',
            didomiVendorsRawConsent: '',
            didomiVendorsRawConsentDenied: '',
            didomiVendorsRawConsentUnknown: ''
          };
          window.didomiState = didomiStateWrapper;
          var tcData = {
            eventStatus: 'tcloaded',
            gdprApplies: false,
            listenerId: noopFunc,
            vendor: {
              consents: []
            },
            purpose: {
              consents: []
            }
          };
          var __tcfapiWrapper = function __tcfapiWrapper() {
            for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
              args[_key] = arguments[_key];
            }
            for (var _i = 0, _args = args; _i < _args.length; _i++) {
              var arg = _args[_i];
              if (typeof arg === 'function') {
                try {
                  setTimeout(arg(tcData, true));
                } catch (ex) {
                }
              }
            }
          };
          window.__tcfapi = __tcfapiWrapper;
          var didomiEventListenersWrapper = {
            stub: true,
            push: noopFunc
          };
          window.didomiEventListeners = didomiEventListenersWrapper;
          var didomiOnReadyWrapper = {
            stub: true,
            push: function push(arg) {
              if (typeof arg !== 'function') {
                return;
              }
              if (document.readyState !== 'complete') {
                window.addEventListener('load', function () {
                  setTimeout(arg(window.Didomi));
                });
              } else {
                setTimeout(arg(window.Didomi));
              }
            }
          };
          window.didomiOnReady = window.didomiOnReady || didomiOnReadyWrapper;
          if (Array.isArray(window.didomiOnReady)) {
            window.didomiOnReady.forEach(function (arg) {
              if (typeof arg === 'function') {
                try {
                  setTimeout(arg(window.Didomi));
                } catch (e) {
                }
              }
            });
          }
          hit(source);
        }
        DidomiLoader.names = ['didomi-loader'];
        DidomiLoader.injections = [hit, noopFunc, noopArray, trueFunc, falseFunc];
        function Prebid(source) {
          var pushFunction = function pushFunction(arg) {
            if (typeof arg === 'function') {
              try {
                arg.call();
              } catch (ex) {
              }
            }
          };
          var pbjsWrapper = {
            addAdUnits: function addAdUnits() {},
            adServers: {
              dfp: {
                buildVideoUrl: noopStr
              }
            },
            adUnits: [],
            aliasBidder: function aliasBidder() {},
            cmd: [],
            enableAnalytics: function enableAnalytics() {},
            getHighestCpmBids: noopArray,
            libLoaded: true,
            que: [],
            requestBids: function requestBids(arg) {
              if (arg instanceof Object && arg.bidsBackHandler) {
                try {
                  arg.bidsBackHandler.call();
                } catch (ex) {
                }
              }
            },
            removeAdUnit: function removeAdUnit() {},
            setBidderConfig: function setBidderConfig() {},
            setConfig: function setConfig() {},
            setTargetingForGPTAsync: function setTargetingForGPTAsync() {}
          };
          pbjsWrapper.cmd.push = pushFunction;
          pbjsWrapper.que.push = pushFunction;
          window.pbjs = pbjsWrapper;
          hit(source);
        }
        Prebid.names = ['prebid'];
        Prebid.injections = [hit, noopFunc, noopStr, noopArray];
        function prebidAds(source) {
          window.canRunAds = true;
          window.isAdBlockActive = false;
          hit(source);
        }
        prebidAds.names = ['prebid-ads', 'ubo-prebid-ads.js', 'prebid-ads.js'];
        prebidAds.injections = [hit];
        function NaverWcslog(source) {
          window.wcs_add = {};
          window.wcs_do = noopFunc;
          window.wcs = {
            inflow: noopFunc
          };
          hit(source);
        }
        NaverWcslog.names = ['naver-wcslog'];
        NaverWcslog.injections = [hit, noopFunc];
        var redirectsList = Object.freeze({
            __proto__: null,
            noeval: noeval,
            GoogleAnalytics: GoogleAnalytics,
            GoogleAnalyticsGa: GoogleAnalyticsGa,
            GoogleSyndicationAdsByGoogle: GoogleSyndicationAdsByGoogle,
            GoogleTagServicesGpt: GoogleTagServicesGpt,
            ScoreCardResearchBeacon: ScoreCardResearchBeacon,
            metrikaYandexTag: metrikaYandexTag,
            metrikaYandexWatch: metrikaYandexWatch,
            preventFab: preventFab,
            preventBab: preventBab,
            setPopadsDummy: setPopadsDummy,
            preventPopadsNet: preventPopadsNet,
            AmazonApstag: AmazonApstag,
            Matomo: Matomo,
            Fingerprintjs2: Fingerprintjs2,
            Fingerprintjs3: Fingerprintjs3,
            Gemius: Gemius,
            ATInternetSmartTag: ATInternetSmartTag,
            preventBab2: preventBab2,
            GoogleIma3: GoogleIma3,
            DidomiLoader: DidomiLoader,
            Prebid: Prebid,
            prebidAds: prebidAds,
            NaverWcslog: NaverWcslog
        });
        function _classCallCheck(instance, Constructor) {
          if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
          }
        }
        var classCallCheck = _classCallCheck;
        function _defineProperties(target, props) {
          for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];
            descriptor.enumerable = descriptor.enumerable || false;
            descriptor.configurable = true;
            if ("value" in descriptor) descriptor.writable = true;
            Object.defineProperty(target, descriptor.key, descriptor);
          }
        }
        function _createClass(Constructor, protoProps, staticProps) {
          if (protoProps) _defineProperties(Constructor.prototype, protoProps);
          if (staticProps) _defineProperties(Constructor, staticProps);
          return Constructor;
        }
        var createClass = _createClass;
        function isNothing(subject) {
          return typeof subject === 'undefined' || subject === null;
        }
        function isObject(subject) {
          return typeof subject === 'object' && subject !== null;
        }
        function toArray$1(sequence) {
          if (Array.isArray(sequence)) return sequence;else if (isNothing(sequence)) return [];
          return [sequence];
        }
        function extend(target, source) {
          var index, length, key, sourceKeys;
          if (source) {
            sourceKeys = Object.keys(source);
            for (index = 0, length = sourceKeys.length; index < length; index += 1) {
              key = sourceKeys[index];
              target[key] = source[key];
            }
          }
          return target;
        }
        function repeat(string, count) {
          var result = '',
              cycle;
          for (cycle = 0; cycle < count; cycle += 1) {
            result += string;
          }
          return result;
        }
        function isNegativeZero(number) {
          return number === 0 && Number.NEGATIVE_INFINITY === 1 / number;
        }
        var isNothing_1 = isNothing;
        var isObject_1 = isObject;
        var toArray_1 = toArray$1;
        var repeat_1 = repeat;
        var isNegativeZero_1 = isNegativeZero;
        var extend_1 = extend;
        var common = {
          isNothing: isNothing_1,
          isObject: isObject_1,
          toArray: toArray_1,
          repeat: repeat_1,
          isNegativeZero: isNegativeZero_1,
          extend: extend_1
        };
        function YAMLException(reason, mark) {
          Error.call(this);
          this.name = 'YAMLException';
          this.reason = reason;
          this.mark = mark;
          this.message = (this.reason || '(unknown reason)') + (this.mark ? ' ' + this.mark.toString() : '');
          if (Error.captureStackTrace) {
            Error.captureStackTrace(this, this.constructor);
          } else {
            this.stack = new Error().stack || '';
          }
        }
        YAMLException.prototype = Object.create(Error.prototype);
        YAMLException.prototype.constructor = YAMLException;
        YAMLException.prototype.toString = function toString(compact) {
          var result = this.name + ': ';
          result += this.reason || '(unknown reason)';
          if (!compact && this.mark) {
            result += ' ' + this.mark.toString();
          }
          return result;
        };
        var exception = YAMLException;
        function Mark(name, buffer, position, line, column) {
          this.name = name;
          this.buffer = buffer;
          this.position = position;
          this.line = line;
          this.column = column;
        }
        Mark.prototype.getSnippet = function getSnippet(indent, maxLength) {
          var head, start, tail, end, snippet;
          if (!this.buffer) return null;
          indent = indent || 4;
          maxLength = maxLength || 75;
          head = '';
          start = this.position;
          while (start > 0 && "\0\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(start - 1)) === -1) {
            start -= 1;
            if (this.position - start > maxLength / 2 - 1) {
              head = ' ... ';
              start += 5;
              break;
            }
          }
          tail = '';
          end = this.position;
          while (end < this.buffer.length && "\0\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(end)) === -1) {
            end += 1;
            if (end - this.position > maxLength / 2 - 1) {
              tail = ' ... ';
              end -= 5;
              break;
            }
          }
          snippet = this.buffer.slice(start, end);
          return common.repeat(' ', indent) + head + snippet + tail + '\n' + common.repeat(' ', indent + this.position - start + head.length) + '^';
        };
        Mark.prototype.toString = function toString(compact) {
          var snippet,
              where = '';
          if (this.name) {
            where += 'in "' + this.name + '" ';
          }
          where += 'at line ' + (this.line + 1) + ', column ' + (this.column + 1);
          if (!compact) {
            snippet = this.getSnippet();
            if (snippet) {
              where += ':\n' + snippet;
            }
          }
          return where;
        };
        var mark = Mark;
        var TYPE_CONSTRUCTOR_OPTIONS = ['kind', 'resolve', 'construct', 'instanceOf', 'predicate', 'represent', 'defaultStyle', 'styleAliases'];
        var YAML_NODE_KINDS = ['scalar', 'sequence', 'mapping'];
        function compileStyleAliases(map) {
          var result = {};
          if (map !== null) {
            Object.keys(map).forEach(function (style) {
              map[style].forEach(function (alias) {
                result[String(alias)] = style;
              });
            });
          }
          return result;
        }
        function Type(tag, options) {
          options = options || {};
          Object.keys(options).forEach(function (name) {
            if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) {
              throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.');
            }
          });
          this.tag = tag;
          this.kind = options['kind'] || null;
          this.resolve = options['resolve'] || function () {
            return true;
          };
          this.construct = options['construct'] || function (data) {
            return data;
          };
          this.instanceOf = options['instanceOf'] || null;
          this.predicate = options['predicate'] || null;
          this.represent = options['represent'] || null;
          this.defaultStyle = options['defaultStyle'] || null;
          this.styleAliases = compileStyleAliases(options['styleAliases'] || null);
          if (YAML_NODE_KINDS.indexOf(this.kind) === -1) {
            throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.');
          }
        }
        var type = Type;
        function compileList(schema, name, result) {
          var exclude = [];
          schema.include.forEach(function (includedSchema) {
            result = compileList(includedSchema, name, result);
          });
          schema[name].forEach(function (currentType) {
            result.forEach(function (previousType, previousIndex) {
              if (previousType.tag === currentType.tag && previousType.kind === currentType.kind) {
                exclude.push(previousIndex);
              }
            });
            result.push(currentType);
          });
          return result.filter(function (type, index) {
            return exclude.indexOf(index) === -1;
          });
        }
        function compileMap()
        {
          var result = {
            scalar: {},
            sequence: {},
            mapping: {},
            fallback: {}
          },
              index,
              length;
          function collectType(type) {
            result[type.kind][type.tag] = result['fallback'][type.tag] = type;
          }
          for (index = 0, length = arguments.length; index < length; index += 1) {
            arguments[index].forEach(collectType);
          }
          return result;
        }
        function Schema(definition) {
          this.include = definition.include || [];
          this.implicit = definition.implicit || [];
          this.explicit = definition.explicit || [];
          this.implicit.forEach(function (type) {
            if (type.loadKind && type.loadKind !== 'scalar') {
              throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.');
            }
          });
          this.compiledImplicit = compileList(this, 'implicit', []);
          this.compiledExplicit = compileList(this, 'explicit', []);
          this.compiledTypeMap = compileMap(this.compiledImplicit, this.compiledExplicit);
        }
        Schema.DEFAULT = null;
        Schema.create = function createSchema() {
          var schemas, types;
          switch (arguments.length) {
            case 1:
              schemas = Schema.DEFAULT;
              types = arguments[0];
              break;
            case 2:
              schemas = arguments[0];
              types = arguments[1];
              break;
            default:
              throw new exception('Wrong number of arguments for Schema.create function');
          }
          schemas = common.toArray(schemas);
          types = common.toArray(types);
          if (!schemas.every(function (schema) {
            return schema instanceof Schema;
          })) {
            throw new exception('Specified list of super schemas (or a single Schema object) contains a non-Schema object.');
          }
          if (!types.every(function (type$1) {
            return type$1 instanceof type;
          })) {
            throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.');
          }
          return new Schema({
            include: schemas,
            explicit: types
          });
        };
        var schema = Schema;
        var str = new type('tag:yaml.org,2002:str', {
          kind: 'scalar',
          construct: function construct(data) {
            return data !== null ? data : '';
          }
        });
        var seq = new type('tag:yaml.org,2002:seq', {
          kind: 'sequence',
          construct: function construct(data) {
            return data !== null ? data : [];
          }
        });
        var map = new type('tag:yaml.org,2002:map', {
          kind: 'mapping',
          construct: function construct(data) {
            return data !== null ? data : {};
          }
        });
        var failsafe = new schema({
          explicit: [str, seq, map]
        });
        function resolveYamlNull(data) {
          if (data === null) return true;
          var max = data.length;
          return max === 1 && data === '~' || max === 4 && (data === 'null' || data === 'Null' || data === 'NULL');
        }
        function constructYamlNull() {
          return null;
        }
        function isNull(object) {
          return object === null;
        }
        var _null = new type('tag:yaml.org,2002:null', {
          kind: 'scalar',
          resolve: resolveYamlNull,
          construct: constructYamlNull,
          predicate: isNull,
          represent: {
            canonical: function canonical() {
              return '~';
            },
            lowercase: function lowercase() {
              return 'null';
            },
            uppercase: function uppercase() {
              return 'NULL';
            },
            camelcase: function camelcase() {
              return 'Null';
            }
          },
          defaultStyle: 'lowercase'
        });
        function resolveYamlBoolean(data) {
          if (data === null) return false;
          var max = data.length;
          return max === 4 && (data === 'true' || data === 'True' || data === 'TRUE') || max === 5 && (data === 'false' || data === 'False' || data === 'FALSE');
        }
        function constructYamlBoolean(data) {
          return data === 'true' || data === 'True' || data === 'TRUE';
        }
        function isBoolean(object) {
          return Object.prototype.toString.call(object) === '[object Boolean]';
        }
        var bool = new type('tag:yaml.org,2002:bool', {
          kind: 'scalar',
          resolve: resolveYamlBoolean,
          construct: constructYamlBoolean,
          predicate: isBoolean,
          represent: {
            lowercase: function lowercase(object) {
              return object ? 'true' : 'false';
            },
            uppercase: function uppercase(object) {
              return object ? 'TRUE' : 'FALSE';
            },
            camelcase: function camelcase(object) {
              return object ? 'True' : 'False';
            }
          },
          defaultStyle: 'lowercase'
        });
        function isHexCode(c) {
          return 0x30
          <= c && c <= 0x39
          || 0x41
          <= c && c <= 0x46
          || 0x61
          <= c && c <= 0x66
          ;
        }
        function isOctCode(c) {
          return 0x30
          <= c && c <= 0x37
          ;
        }
        function isDecCode(c) {
          return 0x30
          <= c && c <= 0x39
          ;
        }
        function resolveYamlInteger(data) {
          if (data === null) return false;
          var max = data.length,
              index = 0,
              hasDigits = false,
              ch;
          if (!max) return false;
          ch = data[index];
          if (ch === '-' || ch === '+') {
            ch = data[++index];
          }
          if (ch === '0') {
            if (index + 1 === max) return true;
            ch = data[++index];
            if (ch === 'b') {
              index++;
              for (; index < max; index++) {
                ch = data[index];
                if (ch === '_') continue;
                if (ch !== '0' && ch !== '1') return false;
                hasDigits = true;
              }
              return hasDigits && ch !== '_';
            }
            if (ch === 'x') {
              index++;
              for (; index < max; index++) {
                ch = data[index];
                if (ch === '_') continue;
                if (!isHexCode(data.charCodeAt(index))) return false;
                hasDigits = true;
              }
              return hasDigits && ch !== '_';
            }
            for (; index < max; index++) {
              ch = data[index];
              if (ch === '_') continue;
              if (!isOctCode(data.charCodeAt(index))) return false;
              hasDigits = true;
            }
            return hasDigits && ch !== '_';
          }
          if (ch === '_') return false;
          for (; index < max; index++) {
            ch = data[index];
            if (ch === '_') continue;
            if (ch === ':') break;
            if (!isDecCode(data.charCodeAt(index))) {
              return false;
            }
            hasDigits = true;
          }
          if (!hasDigits || ch === '_') return false;
          if (ch !== ':') return true;
          return /^(:[0-5]?[0-9])+$/.test(data.slice(index));
        }
        function constructYamlInteger(data) {
          var value = data,
              sign = 1,
              ch,
              base,
              digits = [];
          if (value.indexOf('_') !== -1) {
            value = value.replace(/_/g, '');
          }
          ch = value[0];
          if (ch === '-' || ch === '+') {
            if (ch === '-') sign = -1;
            value = value.slice(1);
            ch = value[0];
          }
          if (value === '0') return 0;
          if (ch === '0') {
            if (value[1] === 'b') return sign * parseInt(value.slice(2), 2);
            if (value[1] === 'x') return sign * parseInt(value, 16);
            return sign * parseInt(value, 8);
          }
          if (value.indexOf(':') !== -1) {
            value.split(':').forEach(function (v) {
              digits.unshift(parseInt(v, 10));
            });
            value = 0;
            base = 1;
            digits.forEach(function (d) {
              value += d * base;
              base *= 60;
            });
            return sign * value;
          }
          return sign * parseInt(value, 10);
        }
        function isInteger(object) {
          return Object.prototype.toString.call(object) === '[object Number]' && object % 1 === 0 && !common.isNegativeZero(object);
        }
        var int = new type('tag:yaml.org,2002:int', {
          kind: 'scalar',
          resolve: resolveYamlInteger,
          construct: constructYamlInteger,
          predicate: isInteger,
          represent: {
            binary: function binary(obj) {
              return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1);
            },
            octal: function octal(obj) {
              return obj >= 0 ? '0' + obj.toString(8) : '-0' + obj.toString(8).slice(1);
            },
            decimal: function decimal(obj) {
              return obj.toString(10);
            },
            hexadecimal: function hexadecimal(obj) {
              return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1);
            }
          },
          defaultStyle: 'decimal',
          styleAliases: {
            binary: [2, 'bin'],
            octal: [8, 'oct'],
            decimal: [10, 'dec'],
            hexadecimal: [16, 'hex']
          }
        });
        var YAML_FLOAT_PATTERN = new RegExp(
        '^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' +
        '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' +
        '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' +
        '|[-+]?\\.(?:inf|Inf|INF)' +
        '|\\.(?:nan|NaN|NAN))$');
        function resolveYamlFloat(data) {
          if (data === null) return false;
          if (!YAML_FLOAT_PATTERN.test(data) ||
          data[data.length - 1] === '_') {
            return false;
          }
          return true;
        }
        function constructYamlFloat(data) {
          var value, sign, base, digits;
          value = data.replace(/_/g, '').toLowerCase();
          sign = value[0] === '-' ? -1 : 1;
          digits = [];
          if ('+-'.indexOf(value[0]) >= 0) {
            value = value.slice(1);
          }
          if (value === '.inf') {
            return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
          } else if (value === '.nan') {
            return NaN;
          } else if (value.indexOf(':') >= 0) {
            value.split(':').forEach(function (v) {
              digits.unshift(parseFloat(v, 10));
            });
            value = 0.0;
            base = 1;
            digits.forEach(function (d) {
              value += d * base;
              base *= 60;
            });
            return sign * value;
          }
          return sign * parseFloat(value, 10);
        }
        var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/;
        function representYamlFloat(object, style) {
          var res;
          if (isNaN(object)) {
            switch (style) {
              case 'lowercase':
                return '.nan';
              case 'uppercase':
                return '.NAN';
              case 'camelcase':
                return '.NaN';
            }
          } else if (Number.POSITIVE_INFINITY === object) {
            switch (style) {
              case 'lowercase':
                return '.inf';
              case 'uppercase':
                return '.INF';
              case 'camelcase':
                return '.Inf';
            }
          } else if (Number.NEGATIVE_INFINITY === object) {
            switch (style) {
              case 'lowercase':
                return '-.inf';
              case 'uppercase':
                return '-.INF';
              case 'camelcase':
                return '-.Inf';
            }
          } else if (common.isNegativeZero(object)) {
            return '-0.0';
          }
          res = object.toString(10);
          return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res;
        }
        function isFloat(object) {
          return Object.prototype.toString.call(object) === '[object Number]' && (object % 1 !== 0 || common.isNegativeZero(object));
        }
        var float = new type('tag:yaml.org,2002:float', {
          kind: 'scalar',
          resolve: resolveYamlFloat,
          construct: constructYamlFloat,
          predicate: isFloat,
          represent: representYamlFloat,
          defaultStyle: 'lowercase'
        });
        var json = new schema({
          include: [failsafe],
          implicit: [_null, bool, int, float]
        });
        var core = new schema({
          include: [json]
        });
        var YAML_DATE_REGEXP = new RegExp('^([0-9][0-9][0-9][0-9])' +
        '-([0-9][0-9])' +
        '-([0-9][0-9])$');
        var YAML_TIMESTAMP_REGEXP = new RegExp('^([0-9][0-9][0-9][0-9])' +
        '-([0-9][0-9]?)' +
        '-([0-9][0-9]?)' +
        '(?:[Tt]|[ \\t]+)' +
        '([0-9][0-9]?)' +
        ':([0-9][0-9])' +
        ':([0-9][0-9])' +
        '(?:\\.([0-9]*))?' +
        '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' +
        '(?::([0-9][0-9]))?))?$');
        function resolveYamlTimestamp(data) {
          if (data === null) return false;
          if (YAML_DATE_REGEXP.exec(data) !== null) return true;
          if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true;
          return false;
        }
        function constructYamlTimestamp(data) {
          var match,
              year,
              month,
              day,
              hour,
              minute,
              second,
              fraction = 0,
              delta = null,
              tz_hour,
              tz_minute,
              date;
          match = YAML_DATE_REGEXP.exec(data);
          if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data);
          if (match === null) throw new Error('Date resolve error');
          year = +match[1];
          month = +match[2] - 1;
          day = +match[3];
          if (!match[4]) {
            return new Date(Date.UTC(year, month, day));
          }
          hour = +match[4];
          minute = +match[5];
          second = +match[6];
          if (match[7]) {
            fraction = match[7].slice(0, 3);
            while (fraction.length < 3) {
              fraction += '0';
            }
            fraction = +fraction;
          }
          if (match[9]) {
            tz_hour = +match[10];
            tz_minute = +(match[11] || 0);
            delta = (tz_hour * 60 + tz_minute) * 60000;
            if (match[9] === '-') delta = -delta;
          }
          date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
          if (delta) date.setTime(date.getTime() - delta);
          return date;
        }
        function representYamlTimestamp(object
        ) {
          return object.toISOString();
        }
        var timestamp = new type('tag:yaml.org,2002:timestamp', {
          kind: 'scalar',
          resolve: resolveYamlTimestamp,
          construct: constructYamlTimestamp,
          instanceOf: Date,
          represent: representYamlTimestamp
        });
        function resolveYamlMerge(data) {
          return data === '<<' || data === null;
        }
        var merge = new type('tag:yaml.org,2002:merge', {
          kind: 'scalar',
          resolve: resolveYamlMerge
        });
        function commonjsRequire (target) {
        	throw new Error('Could not dynamically require "' + target + '". Please configure the dynamicRequireTargets option of @rollup/plugin-commonjs appropriately for this require call to behave properly.');
        }
        var NodeBuffer;
        try {
          var _require = commonjsRequire;
          NodeBuffer = _require('buffer').Buffer;
        } catch (__) {}
        var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r';
        function resolveYamlBinary(data) {
          if (data === null) return false;
          var code,
              idx,
              bitlen = 0,
              max = data.length,
              map = BASE64_MAP;
          for (idx = 0; idx < max; idx++) {
            code = map.indexOf(data.charAt(idx));
            if (code > 64) continue;
            if (code < 0) return false;
            bitlen += 6;
          }
          return bitlen % 8 === 0;
        }
        function constructYamlBinary(data) {
          var idx,
              tailbits,
              input = data.replace(/[\r\n=]/g, ''),
          max = input.length,
              map = BASE64_MAP,
              bits = 0,
              result = [];
          for (idx = 0; idx < max; idx++) {
            if (idx % 4 === 0 && idx) {
              result.push(bits >> 16 & 0xFF);
              result.push(bits >> 8 & 0xFF);
              result.push(bits & 0xFF);
            }
            bits = bits << 6 | map.indexOf(input.charAt(idx));
          }
          tailbits = max % 4 * 6;
          if (tailbits === 0) {
            result.push(bits >> 16 & 0xFF);
            result.push(bits >> 8 & 0xFF);
            result.push(bits & 0xFF);
          } else if (tailbits === 18) {
            result.push(bits >> 10 & 0xFF);
            result.push(bits >> 2 & 0xFF);
          } else if (tailbits === 12) {
            result.push(bits >> 4 & 0xFF);
          }
          if (NodeBuffer) {
            return NodeBuffer.from ? NodeBuffer.from(result) : new NodeBuffer(result);
          }
          return result;
        }
        function representYamlBinary(object
        ) {
          var result = '',
              bits = 0,
              idx,
              tail,
              max = object.length,
              map = BASE64_MAP;
          for (idx = 0; idx < max; idx++) {
            if (idx % 3 === 0 && idx) {
              result += map[bits >> 18 & 0x3F];
              result += map[bits >> 12 & 0x3F];
              result += map[bits >> 6 & 0x3F];
              result += map[bits & 0x3F];
            }
            bits = (bits << 8) + object[idx];
          }
          tail = max % 3;
          if (tail === 0) {
            result += map[bits >> 18 & 0x3F];
            result += map[bits >> 12 & 0x3F];
            result += map[bits >> 6 & 0x3F];
            result += map[bits & 0x3F];
          } else if (tail === 2) {
            result += map[bits >> 10 & 0x3F];
            result += map[bits >> 4 & 0x3F];
            result += map[bits << 2 & 0x3F];
            result += map[64];
          } else if (tail === 1) {
            result += map[bits >> 2 & 0x3F];
            result += map[bits << 4 & 0x3F];
            result += map[64];
            result += map[64];
          }
          return result;
        }
        function isBinary(object) {
          return NodeBuffer && NodeBuffer.isBuffer(object);
        }
        var binary = new type('tag:yaml.org,2002:binary', {
          kind: 'scalar',
          resolve: resolveYamlBinary,
          construct: constructYamlBinary,
          predicate: isBinary,
          represent: representYamlBinary
        });
        var _hasOwnProperty = Object.prototype.hasOwnProperty;
        var _toString = Object.prototype.toString;
        function resolveYamlOmap(data) {
          if (data === null) return true;
          var objectKeys = [],
              index,
              length,
              pair,
              pairKey,
              pairHasKey,
              object = data;
          for (index = 0, length = object.length; index < length; index += 1) {
            pair = object[index];
            pairHasKey = false;
            if (_toString.call(pair) !== '[object Object]') return false;
            for (pairKey in pair) {
              if (_hasOwnProperty.call(pair, pairKey)) {
                if (!pairHasKey) pairHasKey = true;else return false;
              }
            }
            if (!pairHasKey) return false;
            if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey);else return false;
          }
          return true;
        }
        function constructYamlOmap(data) {
          return data !== null ? data : [];
        }
        var omap = new type('tag:yaml.org,2002:omap', {
          kind: 'sequence',
          resolve: resolveYamlOmap,
          construct: constructYamlOmap
        });
        var _toString$1 = Object.prototype.toString;
        function resolveYamlPairs(data) {
          if (data === null) return true;
          var index,
              length,
              pair,
              keys,
              result,
              object = data;
          result = new Array(object.length);
          for (index = 0, length = object.length; index < length; index += 1) {
            pair = object[index];
            if (_toString$1.call(pair) !== '[object Object]') return false;
            keys = Object.keys(pair);
            if (keys.length !== 1) return false;
            result[index] = [keys[0], pair[keys[0]]];
          }
          return true;
        }
        function constructYamlPairs(data) {
          if (data === null) return [];
          var index,
              length,
              pair,
              keys,
              result,
              object = data;
          result = new Array(object.length);
          for (index = 0, length = object.length; index < length; index += 1) {
            pair = object[index];
            keys = Object.keys(pair);
            result[index] = [keys[0], pair[keys[0]]];
          }
          return result;
        }
        var pairs = new type('tag:yaml.org,2002:pairs', {
          kind: 'sequence',
          resolve: resolveYamlPairs,
          construct: constructYamlPairs
        });
        var _hasOwnProperty$1 = Object.prototype.hasOwnProperty;
        function resolveYamlSet(data) {
          if (data === null) return true;
          var key,
              object = data;
          for (key in object) {
            if (_hasOwnProperty$1.call(object, key)) {
              if (object[key] !== null) return false;
            }
          }
          return true;
        }
        function constructYamlSet(data) {
          return data !== null ? data : {};
        }
        var set = new type('tag:yaml.org,2002:set', {
          kind: 'mapping',
          resolve: resolveYamlSet,
          construct: constructYamlSet
        });
        var default_safe = new schema({
          include: [core],
          implicit: [timestamp, merge],
          explicit: [binary, omap, pairs, set]
        });
        function resolveJavascriptUndefined() {
          return true;
        }
        function constructJavascriptUndefined() {
          return undefined;
        }
        function representJavascriptUndefined() {
          return '';
        }
        function isUndefined(object) {
          return typeof object === 'undefined';
        }
        var _undefined = new type('tag:yaml.org,2002:js/undefined', {
          kind: 'scalar',
          resolve: resolveJavascriptUndefined,
          construct: constructJavascriptUndefined,
          predicate: isUndefined,
          represent: representJavascriptUndefined
        });
        function resolveJavascriptRegExp(data) {
          if (data === null) return false;
          if (data.length === 0) return false;
          var regexp = data,
              tail = /\/([gim]*)$/.exec(data),
              modifiers = '';
          if (regexp[0] === '/') {
            if (tail) modifiers = tail[1];
            if (modifiers.length > 3) return false;
            if (regexp[regexp.length - modifiers.length - 1] !== '/') return false;
          }
          return true;
        }
        function constructJavascriptRegExp(data) {
          var regexp = data,
              tail = /\/([gim]*)$/.exec(data),
              modifiers = '';
          if (regexp[0] === '/') {
            if (tail) modifiers = tail[1];
            regexp = regexp.slice(1, regexp.length - modifiers.length - 1);
          }
          return new RegExp(regexp, modifiers);
        }
        function representJavascriptRegExp(object
        ) {
          var result = '/' + object.source + '/';
          if (object.global) result += 'g';
          if (object.multiline) result += 'm';
          if (object.ignoreCase) result += 'i';
          return result;
        }
        function isRegExp(object) {
          return Object.prototype.toString.call(object) === '[object RegExp]';
        }
        var regexp = new type('tag:yaml.org,2002:js/regexp', {
          kind: 'scalar',
          resolve: resolveJavascriptRegExp,
          construct: constructJavascriptRegExp,
          predicate: isRegExp,
          represent: representJavascriptRegExp
        });
        var esprima;
        try {
          var _require$1 = commonjsRequire;
          esprima = _require$1('esprima');
        } catch (_) {
          if (typeof window !== 'undefined') esprima = window.esprima;
        }
        function resolveJavascriptFunction(data) {
          if (data === null) return false;
          try {
            var source = '(' + data + ')',
                ast = esprima.parse(source, {
              range: true
            });
            if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression') {
              return false;
            }
            return true;
          } catch (err) {
            return false;
          }
        }
        function constructJavascriptFunction(data) {
          var source = '(' + data + ')',
              ast = esprima.parse(source, {
            range: true
          }),
              params = [],
              body;
          if (ast.type !== 'Program' || ast.body.length !== 1 || ast.body[0].type !== 'ExpressionStatement' || ast.body[0].expression.type !== 'ArrowFunctionExpression' && ast.body[0].expression.type !== 'FunctionExpression') {
            throw new Error('Failed to resolve function');
          }
          ast.body[0].expression.params.forEach(function (param) {
            params.push(param.name);
          });
          body = ast.body[0].expression.body.range;
          if (ast.body[0].expression.body.type === 'BlockStatement') {
            return new Function(params, source.slice(body[0] + 1, body[1] - 1));
          }
          return new Function(params, 'return ' + source.slice(body[0], body[1]));
        }
        function representJavascriptFunction(object
        ) {
          return object.toString();
        }
        function isFunction(object) {
          return Object.prototype.toString.call(object) === '[object Function]';
        }
        var _function = new type('tag:yaml.org,2002:js/function', {
          kind: 'scalar',
          resolve: resolveJavascriptFunction,
          construct: constructJavascriptFunction,
          predicate: isFunction,
          represent: representJavascriptFunction
        });
        var default_full = schema.DEFAULT = new schema({
          include: [default_safe],
          explicit: [_undefined, regexp, _function]
        });
        var _hasOwnProperty$2 = Object.prototype.hasOwnProperty;
        var CONTEXT_FLOW_IN = 1;
        var CONTEXT_FLOW_OUT = 2;
        var CONTEXT_BLOCK_IN = 3;
        var CONTEXT_BLOCK_OUT = 4;
        var CHOMPING_CLIP = 1;
        var CHOMPING_STRIP = 2;
        var CHOMPING_KEEP = 3;
        var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/;
        var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/;
        var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/;
        var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i;
        var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i;
        function _class(obj) {
          return Object.prototype.toString.call(obj);
        }
        function is_EOL(c) {
          return c === 0x0A
          || c === 0x0D
          ;
        }
        function is_WHITE_SPACE(c) {
          return c === 0x09
          || c === 0x20
          ;
        }
        function is_WS_OR_EOL(c) {
          return c === 0x09
          || c === 0x20
          || c === 0x0A
          || c === 0x0D
          ;
        }
        function is_FLOW_INDICATOR(c) {
          return c === 0x2C
          || c === 0x5B
          || c === 0x5D
          || c === 0x7B
          || c === 0x7D
          ;
        }
        function fromHexCode(c) {
          var lc;
          if (0x30
          <= c && c <= 0x39
          ) {
            return c - 0x30;
          }
          lc = c | 0x20;
          if (0x61
          <= lc && lc <= 0x66
          ) {
            return lc - 0x61 + 10;
          }
          return -1;
        }
        function escapedHexLen(c) {
          if (c === 0x78
          ) {
              return 2;
            }
          if (c === 0x75
          ) {
              return 4;
            }
          if (c === 0x55
          ) {
              return 8;
            }
          return 0;
        }
        function fromDecimalCode(c) {
          if (0x30
          <= c && c <= 0x39
          ) {
            return c - 0x30;
          }
          return -1;
        }
        function simpleEscapeSequence(c) {
          return c === 0x30
          ? '\x00' : c === 0x61
          ? '\x07' : c === 0x62
          ? '\x08' : c === 0x74
          ? '\x09' : c === 0x09
          ? '\x09' : c === 0x6E
          ? '\x0A' : c === 0x76
          ? '\x0B' : c === 0x66
          ? '\x0C' : c === 0x72
          ? '\x0D' : c === 0x65
          ? '\x1B' : c === 0x20
          ? ' ' : c === 0x22
          ? '\x22' : c === 0x2F
          ? '/' : c === 0x5C
          ? '\x5C' : c === 0x4E
          ? '\x85' : c === 0x5F
          ? '\xA0' : c === 0x4C
          ? "\u2028" : c === 0x50
          ? "\u2029" : '';
        }
        function charFromCodepoint(c) {
          if (c <= 0xFFFF) {
            return String.fromCharCode(c);
          }
          return String.fromCharCode((c - 0x010000 >> 10) + 0xD800, (c - 0x010000 & 0x03FF) + 0xDC00);
        }
        var simpleEscapeCheck = new Array(256);
        var simpleEscapeMap = new Array(256);
        for (var i = 0; i < 256; i++) {
          simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0;
          simpleEscapeMap[i] = simpleEscapeSequence(i);
        }
        function State(input, options) {
          this.input = input;
          this.filename = options['filename'] || null;
          this.schema = options['schema'] || default_full;
          this.onWarning = options['onWarning'] || null;
          this.legacy = options['legacy'] || false;
          this.json = options['json'] || false;
          this.listener = options['listener'] || null;
          this.implicitTypes = this.schema.compiledImplicit;
          this.typeMap = this.schema.compiledTypeMap;
          this.length = input.length;
          this.position = 0;
          this.line = 0;
          this.lineStart = 0;
          this.lineIndent = 0;
          this.documents = [];
        }
        function generateError(state, message) {
          return new exception(message, new mark(state.filename, state.input, state.position, state.line, state.position - state.lineStart));
        }
        function throwError(state, message) {
          throw generateError(state, message);
        }
        function throwWarning(state, message) {
          if (state.onWarning) {
            state.onWarning.call(null, generateError(state, message));
          }
        }
        var directiveHandlers = {
          YAML: function handleYamlDirective(state, name, args) {
            var match, major, minor;
            if (state.version !== null) {
              throwError(state, 'duplication of %YAML directive');
            }
            if (args.length !== 1) {
              throwError(state, 'YAML directive accepts exactly one argument');
            }
            match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]);
            if (match === null) {
              throwError(state, 'ill-formed argument of the YAML directive');
            }
            major = parseInt(match[1], 10);
            minor = parseInt(match[2], 10);
            if (major !== 1) {
              throwError(state, 'unacceptable YAML version of the document');
            }
            state.version = args[0];
            state.checkLineBreaks = minor < 2;
            if (minor !== 1 && minor !== 2) {
              throwWarning(state, 'unsupported YAML version of the document');
            }
          },
          TAG: function handleTagDirective(state, name, args) {
            var handle, prefix;
            if (args.length !== 2) {
              throwError(state, 'TAG directive accepts exactly two arguments');
            }
            handle = args[0];
            prefix = args[1];
            if (!PATTERN_TAG_HANDLE.test(handle)) {
              throwError(state, 'ill-formed tag handle (first argument) of the TAG directive');
            }
            if (_hasOwnProperty$2.call(state.tagMap, handle)) {
              throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle');
            }
            if (!PATTERN_TAG_URI.test(prefix)) {
              throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive');
            }
            state.tagMap[handle] = prefix;
          }
        };
        function captureSegment(state, start, end, checkJson) {
          var _position, _length, _character, _result;
          if (start < end) {
            _result = state.input.slice(start, end);
            if (checkJson) {
              for (_position = 0, _length = _result.length; _position < _length; _position += 1) {
                _character = _result.charCodeAt(_position);
                if (!(_character === 0x09 || 0x20 <= _character && _character <= 0x10FFFF)) {
                  throwError(state, 'expected valid JSON character');
                }
              }
            } else if (PATTERN_NON_PRINTABLE.test(_result)) {
              throwError(state, 'the stream contains non-printable characters');
            }
            state.result += _result;
          }
        }
        function mergeMappings(state, destination, source, overridableKeys) {
          var sourceKeys, key, index, quantity;
          if (!common.isObject(source)) {
            throwError(state, 'cannot merge mappings; the provided source object is unacceptable');
          }
          sourceKeys = Object.keys(source);
          for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) {
            key = sourceKeys[index];
            if (!_hasOwnProperty$2.call(destination, key)) {
              destination[key] = source[key];
              overridableKeys[key] = true;
            }
          }
        }
        function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, startLine, startPos) {
          var index, quantity;
          if (Array.isArray(keyNode)) {
            keyNode = Array.prototype.slice.call(keyNode);
            for (index = 0, quantity = keyNode.length; index < quantity; index += 1) {
              if (Array.isArray(keyNode[index])) {
                throwError(state, 'nested arrays are not supported inside keys');
              }
              if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') {
                keyNode[index] = '[object Object]';
              }
            }
          }
          if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') {
            keyNode = '[object Object]';
          }
          keyNode = String(keyNode);
          if (_result === null) {
            _result = {};
          }
          if (keyTag === 'tag:yaml.org,2002:merge') {
            if (Array.isArray(valueNode)) {
              for (index = 0, quantity = valueNode.length; index < quantity; index += 1) {
                mergeMappings(state, _result, valueNode[index], overridableKeys);
              }
            } else {
              mergeMappings(state, _result, valueNode, overridableKeys);
            }
          } else {
            if (!state.json && !_hasOwnProperty$2.call(overridableKeys, keyNode) && _hasOwnProperty$2.call(_result, keyNode)) {
              state.line = startLine || state.line;
              state.position = startPos || state.position;
              throwError(state, 'duplicated mapping key');
            }
            _result[keyNode] = valueNode;
            delete overridableKeys[keyNode];
          }
          return _result;
        }
        function readLineBreak(state) {
          var ch;
          ch = state.input.charCodeAt(state.position);
          if (ch === 0x0A
          ) {
              state.position++;
            } else if (ch === 0x0D
          ) {
              state.position++;
              if (state.input.charCodeAt(state.position) === 0x0A
              ) {
                  state.position++;
                }
            } else {
            throwError(state, 'a line break is expected');
          }
          state.line += 1;
          state.lineStart = state.position;
        }
        function skipSeparationSpace(state, allowComments, checkIndent) {
          var lineBreaks = 0,
              ch = state.input.charCodeAt(state.position);
          while (ch !== 0) {
            while (is_WHITE_SPACE(ch)) {
              ch = state.input.charCodeAt(++state.position);
            }
            if (allowComments && ch === 0x23
            ) {
                do {
                  ch = state.input.charCodeAt(++state.position);
                } while (ch !== 0x0A
                && ch !== 0x0D
                && ch !== 0);
              }
            if (is_EOL(ch)) {
              readLineBreak(state);
              ch = state.input.charCodeAt(state.position);
              lineBreaks++;
              state.lineIndent = 0;
              while (ch === 0x20
              ) {
                state.lineIndent++;
                ch = state.input.charCodeAt(++state.position);
              }
            } else {
              break;
            }
          }
          if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) {
            throwWarning(state, 'deficient indentation');
          }
          return lineBreaks;
        }
        function testDocumentSeparator(state) {
          var _position = state.position,
              ch;
          ch = state.input.charCodeAt(_position);
          if ((ch === 0x2D
          || ch === 0x2E
          ) && ch === state.input.charCodeAt(_position + 1) && ch === state.input.charCodeAt(_position + 2)) {
            _position += 3;
            ch = state.input.charCodeAt(_position);
            if (ch === 0 || is_WS_OR_EOL(ch)) {
              return true;
            }
          }
          return false;
        }
        function writeFoldedLines(state, count) {
          if (count === 1) {
            state.result += ' ';
          } else if (count > 1) {
            state.result += common.repeat('\n', count - 1);
          }
        }
        function readPlainScalar(state, nodeIndent, withinFlowCollection) {
          var preceding,
              following,
              captureStart,
              captureEnd,
              hasPendingContent,
              _line,
              _lineStart,
              _lineIndent,
              _kind = state.kind,
              _result = state.result,
              ch;
          ch = state.input.charCodeAt(state.position);
          if (is_WS_OR_EOL(ch) || is_FLOW_INDICATOR(ch) || ch === 0x23
          || ch === 0x26
          || ch === 0x2A
          || ch === 0x21
          || ch === 0x7C
          || ch === 0x3E
          || ch === 0x27
          || ch === 0x22
          || ch === 0x25
          || ch === 0x40
          || ch === 0x60
          ) {
              return false;
            }
          if (ch === 0x3F
          || ch === 0x2D
          ) {
              following = state.input.charCodeAt(state.position + 1);
              if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) {
                return false;
              }
            }
          state.kind = 'scalar';
          state.result = '';
          captureStart = captureEnd = state.position;
          hasPendingContent = false;
          while (ch !== 0) {
            if (ch === 0x3A
            ) {
                following = state.input.charCodeAt(state.position + 1);
                if (is_WS_OR_EOL(following) || withinFlowCollection && is_FLOW_INDICATOR(following)) {
                  break;
                }
              } else if (ch === 0x23
            ) {
                preceding = state.input.charCodeAt(state.position - 1);
                if (is_WS_OR_EOL(preceding)) {
                  break;
                }
              } else if (state.position === state.lineStart && testDocumentSeparator(state) || withinFlowCollection && is_FLOW_INDICATOR(ch)) {
              break;
            } else if (is_EOL(ch)) {
              _line = state.line;
              _lineStart = state.lineStart;
              _lineIndent = state.lineIndent;
              skipSeparationSpace(state, false, -1);
              if (state.lineIndent >= nodeIndent) {
                hasPendingContent = true;
                ch = state.input.charCodeAt(state.position);
                continue;
              } else {
                state.position = captureEnd;
                state.line = _line;
                state.lineStart = _lineStart;
                state.lineIndent = _lineIndent;
                break;
              }
            }
            if (hasPendingContent) {
              captureSegment(state, captureStart, captureEnd, false);
              writeFoldedLines(state, state.line - _line);
              captureStart = captureEnd = state.position;
              hasPendingContent = false;
            }
            if (!is_WHITE_SPACE(ch)) {
              captureEnd = state.position + 1;
            }
            ch = state.input.charCodeAt(++state.position);
          }
          captureSegment(state, captureStart, captureEnd, false);
          if (state.result) {
            return true;
          }
          state.kind = _kind;
          state.result = _result;
          return false;
        }
        function readSingleQuotedScalar(state, nodeIndent) {
          var ch, captureStart, captureEnd;
          ch = state.input.charCodeAt(state.position);
          if (ch !== 0x27
          ) {
              return false;
            }
          state.kind = 'scalar';
          state.result = '';
          state.position++;
          captureStart = captureEnd = state.position;
          while ((ch = state.input.charCodeAt(state.position)) !== 0) {
            if (ch === 0x27
            ) {
                captureSegment(state, captureStart, state.position, true);
                ch = state.input.charCodeAt(++state.position);
                if (ch === 0x27
                ) {
                    captureStart = state.position;
                    state.position++;
                    captureEnd = state.position;
                  } else {
                  return true;
                }
              } else if (is_EOL(ch)) {
              captureSegment(state, captureStart, captureEnd, true);
              writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
              captureStart = captureEnd = state.position;
            } else if (state.position === state.lineStart && testDocumentSeparator(state)) {
              throwError(state, 'unexpected end of the document within a single quoted scalar');
            } else {
              state.position++;
              captureEnd = state.position;
            }
          }
          throwError(state, 'unexpected end of the stream within a single quoted scalar');
        }
        function readDoubleQuotedScalar(state, nodeIndent) {
          var captureStart, captureEnd, hexLength, hexResult, tmp, ch;
          ch = state.input.charCodeAt(state.position);
          if (ch !== 0x22
          ) {
              return false;
            }
          state.kind = 'scalar';
          state.result = '';
          state.position++;
          captureStart = captureEnd = state.position;
          while ((ch = state.input.charCodeAt(state.position)) !== 0) {
            if (ch === 0x22
            ) {
                captureSegment(state, captureStart, state.position, true);
                state.position++;
                return true;
              } else if (ch === 0x5C
            ) {
                captureSegment(state, captureStart, state.position, true);
                ch = state.input.charCodeAt(++state.position);
                if (is_EOL(ch)) {
                  skipSeparationSpace(state, false, nodeIndent);
                } else if (ch < 256 && simpleEscapeCheck[ch]) {
                  state.result += simpleEscapeMap[ch];
                  state.position++;
                } else if ((tmp = escapedHexLen(ch)) > 0) {
                  hexLength = tmp;
                  hexResult = 0;
                  for (; hexLength > 0; hexLength--) {
                    ch = state.input.charCodeAt(++state.position);
                    if ((tmp = fromHexCode(ch)) >= 0) {
                      hexResult = (hexResult << 4) + tmp;
                    } else {
                      throwError(state, 'expected hexadecimal character');
                    }
                  }
                  state.result += charFromCodepoint(hexResult);
                  state.position++;
                } else {
                  throwError(state, 'unknown escape sequence');
                }
                captureStart = captureEnd = state.position;
              } else if (is_EOL(ch)) {
              captureSegment(state, captureStart, captureEnd, true);
              writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent));
              captureStart = captureEnd = state.position;
            } else if (state.position === state.lineStart && testDocumentSeparator(state)) {
              throwError(state, 'unexpected end of the document within a double quoted scalar');
            } else {
              state.position++;
              captureEnd = state.position;
            }
          }
          throwError(state, 'unexpected end of the stream within a double quoted scalar');
        }
        function readFlowCollection(state, nodeIndent) {
          var readNext = true,
              _line,
              _tag = state.tag,
              _result,
              _anchor = state.anchor,
              following,
              terminator,
              isPair,
              isExplicitPair,
              isMapping,
              overridableKeys = {},
              keyNode,
              keyTag,
              valueNode,
              ch;
          ch = state.input.charCodeAt(state.position);
          if (ch === 0x5B
          ) {
              terminator = 0x5D;
              isMapping = false;
              _result = [];
            } else if (ch === 0x7B
          ) {
              terminator = 0x7D;
              isMapping = true;
              _result = {};
            } else {
            return false;
          }
          if (state.anchor !== null) {
            state.anchorMap[state.anchor] = _result;
          }
          ch = state.input.charCodeAt(++state.position);
          while (ch !== 0) {
            skipSeparationSpace(state, true, nodeIndent);
            ch = state.input.charCodeAt(state.position);
            if (ch === terminator) {
              state.position++;
              state.tag = _tag;
              state.anchor = _anchor;
              state.kind = isMapping ? 'mapping' : 'sequence';
              state.result = _result;
              return true;
            } else if (!readNext) {
              throwError(state, 'missed comma between flow collection entries');
            }
            keyTag = keyNode = valueNode = null;
            isPair = isExplicitPair = false;
            if (ch === 0x3F
            ) {
                following = state.input.charCodeAt(state.position + 1);
                if (is_WS_OR_EOL(following)) {
                  isPair = isExplicitPair = true;
                  state.position++;
                  skipSeparationSpace(state, true, nodeIndent);
                }
              }
            _line = state.line;
            composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
            keyTag = state.tag;
            keyNode = state.result;
            skipSeparationSpace(state, true, nodeIndent);
            ch = state.input.charCodeAt(state.position);
            if ((isExplicitPair || state.line === _line) && ch === 0x3A
            ) {
                isPair = true;
                ch = state.input.charCodeAt(++state.position);
                skipSeparationSpace(state, true, nodeIndent);
                composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
                valueNode = state.result;
              }
            if (isMapping) {
              storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode);
            } else if (isPair) {
              _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode));
            } else {
              _result.push(keyNode);
            }
            skipSeparationSpace(state, true, nodeIndent);
            ch = state.input.charCodeAt(state.position);
            if (ch === 0x2C
            ) {
                readNext = true;
                ch = state.input.charCodeAt(++state.position);
              } else {
              readNext = false;
            }
          }
          throwError(state, 'unexpected end of the stream within a flow collection');
        }
        function readBlockScalar(state, nodeIndent) {
          var captureStart,
              folding,
              chomping = CHOMPING_CLIP,
              didReadContent = false,
              detectedIndent = false,
              textIndent = nodeIndent,
              emptyLines = 0,
              atMoreIndented = false,
              tmp,
              ch;
          ch = state.input.charCodeAt(state.position);
          if (ch === 0x7C
          ) {
              folding = false;
            } else if (ch === 0x3E
          ) {
              folding = true;
            } else {
            return false;
          }
          state.kind = 'scalar';
          state.result = '';
          while (ch !== 0) {
            ch = state.input.charCodeAt(++state.position);
            if (ch === 0x2B
            || ch === 0x2D
            ) {
                if (CHOMPING_CLIP === chomping) {
                  chomping = ch === 0x2B
                  ? CHOMPING_KEEP : CHOMPING_STRIP;
                } else {
                  throwError(state, 'repeat of a chomping mode identifier');
                }
              } else if ((tmp = fromDecimalCode(ch)) >= 0) {
              if (tmp === 0) {
                throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one');
              } else if (!detectedIndent) {
                textIndent = nodeIndent + tmp - 1;
                detectedIndent = true;
              } else {
                throwError(state, 'repeat of an indentation width identifier');
              }
            } else {
              break;
            }
          }
          if (is_WHITE_SPACE(ch)) {
            do {
              ch = state.input.charCodeAt(++state.position);
            } while (is_WHITE_SPACE(ch));
            if (ch === 0x23
            ) {
                do {
                  ch = state.input.charCodeAt(++state.position);
                } while (!is_EOL(ch) && ch !== 0);
              }
          }
          while (ch !== 0) {
            readLineBreak(state);
            state.lineIndent = 0;
            ch = state.input.charCodeAt(state.position);
            while ((!detectedIndent || state.lineIndent < textIndent) && ch === 0x20
            ) {
              state.lineIndent++;
              ch = state.input.charCodeAt(++state.position);
            }
            if (!detectedIndent && state.lineIndent > textIndent) {
              textIndent = state.lineIndent;
            }
            if (is_EOL(ch)) {
              emptyLines++;
              continue;
            }
            if (state.lineIndent < textIndent) {
              if (chomping === CHOMPING_KEEP) {
                state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines);
              } else if (chomping === CHOMPING_CLIP) {
                if (didReadContent) {
                  state.result += '\n';
                }
              }
              break;
            }
            if (folding) {
              if (is_WHITE_SPACE(ch)) {
                atMoreIndented = true;
                state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines);
              } else if (atMoreIndented) {
                atMoreIndented = false;
                state.result += common.repeat('\n', emptyLines + 1);
              } else if (emptyLines === 0) {
                if (didReadContent) {
                  state.result += ' ';
                }
              } else {
                state.result += common.repeat('\n', emptyLines);
              }
            } else {
              state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines);
            }
            didReadContent = true;
            detectedIndent = true;
            emptyLines = 0;
            captureStart = state.position;
            while (!is_EOL(ch) && ch !== 0) {
              ch = state.input.charCodeAt(++state.position);
            }
            captureSegment(state, captureStart, state.position, false);
          }
          return true;
        }
        function readBlockSequence(state, nodeIndent) {
          var _line,
              _tag = state.tag,
              _anchor = state.anchor,
              _result = [],
              following,
              detected = false,
              ch;
          if (state.anchor !== null) {
            state.anchorMap[state.anchor] = _result;
          }
          ch = state.input.charCodeAt(state.position);
          while (ch !== 0) {
            if (ch !== 0x2D
            ) {
                break;
              }
            following = state.input.charCodeAt(state.position + 1);
            if (!is_WS_OR_EOL(following)) {
              break;
            }
            detected = true;
            state.position++;
            if (skipSeparationSpace(state, true, -1)) {
              if (state.lineIndent <= nodeIndent) {
                _result.push(null);
                ch = state.input.charCodeAt(state.position);
                continue;
              }
            }
            _line = state.line;
            composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true);
            _result.push(state.result);
            skipSeparationSpace(state, true, -1);
            ch = state.input.charCodeAt(state.position);
            if ((state.line === _line || state.lineIndent > nodeIndent) && ch !== 0) {
              throwError(state, 'bad indentation of a sequence entry');
            } else if (state.lineIndent < nodeIndent) {
              break;
            }
          }
          if (detected) {
            state.tag = _tag;
            state.anchor = _anchor;
            state.kind = 'sequence';
            state.result = _result;
            return true;
          }
          return false;
        }
        function readBlockMapping(state, nodeIndent, flowIndent) {
          var following,
              allowCompact,
              _line,
              _pos,
              _tag = state.tag,
              _anchor = state.anchor,
              _result = {},
              overridableKeys = {},
              keyTag = null,
              keyNode = null,
              valueNode = null,
              atExplicitKey = false,
              detected = false,
              ch;
          if (state.anchor !== null) {
            state.anchorMap[state.anchor] = _result;
          }
          ch = state.input.charCodeAt(state.position);
          while (ch !== 0) {
            following = state.input.charCodeAt(state.position + 1);
            _line = state.line;
            _pos = state.position;
            if ((ch === 0x3F
            || ch === 0x3A
            ) && is_WS_OR_EOL(following)) {
              if (ch === 0x3F
              ) {
                  if (atExplicitKey) {
                    storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
                    keyTag = keyNode = valueNode = null;
                  }
                  detected = true;
                  atExplicitKey = true;
                  allowCompact = true;
                } else if (atExplicitKey) {
                atExplicitKey = false;
                allowCompact = true;
              } else {
                throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line');
              }
              state.position += 1;
              ch = following;
            } else if (composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) {
              if (state.line === _line) {
                ch = state.input.charCodeAt(state.position);
                while (is_WHITE_SPACE(ch)) {
                  ch = state.input.charCodeAt(++state.position);
                }
                if (ch === 0x3A
                ) {
                    ch = state.input.charCodeAt(++state.position);
                    if (!is_WS_OR_EOL(ch)) {
                      throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping');
                    }
                    if (atExplicitKey) {
                      storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
                      keyTag = keyNode = valueNode = null;
                    }
                    detected = true;
                    atExplicitKey = false;
                    allowCompact = false;
                    keyTag = state.tag;
                    keyNode = state.result;
                  } else if (detected) {
                  throwError(state, 'can not read an implicit mapping pair; a colon is missed');
                } else {
                  state.tag = _tag;
                  state.anchor = _anchor;
                  return true;
                }
              } else if (detected) {
                throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key');
              } else {
                state.tag = _tag;
                state.anchor = _anchor;
                return true;
              }
            } else {
                break;
              }
            if (state.line === _line || state.lineIndent > nodeIndent) {
              if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) {
                if (atExplicitKey) {
                  keyNode = state.result;
                } else {
                  valueNode = state.result;
                }
              }
              if (!atExplicitKey) {
                storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _pos);
                keyTag = keyNode = valueNode = null;
              }
              skipSeparationSpace(state, true, -1);
              ch = state.input.charCodeAt(state.position);
            }
            if (state.lineIndent > nodeIndent && ch !== 0) {
              throwError(state, 'bad indentation of a mapping entry');
            } else if (state.lineIndent < nodeIndent) {
              break;
            }
          }
          if (atExplicitKey) {
            storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null);
          }
          if (detected) {
            state.tag = _tag;
            state.anchor = _anchor;
            state.kind = 'mapping';
            state.result = _result;
          }
          return detected;
        }
        function readTagProperty(state) {
          var _position,
              isVerbatim = false,
              isNamed = false,
              tagHandle,
              tagName,
              ch;
          ch = state.input.charCodeAt(state.position);
          if (ch !== 0x21
          ) return false;
          if (state.tag !== null) {
            throwError(state, 'duplication of a tag property');
          }
          ch = state.input.charCodeAt(++state.position);
          if (ch === 0x3C
          ) {
              isVerbatim = true;
              ch = state.input.charCodeAt(++state.position);
            } else if (ch === 0x21
          ) {
              isNamed = true;
              tagHandle = '!!';
              ch = state.input.charCodeAt(++state.position);
            } else {
            tagHandle = '!';
          }
          _position = state.position;
          if (isVerbatim) {
            do {
              ch = state.input.charCodeAt(++state.position);
            } while (ch !== 0 && ch !== 0x3E
            );
            if (state.position < state.length) {
              tagName = state.input.slice(_position, state.position);
              ch = state.input.charCodeAt(++state.position);
            } else {
              throwError(state, 'unexpected end of the stream within a verbatim tag');
            }
          } else {
            while (ch !== 0 && !is_WS_OR_EOL(ch)) {
              if (ch === 0x21
              ) {
                  if (!isNamed) {
                    tagHandle = state.input.slice(_position - 1, state.position + 1);
                    if (!PATTERN_TAG_HANDLE.test(tagHandle)) {
                      throwError(state, 'named tag handle cannot contain such characters');
                    }
                    isNamed = true;
                    _position = state.position + 1;
                  } else {
                    throwError(state, 'tag suffix cannot contain exclamation marks');
                  }
                }
              ch = state.input.charCodeAt(++state.position);
            }
            tagName = state.input.slice(_position, state.position);
            if (PATTERN_FLOW_INDICATORS.test(tagName)) {
              throwError(state, 'tag suffix cannot contain flow indicator characters');
            }
          }
          if (tagName && !PATTERN_TAG_URI.test(tagName)) {
            throwError(state, 'tag name cannot contain such characters: ' + tagName);
          }
          if (isVerbatim) {
            state.tag = tagName;
          } else if (_hasOwnProperty$2.call(state.tagMap, tagHandle)) {
            state.tag = state.tagMap[tagHandle] + tagName;
          } else if (tagHandle === '!') {
            state.tag = '!' + tagName;
          } else if (tagHandle === '!!') {
            state.tag = 'tag:yaml.org,2002:' + tagName;
          } else {
            throwError(state, 'undeclared tag handle "' + tagHandle + '"');
          }
          return true;
        }
        function readAnchorProperty(state) {
          var _position, ch;
          ch = state.input.charCodeAt(state.position);
          if (ch !== 0x26
          ) return false;
          if (state.anchor !== null) {
            throwError(state, 'duplication of an anchor property');
          }
          ch = state.input.charCodeAt(++state.position);
          _position = state.position;
          while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
            ch = state.input.charCodeAt(++state.position);
          }
          if (state.position === _position) {
            throwError(state, 'name of an anchor node must contain at least one character');
          }
          state.anchor = state.input.slice(_position, state.position);
          return true;
        }
        function readAlias(state) {
          var _position, alias, ch;
          ch = state.input.charCodeAt(state.position);
          if (ch !== 0x2A
          ) return false;
          ch = state.input.charCodeAt(++state.position);
          _position = state.position;
          while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) {
            ch = state.input.charCodeAt(++state.position);
          }
          if (state.position === _position) {
            throwError(state, 'name of an alias node must contain at least one character');
          }
          alias = state.input.slice(_position, state.position);
          if (!_hasOwnProperty$2.call(state.anchorMap, alias)) {
            throwError(state, 'unidentified alias "' + alias + '"');
          }
          state.result = state.anchorMap[alias];
          skipSeparationSpace(state, true, -1);
          return true;
        }
        function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) {
          var allowBlockStyles,
              allowBlockScalars,
              allowBlockCollections,
              indentStatus = 1,
          atNewLine = false,
              hasContent = false,
              typeIndex,
              typeQuantity,
              type,
              flowIndent,
              blockIndent;
          if (state.listener !== null) {
            state.listener('open', state);
          }
          state.tag = null;
          state.anchor = null;
          state.kind = null;
          state.result = null;
          allowBlockStyles = allowBlockScalars = allowBlockCollections = CONTEXT_BLOCK_OUT === nodeContext || CONTEXT_BLOCK_IN === nodeContext;
          if (allowToSeek) {
            if (skipSeparationSpace(state, true, -1)) {
              atNewLine = true;
              if (state.lineIndent > parentIndent) {
                indentStatus = 1;
              } else if (state.lineIndent === parentIndent) {
                indentStatus = 0;
              } else if (state.lineIndent < parentIndent) {
                indentStatus = -1;
              }
            }
          }
          if (indentStatus === 1) {
            while (readTagProperty(state) || readAnchorProperty(state)) {
              if (skipSeparationSpace(state, true, -1)) {
                atNewLine = true;
                allowBlockCollections = allowBlockStyles;
                if (state.lineIndent > parentIndent) {
                  indentStatus = 1;
                } else if (state.lineIndent === parentIndent) {
                  indentStatus = 0;
                } else if (state.lineIndent < parentIndent) {
                  indentStatus = -1;
                }
              } else {
                allowBlockCollections = false;
              }
            }
          }
          if (allowBlockCollections) {
            allowBlockCollections = atNewLine || allowCompact;
          }
          if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) {
            if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) {
              flowIndent = parentIndent;
            } else {
              flowIndent = parentIndent + 1;
            }
            blockIndent = state.position - state.lineStart;
            if (indentStatus === 1) {
              if (allowBlockCollections && (readBlockSequence(state, blockIndent) || readBlockMapping(state, blockIndent, flowIndent)) || readFlowCollection(state, flowIndent)) {
                hasContent = true;
              } else {
                if (allowBlockScalars && readBlockScalar(state, flowIndent) || readSingleQuotedScalar(state, flowIndent) || readDoubleQuotedScalar(state, flowIndent)) {
                  hasContent = true;
                } else if (readAlias(state)) {
                  hasContent = true;
                  if (state.tag !== null || state.anchor !== null) {
                    throwError(state, 'alias node should not have any properties');
                  }
                } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) {
                  hasContent = true;
                  if (state.tag === null) {
                    state.tag = '?';
                  }
                }
                if (state.anchor !== null) {
                  state.anchorMap[state.anchor] = state.result;
                }
              }
            } else if (indentStatus === 0) {
              hasContent = allowBlockCollections && readBlockSequence(state, blockIndent);
            }
          }
          if (state.tag !== null && state.tag !== '!') {
            if (state.tag === '?') {
              if (state.result !== null && state.kind !== 'scalar') {
                throwError(state, 'unacceptable node kind for !<?> tag; it should be "scalar", not "' + state.kind + '"');
              }
              for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {
                type = state.implicitTypes[typeIndex];
                if (type.resolve(state.result)) {
                  state.result = type.construct(state.result);
                  state.tag = type.tag;
                  if (state.anchor !== null) {
                    state.anchorMap[state.anchor] = state.result;
                  }
                  break;
                }
              }
            } else if (_hasOwnProperty$2.call(state.typeMap[state.kind || 'fallback'], state.tag)) {
              type = state.typeMap[state.kind || 'fallback'][state.tag];
              if (state.result !== null && type.kind !== state.kind) {
                throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"');
              }
              if (!type.resolve(state.result)) {
                throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag');
              } else {
                state.result = type.construct(state.result);
                if (state.anchor !== null) {
                  state.anchorMap[state.anchor] = state.result;
                }
              }
            } else {
              throwError(state, 'unknown tag !<' + state.tag + '>');
            }
          }
          if (state.listener !== null) {
            state.listener('close', state);
          }
          return state.tag !== null || state.anchor !== null || hasContent;
        }
        function readDocument(state) {
          var documentStart = state.position,
              _position,
              directiveName,
              directiveArgs,
              hasDirectives = false,
              ch;
          state.version = null;
          state.checkLineBreaks = state.legacy;
          state.tagMap = {};
          state.anchorMap = {};
          while ((ch = state.input.charCodeAt(state.position)) !== 0) {
            skipSeparationSpace(state, true, -1);
            ch = state.input.charCodeAt(state.position);
            if (state.lineIndent > 0 || ch !== 0x25
            ) {
                break;
              }
            hasDirectives = true;
            ch = state.input.charCodeAt(++state.position);
            _position = state.position;
            while (ch !== 0 && !is_WS_OR_EOL(ch)) {
              ch = state.input.charCodeAt(++state.position);
            }
            directiveName = state.input.slice(_position, state.position);
            directiveArgs = [];
            if (directiveName.length < 1) {
              throwError(state, 'directive name must not be less than one character in length');
            }
            while (ch !== 0) {
              while (is_WHITE_SPACE(ch)) {
                ch = state.input.charCodeAt(++state.position);
              }
              if (ch === 0x23
              ) {
                  do {
                    ch = state.input.charCodeAt(++state.position);
                  } while (ch !== 0 && !is_EOL(ch));
                  break;
                }
              if (is_EOL(ch)) break;
              _position = state.position;
              while (ch !== 0 && !is_WS_OR_EOL(ch)) {
                ch = state.input.charCodeAt(++state.position);
              }
              directiveArgs.push(state.input.slice(_position, state.position));
            }
            if (ch !== 0) readLineBreak(state);
            if (_hasOwnProperty$2.call(directiveHandlers, directiveName)) {
              directiveHandlers[directiveName](state, directiveName, directiveArgs);
            } else {
              throwWarning(state, 'unknown document directive "' + directiveName + '"');
            }
          }
          skipSeparationSpace(state, true, -1);
          if (state.lineIndent === 0 && state.input.charCodeAt(state.position) === 0x2D
          && state.input.charCodeAt(state.position + 1) === 0x2D
          && state.input.charCodeAt(state.position + 2) === 0x2D
          ) {
              state.position += 3;
              skipSeparationSpace(state, true, -1);
            } else if (hasDirectives) {
            throwError(state, 'directives end mark is expected');
          }
          composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true);
          skipSeparationSpace(state, true, -1);
          if (state.checkLineBreaks && PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) {
            throwWarning(state, 'non-ASCII line breaks are interpreted as content');
          }
          state.documents.push(state.result);
          if (state.position === state.lineStart && testDocumentSeparator(state)) {
            if (state.input.charCodeAt(state.position) === 0x2E
            ) {
                state.position += 3;
                skipSeparationSpace(state, true, -1);
              }
            return;
          }
          if (state.position < state.length - 1) {
            throwError(state, 'end of the stream or a document separator is expected');
          } else {
            return;
          }
        }
        function loadDocuments(input, options) {
          input = String(input);
          options = options || {};
          if (input.length !== 0) {
            if (input.charCodeAt(input.length - 1) !== 0x0A
            && input.charCodeAt(input.length - 1) !== 0x0D
            ) {
                input += '\n';
              }
            if (input.charCodeAt(0) === 0xFEFF) {
              input = input.slice(1);
            }
          }
          var state = new State(input, options);
          var nullpos = input.indexOf('\0');
          if (nullpos !== -1) {
            state.position = nullpos;
            throwError(state, 'null byte is not allowed in input');
          }
          state.input += '\0';
          while (state.input.charCodeAt(state.position) === 0x20
          ) {
            state.lineIndent += 1;
            state.position += 1;
          }
          while (state.position < state.length - 1) {
            readDocument(state);
          }
          return state.documents;
        }
        function loadAll(input, iterator, options) {
          if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') {
            options = iterator;
            iterator = null;
          }
          var documents = loadDocuments(input, options);
          if (typeof iterator !== 'function') {
            return documents;
          }
          for (var index = 0, length = documents.length; index < length; index += 1) {
            iterator(documents[index]);
          }
        }
        function load(input, options) {
          var documents = loadDocuments(input, options);
          if (documents.length === 0) {
            return undefined;
          } else if (documents.length === 1) {
            return documents[0];
          }
          throw new exception('expected a single document in the stream, but found more');
        }
        function safeLoadAll(input, iterator, options) {
          if (typeof iterator === 'object' && iterator !== null && typeof options === 'undefined') {
            options = iterator;
            iterator = null;
          }
          return loadAll(input, iterator, common.extend({
            schema: default_safe
          }, options));
        }
        function safeLoad(input, options) {
          return load(input, common.extend({
            schema: default_safe
          }, options));
        }
        var loadAll_1 = loadAll;
        var load_1 = load;
        var safeLoadAll_1 = safeLoadAll;
        var safeLoad_1 = safeLoad;
        var loader = {
          loadAll: loadAll_1,
          load: load_1,
          safeLoadAll: safeLoadAll_1,
          safeLoad: safeLoad_1
        };
        var _toString$2 = Object.prototype.toString;
        var _hasOwnProperty$3 = Object.prototype.hasOwnProperty;
        var CHAR_TAB = 0x09;
        var CHAR_LINE_FEED = 0x0A;
        var CHAR_CARRIAGE_RETURN = 0x0D;
        var CHAR_SPACE = 0x20;
        var CHAR_EXCLAMATION = 0x21;
        var CHAR_DOUBLE_QUOTE = 0x22;
        var CHAR_SHARP = 0x23;
        var CHAR_PERCENT = 0x25;
        var CHAR_AMPERSAND = 0x26;
        var CHAR_SINGLE_QUOTE = 0x27;
        var CHAR_ASTERISK = 0x2A;
        var CHAR_COMMA = 0x2C;
        var CHAR_MINUS = 0x2D;
        var CHAR_COLON = 0x3A;
        var CHAR_EQUALS = 0x3D;
        var CHAR_GREATER_THAN = 0x3E;
        var CHAR_QUESTION = 0x3F;
        var CHAR_COMMERCIAL_AT = 0x40;
        var CHAR_LEFT_SQUARE_BRACKET = 0x5B;
        var CHAR_RIGHT_SQUARE_BRACKET = 0x5D;
        var CHAR_GRAVE_ACCENT = 0x60;
        var CHAR_LEFT_CURLY_BRACKET = 0x7B;
        var CHAR_VERTICAL_LINE = 0x7C;
        var CHAR_RIGHT_CURLY_BRACKET = 0x7D;
        var ESCAPE_SEQUENCES = {};
        ESCAPE_SEQUENCES[0x00] = '\\0';
        ESCAPE_SEQUENCES[0x07] = '\\a';
        ESCAPE_SEQUENCES[0x08] = '\\b';
        ESCAPE_SEQUENCES[0x09] = '\\t';
        ESCAPE_SEQUENCES[0x0A] = '\\n';
        ESCAPE_SEQUENCES[0x0B] = '\\v';
        ESCAPE_SEQUENCES[0x0C] = '\\f';
        ESCAPE_SEQUENCES[0x0D] = '\\r';
        ESCAPE_SEQUENCES[0x1B] = '\\e';
        ESCAPE_SEQUENCES[0x22] = '\\"';
        ESCAPE_SEQUENCES[0x5C] = '\\\\';
        ESCAPE_SEQUENCES[0x85] = '\\N';
        ESCAPE_SEQUENCES[0xA0] = '\\_';
        ESCAPE_SEQUENCES[0x2028] = '\\L';
        ESCAPE_SEQUENCES[0x2029] = '\\P';
        var DEPRECATED_BOOLEANS_SYNTAX = ['y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'];
        function compileStyleMap(schema, map) {
          var result, keys, index, length, tag, style, type;
          if (map === null) return {};
          result = {};
          keys = Object.keys(map);
          for (index = 0, length = keys.length; index < length; index += 1) {
            tag = keys[index];
            style = String(map[tag]);
            if (tag.slice(0, 2) === '!!') {
              tag = 'tag:yaml.org,2002:' + tag.slice(2);
            }
            type = schema.compiledTypeMap['fallback'][tag];
            if (type && _hasOwnProperty$3.call(type.styleAliases, style)) {
              style = type.styleAliases[style];
            }
            result[tag] = style;
          }
          return result;
        }
        function encodeHex(character) {
          var string, handle, length;
          string = character.toString(16).toUpperCase();
          if (character <= 0xFF) {
            handle = 'x';
            length = 2;
          } else if (character <= 0xFFFF) {
            handle = 'u';
            length = 4;
          } else if (character <= 0xFFFFFFFF) {
            handle = 'U';
            length = 8;
          } else {
            throw new exception('code point within a string may not be greater than 0xFFFFFFFF');
          }
          return '\\' + handle + common.repeat('0', length - string.length) + string;
        }
        function State$1(options) {
          this.schema = options['schema'] || default_full;
          this.indent = Math.max(1, options['indent'] || 2);
          this.noArrayIndent = options['noArrayIndent'] || false;
          this.skipInvalid = options['skipInvalid'] || false;
          this.flowLevel = common.isNothing(options['flowLevel']) ? -1 : options['flowLevel'];
          this.styleMap = compileStyleMap(this.schema, options['styles'] || null);
          this.sortKeys = options['sortKeys'] || false;
          this.lineWidth = options['lineWidth'] || 80;
          this.noRefs = options['noRefs'] || false;
          this.noCompatMode = options['noCompatMode'] || false;
          this.condenseFlow = options['condenseFlow'] || false;
          this.implicitTypes = this.schema.compiledImplicit;
          this.explicitTypes = this.schema.compiledExplicit;
          this.tag = null;
          this.result = '';
          this.duplicates = [];
          this.usedDuplicates = null;
        }
        function indentString(string, spaces) {
          var ind = common.repeat(' ', spaces),
              position = 0,
              next = -1,
              result = '',
              line,
              length = string.length;
          while (position < length) {
            next = string.indexOf('\n', position);
            if (next === -1) {
              line = string.slice(position);
              position = length;
            } else {
              line = string.slice(position, next + 1);
              position = next + 1;
            }
            if (line.length && line !== '\n') result += ind;
            result += line;
          }
          return result;
        }
        function generateNextLine(state, level) {
          return '\n' + common.repeat(' ', state.indent * level);
        }
        function testImplicitResolving(state, str) {
          var index, length, type;
          for (index = 0, length = state.implicitTypes.length; index < length; index += 1) {
            type = state.implicitTypes[index];
            if (type.resolve(str)) {
              return true;
            }
          }
          return false;
        }
        function isWhitespace(c) {
          return c === CHAR_SPACE || c === CHAR_TAB;
        }
        function isPrintable(c) {
          return 0x00020 <= c && c <= 0x00007E || 0x000A1 <= c && c <= 0x00D7FF && c !== 0x2028 && c !== 0x2029 || 0x0E000 <= c && c <= 0x00FFFD && c !== 0xFEFF
          || 0x10000 <= c && c <= 0x10FFFF;
        }
        function isNsChar(c) {
          return isPrintable(c) && !isWhitespace(c)
          && c !== 0xFEFF
          && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED;
        }
        function isPlainSafe(c, prev) {
          return isPrintable(c) && c !== 0xFEFF
          && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET
          && c !== CHAR_COLON && (c !== CHAR_SHARP || prev && isNsChar(prev));
        }
        function isPlainSafeFirst(c) {
          return isPrintable(c) && c !== 0xFEFF && !isWhitespace(c)
          && c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET
          && c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE
          && c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT;
        }
        function needIndentIndicator(string) {
          var leadingSpaceRe = /^\n* /;
          return leadingSpaceRe.test(string);
        }
        var STYLE_PLAIN = 1,
            STYLE_SINGLE = 2,
            STYLE_LITERAL = 3,
            STYLE_FOLDED = 4,
            STYLE_DOUBLE = 5;
        function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) {
          var i;
          var char, prev_char;
          var hasLineBreak = false;
          var hasFoldableLine = false;
          var shouldTrackWidth = lineWidth !== -1;
          var previousLineBreak = -1;
          var plain = isPlainSafeFirst(string.charCodeAt(0)) && !isWhitespace(string.charCodeAt(string.length - 1));
          if (singleLineOnly) {
            for (i = 0; i < string.length; i++) {
              char = string.charCodeAt(i);
              if (!isPrintable(char)) {
                return STYLE_DOUBLE;
              }
              prev_char = i > 0 ? string.charCodeAt(i - 1) : null;
              plain = plain && isPlainSafe(char, prev_char);
            }
          } else {
            for (i = 0; i < string.length; i++) {
              char = string.charCodeAt(i);
              if (char === CHAR_LINE_FEED) {
                hasLineBreak = true;
                if (shouldTrackWidth) {
                  hasFoldableLine = hasFoldableLine ||
                  i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' ';
                  previousLineBreak = i;
                }
              } else if (!isPrintable(char)) {
                return STYLE_DOUBLE;
              }
              prev_char = i > 0 ? string.charCodeAt(i - 1) : null;
              plain = plain && isPlainSafe(char, prev_char);
            }
            hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1] !== ' ';
          }
          if (!hasLineBreak && !hasFoldableLine) {
            return plain && !testAmbiguousType(string) ? STYLE_PLAIN : STYLE_SINGLE;
          }
          if (indentPerLevel > 9 && needIndentIndicator(string)) {
            return STYLE_DOUBLE;
          }
          return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL;
        }
        function writeScalar(state, string, level, iskey) {
          state.dump = function () {
            if (string.length === 0) {
              return "''";
            }
            if (!state.noCompatMode && DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) {
              return "'" + string + "'";
            }
            var indent = state.indent * Math.max(1, level);
            var lineWidth = state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent);
            var singleLineOnly = iskey
            || state.flowLevel > -1 && level >= state.flowLevel;
            function testAmbiguity(string) {
              return testImplicitResolving(state, string);
            }
            switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) {
              case STYLE_PLAIN:
                return string;
              case STYLE_SINGLE:
                return "'" + string.replace(/'/g, "''") + "'";
              case STYLE_LITERAL:
                return '|' + blockHeader(string, state.indent) + dropEndingNewline(indentString(string, indent));
              case STYLE_FOLDED:
                return '>' + blockHeader(string, state.indent) + dropEndingNewline(indentString(foldString(string, lineWidth), indent));
              case STYLE_DOUBLE:
                return '"' + escapeString(string) + '"';
              default:
                throw new exception('impossible error: invalid scalar style');
            }
          }();
        }
        function blockHeader(string, indentPerLevel) {
          var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : '';
          var clip = string[string.length - 1] === '\n';
          var keep = clip && (string[string.length - 2] === '\n' || string === '\n');
          var chomp = keep ? '+' : clip ? '' : '-';
          return indentIndicator + chomp + '\n';
        }
        function dropEndingNewline(string) {
          return string[string.length - 1] === '\n' ? string.slice(0, -1) : string;
        }
        function foldString(string, width) {
          var lineRe = /(\n+)([^\n]*)/g;
          var result = function () {
            var nextLF = string.indexOf('\n');
            nextLF = nextLF !== -1 ? nextLF : string.length;
            lineRe.lastIndex = nextLF;
            return foldLine(string.slice(0, nextLF), width);
          }();
          var prevMoreIndented = string[0] === '\n' || string[0] === ' ';
          var moreIndented;
          var match;
          while (match = lineRe.exec(string)) {
            var prefix = match[1],
                line = match[2];
            moreIndented = line[0] === ' ';
            result += prefix + (!prevMoreIndented && !moreIndented && line !== '' ? '\n' : '') + foldLine(line, width);
            prevMoreIndented = moreIndented;
          }
          return result;
        }
        function foldLine(line, width) {
          if (line === '' || line[0] === ' ') return line;
          var breakRe = / [^ ]/g;
          var match;
          var start = 0,
              end,
              curr = 0,
              next = 0;
          var result = '';
          while (match = breakRe.exec(line)) {
            next = match.index;
            if (next - start > width) {
              end = curr > start ? curr : next;
              result += '\n' + line.slice(start, end);
              start = end + 1;
            }
            curr = next;
          }
          result += '\n';
          if (line.length - start > width && curr > start) {
            result += line.slice(start, curr) + '\n' + line.slice(curr + 1);
          } else {
            result += line.slice(start);
          }
          return result.slice(1);
        }
        function escapeString(string) {
          var result = '';
          var char, nextChar;
          var escapeSeq;
          for (var i = 0; i < string.length; i++) {
            char = string.charCodeAt(i);
            if (char >= 0xD800 && char <= 0xDBFF
            ) {
                nextChar = string.charCodeAt(i + 1);
                if (nextChar >= 0xDC00 && nextChar <= 0xDFFF
                ) {
                    result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000);
                    i++;
                    continue;
                  }
              }
            escapeSeq = ESCAPE_SEQUENCES[char];
            result += !escapeSeq && isPrintable(char) ? string[i] : escapeSeq || encodeHex(char);
          }
          return result;
        }
        function writeFlowSequence(state, level, object) {
          var _result = '',
              _tag = state.tag,
              index,
              length;
          for (index = 0, length = object.length; index < length; index += 1) {
            if (writeNode(state, level, object[index], false, false)) {
              if (index !== 0) _result += ',' + (!state.condenseFlow ? ' ' : '');
              _result += state.dump;
            }
          }
          state.tag = _tag;
          state.dump = '[' + _result + ']';
        }
        function writeBlockSequence(state, level, object, compact) {
          var _result = '',
              _tag = state.tag,
              index,
              length;
          for (index = 0, length = object.length; index < length; index += 1) {
            if (writeNode(state, level + 1, object[index], true, true)) {
              if (!compact || index !== 0) {
                _result += generateNextLine(state, level);
              }
              if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
                _result += '-';
              } else {
                _result += '- ';
              }
              _result += state.dump;
            }
          }
          state.tag = _tag;
          state.dump = _result || '[]';
        }
        function writeFlowMapping(state, level, object) {
          var _result = '',
              _tag = state.tag,
              objectKeyList = Object.keys(object),
              index,
              length,
              objectKey,
              objectValue,
              pairBuffer;
          for (index = 0, length = objectKeyList.length; index < length; index += 1) {
            pairBuffer = '';
            if (index !== 0) pairBuffer += ', ';
            if (state.condenseFlow) pairBuffer += '"';
            objectKey = objectKeyList[index];
            objectValue = object[objectKey];
            if (!writeNode(state, level, objectKey, false, false)) {
              continue;
            }
            if (state.dump.length > 1024) pairBuffer += '? ';
            pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' ');
            if (!writeNode(state, level, objectValue, false, false)) {
              continue;
            }
            pairBuffer += state.dump;
            _result += pairBuffer;
          }
          state.tag = _tag;
          state.dump = '{' + _result + '}';
        }
        function writeBlockMapping(state, level, object, compact) {
          var _result = '',
              _tag = state.tag,
              objectKeyList = Object.keys(object),
              index,
              length,
              objectKey,
              objectValue,
              explicitPair,
              pairBuffer;
          if (state.sortKeys === true) {
            objectKeyList.sort();
          } else if (typeof state.sortKeys === 'function') {
            objectKeyList.sort(state.sortKeys);
          } else if (state.sortKeys) {
            throw new exception('sortKeys must be a boolean or a function');
          }
          for (index = 0, length = objectKeyList.length; index < length; index += 1) {
            pairBuffer = '';
            if (!compact || index !== 0) {
              pairBuffer += generateNextLine(state, level);
            }
            objectKey = objectKeyList[index];
            objectValue = object[objectKey];
            if (!writeNode(state, level + 1, objectKey, true, true, true)) {
              continue;
            }
            explicitPair = state.tag !== null && state.tag !== '?' || state.dump && state.dump.length > 1024;
            if (explicitPair) {
              if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
                pairBuffer += '?';
              } else {
                pairBuffer += '? ';
              }
            }
            pairBuffer += state.dump;
            if (explicitPair) {
              pairBuffer += generateNextLine(state, level);
            }
            if (!writeNode(state, level + 1, objectValue, true, explicitPair)) {
              continue;
            }
            if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) {
              pairBuffer += ':';
            } else {
              pairBuffer += ': ';
            }
            pairBuffer += state.dump;
            _result += pairBuffer;
          }
          state.tag = _tag;
          state.dump = _result || '{}';
        }
        function detectType(state, object, explicit) {
          var _result, typeList, index, length, type, style;
          typeList = explicit ? state.explicitTypes : state.implicitTypes;
          for (index = 0, length = typeList.length; index < length; index += 1) {
            type = typeList[index];
            if ((type.instanceOf || type.predicate) && (!type.instanceOf || typeof object === 'object' && object instanceof type.instanceOf) && (!type.predicate || type.predicate(object))) {
              state.tag = explicit ? type.tag : '?';
              if (type.represent) {
                style = state.styleMap[type.tag] || type.defaultStyle;
                if (_toString$2.call(type.represent) === '[object Function]') {
                  _result = type.represent(object, style);
                } else if (_hasOwnProperty$3.call(type.represent, style)) {
                  _result = type.represent[style](object, style);
                } else {
                  throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
                }
                state.dump = _result;
              }
              return true;
            }
          }
          return false;
        }
        function writeNode(state, level, object, block, compact, iskey) {
          state.tag = null;
          state.dump = object;
          if (!detectType(state, object, false)) {
            detectType(state, object, true);
          }
          var type = _toString$2.call(state.dump);
          if (block) {
            block = state.flowLevel < 0 || state.flowLevel > level;
          }
          var objectOrArray = type === '[object Object]' || type === '[object Array]',
              duplicateIndex,
              duplicate;
          if (objectOrArray) {
            duplicateIndex = state.duplicates.indexOf(object);
            duplicate = duplicateIndex !== -1;
          }
          if (state.tag !== null && state.tag !== '?' || duplicate || state.indent !== 2 && level > 0) {
            compact = false;
          }
          if (duplicate && state.usedDuplicates[duplicateIndex]) {
            state.dump = '*ref_' + duplicateIndex;
          } else {
            if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) {
              state.usedDuplicates[duplicateIndex] = true;
            }
            if (type === '[object Object]') {
              if (block && Object.keys(state.dump).length !== 0) {
                writeBlockMapping(state, level, state.dump, compact);
                if (duplicate) {
                  state.dump = '&ref_' + duplicateIndex + state.dump;
                }
              } else {
                writeFlowMapping(state, level, state.dump);
                if (duplicate) {
                  state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
                }
              }
            } else if (type === '[object Array]') {
              var arrayLevel = state.noArrayIndent && level > 0 ? level - 1 : level;
              if (block && state.dump.length !== 0) {
                writeBlockSequence(state, arrayLevel, state.dump, compact);
                if (duplicate) {
                  state.dump = '&ref_' + duplicateIndex + state.dump;
                }
              } else {
                writeFlowSequence(state, arrayLevel, state.dump);
                if (duplicate) {
                  state.dump = '&ref_' + duplicateIndex + ' ' + state.dump;
                }
              }
            } else if (type === '[object String]') {
              if (state.tag !== '?') {
                writeScalar(state, state.dump, level, iskey);
              }
            } else {
              if (state.skipInvalid) return false;
              throw new exception('unacceptable kind of an object to dump ' + type);
            }
            if (state.tag !== null && state.tag !== '?') {
              state.dump = '!<' + state.tag + '> ' + state.dump;
            }
          }
          return true;
        }
        function getDuplicateReferences(object, state) {
          var objects = [],
              duplicatesIndexes = [],
              index,
              length;
          inspectNode(object, objects, duplicatesIndexes);
          for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) {
            state.duplicates.push(objects[duplicatesIndexes[index]]);
          }
          state.usedDuplicates = new Array(length);
        }
        function inspectNode(object, objects, duplicatesIndexes) {
          var objectKeyList, index, length;
          if (object !== null && typeof object === 'object') {
            index = objects.indexOf(object);
            if (index !== -1) {
              if (duplicatesIndexes.indexOf(index) === -1) {
                duplicatesIndexes.push(index);
              }
            } else {
              objects.push(object);
              if (Array.isArray(object)) {
                for (index = 0, length = object.length; index < length; index += 1) {
                  inspectNode(object[index], objects, duplicatesIndexes);
                }
              } else {
                objectKeyList = Object.keys(object);
                for (index = 0, length = objectKeyList.length; index < length; index += 1) {
                  inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes);
                }
              }
            }
          }
        }
        function dump(input, options) {
          options = options || {};
          var state = new State$1(options);
          if (!state.noRefs) getDuplicateReferences(input, state);
          if (writeNode(state, 0, input, true, true)) return state.dump + '\n';
          return '';
        }
        function safeDump(input, options) {
          return dump(input, common.extend({
            schema: default_safe
          }, options));
        }
        var dump_1 = dump;
        var safeDump_1 = safeDump;
        var dumper = {
          dump: dump_1,
          safeDump: safeDump_1
        };
        function deprecated(name) {
          return function () {
            throw new Error('Function ' + name + ' is deprecated and cannot be used.');
          };
        }
        var Type$1 = type;
        var Schema$1 = schema;
        var FAILSAFE_SCHEMA = failsafe;
        var JSON_SCHEMA = json;
        var CORE_SCHEMA = core;
        var DEFAULT_SAFE_SCHEMA = default_safe;
        var DEFAULT_FULL_SCHEMA = default_full;
        var load$1 = loader.load;
        var loadAll$1 = loader.loadAll;
        var safeLoad$1 = loader.safeLoad;
        var safeLoadAll$1 = loader.safeLoadAll;
        var dump$1 = dumper.dump;
        var safeDump$1 = dumper.safeDump;
        var YAMLException$1 = exception;
        var MINIMAL_SCHEMA = failsafe;
        var SAFE_SCHEMA = default_safe;
        var DEFAULT_SCHEMA = default_full;
        var scan = deprecated('scan');
        var parse = deprecated('parse');
        var compose = deprecated('compose');
        var addConstructor = deprecated('addConstructor');
        var jsYaml = {
          Type: Type$1,
          Schema: Schema$1,
          FAILSAFE_SCHEMA: FAILSAFE_SCHEMA,
          JSON_SCHEMA: JSON_SCHEMA,
          CORE_SCHEMA: CORE_SCHEMA,
          DEFAULT_SAFE_SCHEMA: DEFAULT_SAFE_SCHEMA,
          DEFAULT_FULL_SCHEMA: DEFAULT_FULL_SCHEMA,
          load: load$1,
          loadAll: loadAll$1,
          safeLoad: safeLoad$1,
          safeLoadAll: safeLoadAll$1,
          dump: dump$1,
          safeDump: safeDump$1,
          YAMLException: YAMLException$1,
          MINIMAL_SCHEMA: MINIMAL_SCHEMA,
          SAFE_SCHEMA: SAFE_SCHEMA,
          DEFAULT_SCHEMA: DEFAULT_SCHEMA,
          scan: scan,
          parse: parse,
          compose: compose,
          addConstructor: addConstructor
        };
        var jsYaml$1 = jsYaml;
        function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
        function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
        var Redirects = function () {
          function Redirects(rawYaml) {
            classCallCheck(this, Redirects);
            try {
              var arrOfRedirects = jsYaml$1.safeLoad(rawYaml);
              this.redirects = arrOfRedirects.reduce(function (acc, redirect) {
                return _objectSpread(_objectSpread({}, acc), {}, defineProperty({}, redirect.title, redirect));
              }, {});
            } catch (e) {
              console.log("Was unable to load YAML into JS due to: ".concat(e.message));
              throw e;
            }
          }
          createClass(Redirects, [{
            key: "getRedirect",
            value: function getRedirect(title) {
              var _this = this;
              if (Object.prototype.hasOwnProperty.call(this.redirects, title)) {
                return this.redirects[title];
              }
              var values = Object.keys(this.redirects).map(function (key) {
                return _this.redirects[key];
              });
              return values.find(function (redirect) {
                var aliases = redirect.aliases;
                if (!aliases) {
                  return false;
                }
                return aliases.indexOf(title) > -1;
              });
            }
          }]);
          return Redirects;
        }();
        var getRedirectByName = function getRedirectByName(name) {
          var redirects = Object.keys(redirectsList).map(function (key) {
            return redirectsList[key];
          });
          return redirects.find(function (r) {
            return r.names && r.names.indexOf(name) > -1;
          });
        };
        var getRedirectCode = function getRedirectCode(source) {
          var redirect = getRedirectByName(source.name);
          var result = attachDependencies(redirect);
          result = addCall(redirect, result);
          result = source.engine === 'test' ? wrapInNonameFunc(result) : passSourceAndProps(source, result);
          return result;
        };
        var redirectsCjs = {
          Redirects: Redirects,
          getCode: getRedirectCode,
          isAdgRedirectRule: validator.isAdgRedirectRule,
          isValidAdgRedirectRule: validator.isValidAdgRedirectRule,
          isAdgRedirectCompatibleWithUbo: validator.isAdgRedirectCompatibleWithUbo,
          isUboRedirectCompatibleWithAdg: validator.isUboRedirectCompatibleWithAdg,
          isAbpRedirectCompatibleWithAdg: validator.isAbpRedirectCompatibleWithAdg,
          convertUboRedirectToAdg: convertUboRedirectToAdg,
          convertAbpRedirectToAdg: convertAbpRedirectToAdg,
          convertRedirectToAdg: convertRedirectToAdg,
          convertAdgRedirectToUbo: convertAdgRedirectToUbo
        };
        function getScriptletCode(source) {
          if (!validator.isValidScriptletName(source.name)) {
            return null;
          }
          var scriptlet = validator.getScriptletByName(source.name);
          var result = attachDependencies(scriptlet);
          result = addCall(scriptlet, result);
          result = source.engine === 'corelibs' || source.engine === 'test' ? wrapInNonameFunc(result) : passSourceAndProps(source, result);
          return result;
        }
        var scriptletsObject = function () {
          return {
            invoke: getScriptletCode,
            isValidScriptletName: validator.isValidScriptletName,
            isValidScriptletRule: isValidScriptletRule,
            isAdgScriptletRule: validator.isAdgScriptletRule,
            isUboScriptletRule: validator.isUboScriptletRule,
            isAbpSnippetRule: validator.isAbpSnippetRule,
            convertUboToAdg: convertUboScriptletToAdg,
            convertAbpToAdg: convertAbpSnippetToAdg,
            convertScriptletToAdg: convertScriptletToAdg,
            convertAdgToUbo: convertAdgScriptletToUbo,
            redirects: redirectsCjs
          };
        }();
        scriptlets_umd.exports = scriptletsObject;
    })));
    var scriptlets = scriptlets_umd.exports;

    /* eslint-disable @typescript-eslint/no-explicit-any */
    /**
     * Scriptlets helper class
     */
    // eslint-disable-next-line max-classes-per-file
    var ScriptletParser = /** @class */ (function () {
        function ScriptletParser() {
        }
        /**
         * Iterate over iterable argument and evaluate current state with transitions
         *
         * @param {Array|Collection|string} iterable
         * @param {Object} transitions transition functions
         * @param {string} initState first transition name
         * @param {any} args arguments which should be passed to transition functions
         * @returns {string} transition
         */
        ScriptletParser.iterateWithTransitions = function (iterable, transitions, initState, args) {
            var state = initState;
            for (var i = 0; i < iterable.length; i += 1) {
                state = transitions[state](iterable, i, args);
            }
            return state;
        };
        /**
         * Parse and validate scriptlet rule
         * @param {*} ruleContent
         * @returns {{name: string, args: Array<string>}}
         */
        ScriptletParser.parseRule = function (ruleContent) {
            var _a;
            var transitions = (_a = {},
                _a[ScriptletParser.TRANSITION.OPENED] = ScriptletParser.opened,
                _a[ScriptletParser.TRANSITION.PARAM] = ScriptletParser.param,
                _a[ScriptletParser.TRANSITION.CLOSED] = function () { },
                _a);
            var sep = { symb: null };
            var saver = new ScriptletParser.WordSaver();
            var state = ScriptletParser.iterateWithTransitions(ruleContent, transitions, ScriptletParser.TRANSITION.OPENED, { sep: sep, saver: saver });
            if (state !== 'closed') {
                throw new Error("Invalid scriptlet ".concat(ruleContent));
            }
            var args = saver.getAll();
            return {
                name: args[0],
                args: args.slice(1),
            };
        };
        /**
         * Helper class to accumulate an array of strings char by char
         */
        ScriptletParser.WordSaver = /** @class */ (function () {
            function class_1() {
                /**
                 * String cursor
                 */
                this.str = '';
                /**
                 * Strings array
                 */
                this.collectedStrings = [];
            }
            /**
             * Saves symbol to cursor
             *
             * @param s
             */
            class_1.prototype.saveSymbol = function (s) {
                this.str += s;
            };
            /**
             * Saves cursor to strings
             */
            class_1.prototype.saveStr = function () {
                this.collectedStrings.push(this.str);
                this.str = '';
            };
            /**
             * Returns collected strings
             */
            class_1.prototype.getAll = function () {
                return __spreadArray([], this.collectedStrings, true);
            };
            return class_1;
        }());
        /**
         * Transition names
         */
        ScriptletParser.TRANSITION = {
            OPENED: 'opened',
            PARAM: 'param',
            CLOSED: 'closed',
        };
        /**
         * Transition function: the current index position in start, end or between params
         * @param {string} rule
         * @param {number} index
         * @param {Object} Object
         * @property {Object} Object.sep contains prop symb with current separator char
         * @returns {string} transition
         */
        ScriptletParser.opened = function (rule, index, _a) {
            var sep = _a.sep;
            var char = rule[index];
            switch (char) {
                case ' ':
                case '(':
                case ',':
                    return ScriptletParser.TRANSITION.OPENED;
                case '\'':
                case '"':
                    // eslint-disable-next-line no-param-reassign
                    sep.symb = char;
                    return ScriptletParser.TRANSITION.PARAM;
                case ')':
                    return index === rule.length - 1
                        ? ScriptletParser.TRANSITION.CLOSED
                        : ScriptletParser.TRANSITION.OPENED;
            }
            return undefined;
        };
        /**
         * Transition function: the current index position inside param
         *
         * @param {string} rule
         * @param {number} index
         * @param {Object} Object
         * @property {Object} Object.sep contains prop `symb` with current separator char
         * @property {Object} Object.saver helper which allow to save strings by car by char
         * @returns {string} transition
         */
        ScriptletParser.param = function (rule, index, _a) {
            var saver = _a.saver, sep = _a.sep;
            var char = rule[index];
            switch (char) {
                case '\'':
                case '"':
                    if (char === sep.symb && rule[index - 1] !== '\\') {
                        // eslint-disable-next-line no-param-reassign
                        sep.symb = null;
                        saver.saveStr();
                        return ScriptletParser.TRANSITION.OPENED;
                    }
                    saver.saveSymbol(char);
                    return ScriptletParser.TRANSITION.PARAM;
                default:
                    saver.saveSymbol(char);
                    return ScriptletParser.TRANSITION.PARAM;
            }
        };
        return ScriptletParser;
    }());

    /**
     * Enumeration with the cosmetic rules markers.
     *
     * All cosmetic rules have similar structure:
     * ```
     * rule = [domains] "marker" content
     * domains = [domain0, domain1[, ...[, domainN]]]
     * ```
     *
     * For instance, element hiding rules look like:
     * `example.org##.banner`
     *
     * In this case:
     * * `[domains]` is `example.org` (comma-separated list of domains)
     * * `marker` is `##` (marker of element hiding rules)
     * * `content` is `.banner` (CSS selector)
     */
    exports.CosmeticRuleMarker = void 0;
    (function (CosmeticRuleMarker) {
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#cosmetic-elemhide-rules */
        CosmeticRuleMarker["ElementHiding"] = "##";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#element-hiding-rules-exceptions */
        CosmeticRuleMarker["ElementHidingException"] = "#@#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#extended-css-selectors */
        CosmeticRuleMarker["ElementHidingExtCSS"] = "#?#";
        /** Basically the same as {@link CosmeticRuleMarker.ElementHidingException} */
        CosmeticRuleMarker["ElementHidingExtCSSException"] = "#@?#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#cosmetic-css-rules */
        CosmeticRuleMarker["Css"] = "#$#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#cosmetic-css-rules-exceptions */
        CosmeticRuleMarker["CssException"] = "#@$#";
        /**
         * CSS rules that use extended CSS selectors:
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#extended-css-selectors
         */
        CosmeticRuleMarker["CssExtCSS"] = "#$?#";
        /** Basically the same as {@link CosmeticRuleMarker.CssException} */
        CosmeticRuleMarker["CssExtCSSException"] = "#@$?#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#javascript-rules */
        CosmeticRuleMarker["Js"] = "#%#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#javascript-rules-exceptions-1 */
        CosmeticRuleMarker["JsException"] = "#@%#";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#html-filtering-rules */
        CosmeticRuleMarker["Html"] = "$$";
        /** https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#html-filtering-rules-exceptions-1 */
        CosmeticRuleMarker["HtmlException"] = "$@$";
    })(exports.CosmeticRuleMarker || (exports.CosmeticRuleMarker = {}));
    /**
     * findCosmeticRuleMarker looks for a cosmetic rule marker in the rule text
     * and returns the start index of the marker and the marker found.
     * If nothing found, it returns -1 and null.
     *
     * @privateRemarks
     *
     * The idea is to search for the rule marker as quickly as possible.
     * If we were simply using `Array.includes` we had to call it a dozen of times (for every marker),
     * and that'd have been much slower.
     *
     * @param ruleText - rule text to scan.
     */
    function findCosmeticRuleMarker(ruleText) {
        var maxIndex = ruleText.length - 1;
        for (var i = 0; i < maxIndex; i += 1) {
            var char = ruleText.charAt(i);
            switch (char) {
                case '#':
                    if (i + 4 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '@'
                            && ruleText.charAt(i + 2) === '$'
                            && ruleText.charAt(i + 3) === '?'
                            && ruleText.charAt(i + 4) === '#') {
                            return [i, exports.CosmeticRuleMarker.CssExtCSSException];
                        }
                    }
                    if (i + 3 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '@'
                            && ruleText.charAt(i + 2) === '?' && ruleText.charAt(i + 3) === '#') {
                            return [i, exports.CosmeticRuleMarker.ElementHidingExtCSSException];
                        }
                        if (ruleText.charAt(i + 1) === '@'
                            && ruleText.charAt(i + 2) === '$' && ruleText.charAt(i + 3) === '#') {
                            return [i, exports.CosmeticRuleMarker.CssException];
                        }
                        if (ruleText.charAt(i + 1) === '@'
                            && ruleText.charAt(i + 2) === '%' && ruleText.charAt(i + 3) === '#') {
                            return [i, exports.CosmeticRuleMarker.JsException];
                        }
                        if (ruleText.charAt(i + 1) === '$'
                            && ruleText.charAt(i + 2) === '?' && ruleText.charAt(i + 3) === '#') {
                            return [i, exports.CosmeticRuleMarker.CssExtCSS];
                        }
                    }
                    if (i + 2 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '@' && ruleText.charAt(i + 2) === '#') {
                            return [i, exports.CosmeticRuleMarker.ElementHidingException];
                        }
                        if (ruleText.charAt(i + 1) === '?' && ruleText.charAt(i + 2) === '#') {
                            return [i, exports.CosmeticRuleMarker.ElementHidingExtCSS];
                        }
                        if (ruleText.charAt(i + 1) === '%' && ruleText.charAt(i + 2) === '#') {
                            return [i, exports.CosmeticRuleMarker.Js];
                        }
                        if (ruleText.charAt(i + 1) === '$' && ruleText.charAt(i + 2) === '#') {
                            return [i, exports.CosmeticRuleMarker.Css];
                        }
                    }
                    if (i + 1 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '#') {
                            // Handling false positives while looking for cosmetic rules in host files.
                            //
                            // For instance, it could look like this:
                            // 127.0.0.1 localhost ## this is just a comment
                            if (i > 0 && ruleText.charAt(i - 1) === ' ') {
                                return [-1, null];
                            }
                            return [i, exports.CosmeticRuleMarker.ElementHiding];
                        }
                    }
                    break;
                case '$':
                    if (i + 2 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '@' && ruleText.charAt(i + 2) === '$') {
                            return [i, exports.CosmeticRuleMarker.HtmlException];
                        }
                    }
                    if (i + 1 <= maxIndex) {
                        if (ruleText.charAt(i + 1) === '$') {
                            return [i, exports.CosmeticRuleMarker.Html];
                        }
                    }
                    break;
            }
        }
        return [-1, null];
    }
    /**
     * Detects is the rule is extended css rule
     * @param marker - string to check
     */
    function isExtCssMarker(marker) {
        var EXTENDED_CSS_MARKERS = [
            exports.CosmeticRuleMarker.CssExtCSS,
            exports.CosmeticRuleMarker.CssExtCSSException,
            exports.CosmeticRuleMarker.ElementHidingExtCSS,
            exports.CosmeticRuleMarker.ElementHidingExtCSSException,
        ];
        return EXTENDED_CSS_MARKERS.indexOf(marker) !== -1;
    }
    /**
     * AdGuard scriptlet rule mask
     */
    var ADG_SCRIPTLET_MASK = '//scriptlet';

    /**
     * This class stores found script rules content in the appropriate collections
     * It is primarily used by the {@see CosmeticResult}
     */
    var CosmeticScriptsResult = /** @class */ (function () {
        /**
         * Constructor
         */
        function CosmeticScriptsResult() {
            this.generic = [];
            this.specific = [];
        }
        /**
         * Appends rule to appropriate collection
         * @param rule
         * @param request
         */
        CosmeticScriptsResult.prototype.append = function (rule, request) {
            CosmeticScriptsResult.setScriptCode(rule, request);
            if (rule.isGeneric()) {
                this.generic.push(rule);
            }
            else {
                this.specific.push(rule);
            }
        };
        /**
         * Returns rules collected
         */
        CosmeticScriptsResult.prototype.getRules = function () {
            return __spreadArray(__spreadArray([], this.generic, true), this.specific, true);
        };
        /**
         * Updates rule.script with js ready to execute
         *
         * @param rule
         * @param request
         */
        CosmeticScriptsResult.setScriptCode = function (rule, request) {
            var requestDomainName;
            if (request) {
                requestDomainName = request.domain;
            }
            if (rule.script && rule.scriptVerbose) {
                if (!rule.isScriptlet) {
                    // Already done for this none-scriptlet rule
                    return;
                }
                // do not reinvoke scriptVerbose for same domain for scriptlet rule
                if (rule.isScriptlet
                    && requestDomainName
                    && rule.verboseInvokedForDomain === requestDomainName) {
                    return;
                }
            }
            var ruleContent = rule.getContent();
            if (!ruleContent.startsWith(ADG_SCRIPTLET_MASK)) {
                // eslint-disable-next-line no-param-reassign
                rule.script = ruleContent;
                // eslint-disable-next-line no-param-reassign
                rule.scriptVerbose = ruleContent;
                return;
            }
            var scriptletContent = ruleContent.substr(ADG_SCRIPTLET_MASK.length);
            var scriptletParams = ScriptletParser.parseRule(scriptletContent);
            var params = {
                args: scriptletParams.args,
                engine: exports.config.engine ? exports.config.engine : '',
                name: scriptletParams.name,
                ruleText: rule.getText(),
                verbose: false,
                version: exports.config.version ? exports.config.version : '',
            };
            var scriptText;
            if (!rule.script) {
                scriptText = scriptlets.invoke(params);
                // eslint-disable-next-line no-param-reassign
                rule.script = scriptText !== null ? scriptText : undefined;
            }
            params.verbose = true;
            // add domainName to reduce log output in the rules with multiple domains
            if (requestDomainName) {
                params.domainName = requestDomainName;
                rule.verboseInvokedForDomain = requestDomainName;
            }
            scriptText = scriptlets.invoke(params);
            // eslint-disable-next-line no-param-reassign
            rule.scriptVerbose = scriptText !== null ? scriptText : undefined;
        };
        return CosmeticScriptsResult;
    }());

    /**
     * This class stores found cosmetic html rules content in the appropriate collections
     * It is primarily used by the {@see CosmeticResult}
     */
    var CosmeticHtmlResult = /** @class */ (function () {
        /**
         * Constructor
         */
        function CosmeticHtmlResult() {
            this.generic = [];
            this.specific = [];
        }
        /**
         * Appends rule to the appropriate collection
         * @param rule
         */
        CosmeticHtmlResult.prototype.append = function (rule) {
            if (rule.isGeneric()) {
                this.generic.push(rule);
            }
            else {
                this.specific.push(rule);
            }
        };
        /**
         * Returns rules collected
         */
        CosmeticHtmlResult.prototype.getRules = function () {
            return __spreadArray(__spreadArray([], this.generic, true), this.specific, true);
        };
        return CosmeticHtmlResult;
    }());

    /**
     * Cosmetic result is the representation of rules
     * It is primarily used by the {@see CosmeticEngine}
     */
    var CosmeticResult = /** @class */ (function () {
        /**
         * Constructor
         */
        function CosmeticResult() {
            this.elementHiding = new CosmeticStylesResult();
            this.CSS = new CosmeticStylesResult();
            this.JS = new CosmeticScriptsResult();
            this.Html = new CosmeticHtmlResult();
        }
        /**
         * Script rules
         */
        CosmeticResult.prototype.getScriptRules = function () {
            return this.JS.getRules();
        };
        return CosmeticResult;
    }());

    /**
     * CosmeticOption is the enumeration of various content script options.
     * Depending on the set of enabled flags the content script will contain different set of settings.
     */
    exports.CosmeticOption = void 0;
    (function (CosmeticOption) {
        /**
         * if generic elemhide and CSS rules are enabled
         * Could be disabled by a $generichide rule and $elemhide rule.
         */
        CosmeticOption[CosmeticOption["CosmeticOptionGenericCSS"] = 2] = "CosmeticOptionGenericCSS";
        /**
         * if specific elemhide and CSS rules are enabled
         * Could be disabled by a $specifichide rule and $elemhide rule.
         */
        CosmeticOption[CosmeticOption["CosmeticOptionSpecificCSS"] = 4] = "CosmeticOptionSpecificCSS";
        /**
         * if JS rules and scriptlets are enabled
         * Could be disabled by a $jsinject rule.
         */
        CosmeticOption[CosmeticOption["CosmeticOptionJS"] = 8] = "CosmeticOptionJS";
        /**
         * if Html filtering rules are enabled
         * Could be disabled by a $content rule.
         */
        CosmeticOption[CosmeticOption["CosmeticOptionHtml"] = 16] = "CosmeticOptionHtml";
        /**
         * TODO: Add support for these flags
         * They are useful when content script is injected into an iframe
         * In this case we can check what flags were applied to the top-level frame
         */
        CosmeticOption[CosmeticOption["CosmeticOptionSourceGenericCSS"] = 32] = "CosmeticOptionSourceGenericCSS";
        CosmeticOption[CosmeticOption["CosmeticOptionSourceCSS"] = 64] = "CosmeticOptionSourceCSS";
        CosmeticOption[CosmeticOption["CosmeticOptionSourceJS"] = 128] = "CosmeticOptionSourceJS";
        /**
         * everything is enabled
         */
        CosmeticOption[CosmeticOption["CosmeticOptionAll"] = 30] = "CosmeticOptionAll";
        /**
         * everything is disabled
         */
        CosmeticOption[CosmeticOption["CosmeticOptionNone"] = 0] = "CosmeticOptionNone";
    })(exports.CosmeticOption || (exports.CosmeticOption = {}));

    // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/regexp
    // should be escaped . * + ? ^ $ { } ( ) | [ ] / \
    // except of * | ^
    var specialCharacters = ['.', '+', '?', '$', '{', '}', '(', ')', '[', ']', '/', '\\'];
    var reSpecialCharacters = new RegExp("[".concat(specialCharacters.join('\\'), "]"), 'g');
    var reSpecialCharactersFull = /[.*+?^${}()|[\]\\]/g;
    var reEscapedSpecialCharactersFull = /\\[.*+?^${}()|[\]\\]/g;
    /**
     * Class with static helper methods for working with basic filtering rules patterns.
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules
     */
    var SimpleRegex = /** @class */ (function () {
        function SimpleRegex() {
        }
        /**
         * Extracts the shortcut from the rule's pattern.
         * Shortcut is the longest substring of the pattern that does not contain
         * any special characters.
         *
         * Please note, that the shortcut is always lower-case!
         *
         * @param pattern - network rule's pattern.
         * @returns the shortcut or the empty string if we could not extract any.
         */
        SimpleRegex.extractShortcut = function (pattern) {
            if (pattern.startsWith(this.MASK_REGEX_RULE) && pattern.endsWith(this.MASK_REGEX_RULE)) {
                return this.extractRegexpShortcut(pattern);
            }
            return this.extractBasicShortcut(pattern);
        };
        /**
         * Searches for the longest substring of the pattern that
         * does not contain any special characters: *,^,|.
         *
         * @param pattern - network rule's pattern.
         * @returns the shortcut or the empty string
         */
        SimpleRegex.extractBasicShortcut = function (pattern) {
            var longest = '';
            var parts = pattern.split(this.rePatternSpecialCharacters);
            for (var _i = 0, parts_1 = parts; _i < parts_1.length; _i++) {
                var part = parts_1[_i];
                if (part.length > longest.length) {
                    longest = part;
                }
            }
            return (longest || '').toLowerCase();
        };
        /**
         * Searches for a shortcut inside of a regexp pattern.
         * Shortcut in this case is a longest string with no REGEX special characters.
         * Also, we discard complicated regexps right away.
         *
         * @param pattern - network rule's pattern (regexp).
         * @returns the shortcut or the empty string
         */
        SimpleRegex.extractRegexpShortcut = function (pattern) {
            var reText = pattern.substring(this.MASK_REGEX_RULE.length, pattern.length - this.MASK_REGEX_RULE.length);
            if (reText.length === 0) {
                // The rule is too short, doing nothing
                return '';
            }
            if (reText.indexOf('(?') >= 0 || reText.indexOf('(!?') >= 0) {
                // Do not mess with complex expressions which use lookahead
                return '';
            }
            var specialCharacter = '$$$';
            // Prepend specialCharacter for the following replace calls to work properly
            reText = specialCharacter + reText;
            // Strip all types of brackets
            reText = reText.replace(/[^\\]\(.*[^\\]\)/, specialCharacter);
            reText = reText.replace(/[^\\]\[.*[^\\]\]/, specialCharacter);
            reText = reText.replace(/[^\\]\{.*[^\\]\}/, specialCharacter);
            // Strip some special characters
            reText = reText.replace(/[^\\]\\[a-zA-Z]/, specialCharacter);
            // Replace \. with .
            reText = reText.replace(/\\\./g, '.');
            // Split by special characters
            // `.` is one of the special characters so our `specialCharacter`
            // will be removed from the resulting array
            var parts = reText.split(/[\\^$*+?()|[\]{}]/);
            var longest = '';
            for (var i = 0; i < parts.length; i += 1) {
                var part = parts[i];
                if (part.length > longest.length) {
                    longest = part;
                }
            }
            return longest.toLowerCase();
        };
        /**
         * patternToRegexp is a helper method for creating regular expressions from the simple
         * wildcard-based syntax which is used in basic filters:
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules
         *
         * @param pattern - basic rule pattern
         * @returns regular expression
         */
        SimpleRegex.patternToRegexp = function (pattern) {
            if (pattern === this.MASK_START_URL
                || pattern === this.MASK_PIPE
                || pattern === this.MASK_ANY_CHARACTER
                || pattern === '') {
                return this.REGEX_ANY_CHARACTER;
            }
            if (pattern.startsWith(this.MASK_REGEX_RULE) && pattern.endsWith(this.MASK_REGEX_RULE)) {
                // This is a regex rule, just remove the regex markers
                return pattern.substring(this.MASK_REGEX_RULE.length, pattern.length - this.MASK_REGEX_RULE.length);
            }
            // Escape special characters except of * | ^
            var regex = pattern.replace(reSpecialCharacters, '\\$&');
            // Now escape "|" characters but avoid escaping them in the special places
            if (regex.startsWith(this.MASK_START_URL)) {
                regex = regex.substring(0, this.MASK_START_URL.length)
                    + replaceAll(regex.substring(this.MASK_START_URL.length, regex.length - this.MASK_PIPE.length), this.MASK_PIPE, "\\".concat(this.MASK_PIPE))
                    + regex.substring(regex.length - this.MASK_PIPE.length);
            }
            else {
                regex = regex.substring(0, this.MASK_PIPE.length)
                    + replaceAll(regex.substring(this.MASK_PIPE.length, regex.length - this.MASK_PIPE.length), this.MASK_PIPE, "\\".concat(this.MASK_PIPE))
                    + regex.substring(regex.length - this.MASK_PIPE.length);
            }
            // Replace special URL masks
            regex = replaceAll(regex, this.MASK_ANY_CHARACTER, this.REGEX_ANY_CHARACTER);
            regex = replaceAll(regex, this.MASK_SEPARATOR, this.REGEX_SEPARATOR);
            // Replace start URL and pipes
            if (regex.startsWith(this.MASK_START_URL)) {
                regex = this.REGEX_START_URL + regex.substring(this.MASK_START_URL.length);
            }
            else if (regex.startsWith(this.MASK_PIPE)) {
                regex = this.REGEX_START_STRING + regex.substring(this.MASK_PIPE.length);
            }
            if (regex.endsWith(this.MASK_PIPE)) {
                regex = regex.substring(0, regex.length - this.MASK_PIPE.length) + this.REGEX_END_STRING;
            }
            return regex;
        };
        /**
         * Creates RegExp object from string in '/reg_exp/gi' format
         *
         * @param str
         */
        SimpleRegex.patternFromString = function (str) {
            var parts = splitByDelimiterWithEscapeCharacter(str, '/', '\\', true);
            var modifiers = (parts[1] || '');
            if (modifiers.indexOf('g') < 0) {
                modifiers += 'g';
            }
            return new RegExp(parts[0], modifiers);
        };
        /**
         * Escapes characters with special meaning inside a regular expression.
         *
         * @param str
         * @param searchPattern - Pattern for detecting special characters. Optional.
         */
        SimpleRegex.escapeRegexSpecials = function (str, searchPattern) {
            if (searchPattern === void 0) { searchPattern = reSpecialCharactersFull; }
            return str.replace(searchPattern, '\\$&');
        };
        /**
         * Unescapes characters with special meaning inside a regular expression.
         *
         * @param str
         * @param searchPattern - Pattern for detecting special characters. Optional.
         */
        SimpleRegex.unescapeRegexSpecials = function (str, searchPattern) {
            if (searchPattern === void 0) { searchPattern = reEscapedSpecialCharactersFull; }
            return str.replace(searchPattern, function (match) { return match.substring(1); });
        };
        /**
         * Check if pattern is Regex
         */
        SimpleRegex.isRegexPattern = function (str) {
            return str.startsWith('/') && str.endsWith('/');
        };
        /**
         * Matching the beginning of an address. With this character you don't
         * have to specify a particular protocol and subdomain in address mask.
         * It means, || stands for http://*., https://*., ws://*., wss://*. at once.
         */
        SimpleRegex.MASK_START_URL = '||';
        /**
         * REGEX_START_URL corresponds to MASK_START_URL
         */
        SimpleRegex.REGEX_START_URL = '^(http|https|ws|wss)://([a-z0-9-_.]+\\.)?';
        /**
         * A pointer to the beginning or the end of address. The value depends on the
         * character placement in the mask. For example, a rule swf| corresponds
         * to http://example.com/annoyingflash.swf , but not to http://example.com/swf/index.html.
         * |http://example.org corresponds to http://example.org,
         * but not to http://domain.com?url=http://example.org.
         */
        SimpleRegex.MASK_PIPE = '|';
        /**
         * REGEX_END_STRING corresponds to MASK_PIPE if it is in the end of a pattern.
         */
        SimpleRegex.REGEX_END_STRING = '$';
        /**
         * REGEX_START_STRING corresponds to MASK_PIPE if it is in the beginning of a pattern.
         */
        SimpleRegex.REGEX_START_STRING = '^';
        /**
         * Separator character mark. Separator character is any character,
         * but a letter, a digit, or one of the following: _ - .
         */
        SimpleRegex.MASK_SEPARATOR = '^';
        /**
         * REGEX_SEPARATOR corresponds to MASK_SEPARATOR
         */
        SimpleRegex.REGEX_SEPARATOR = '([^ a-zA-Z0-9.%_-]|$)';
        /**
         * This is a wildcard character. It is used to represent "any set of characters".
         * This can also be an empty string or a string of any length.
         */
        SimpleRegex.MASK_ANY_CHARACTER = '*';
        /**
         * Path separator
         */
        SimpleRegex.MASK_BACKSLASH = '/';
        /**
         * REGEX_ANY_CHARACTER corresponds to MASK_ANY_CHARACTER.
         */
        SimpleRegex.REGEX_ANY_CHARACTER = '.*';
        /**
         * Enclose regex in two backslashes to mark a regex rule:
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#regular-expressions-support
         */
        SimpleRegex.MASK_REGEX_RULE = '/';
        /**
         *  Regex for matching special characters in modifier regex pattern
         */
        SimpleRegex.reModifierPatternSpecialCharacters = /[[\],\\]/g;
        /**
          *  Regex for matching escaped special characters in modifier regex pattern
          */
        SimpleRegex.reModifierPatternEscapedSpecialCharacters = /\\[[\],\\]/g;
        /**
         * If string starts with exclamation mark "!" we consider it as comment
         */
        SimpleRegex.MASK_COMMENT = '!';
        /**
         * Min length of rule shortcut
         * This value has been picked as a result of performance experiments
         */
        SimpleRegex.MIN_SHORTCUT_LENGTH = 3;
        /**
         * Min length of generic rule shortcut
         */
        SimpleRegex.MIN_GENERIC_RULE_LENGTH = 4;
        /** Regex with basic matching pattern special characters */
        SimpleRegex.rePatternSpecialCharacters = new RegExp('[*^|]');
        return SimpleRegex;
    }());

    function shareSameDomainSuffix(hostname, vhost) {
        if (hostname.endsWith(vhost)) {
            return (hostname.length === vhost.length ||
                hostname[hostname.length - vhost.length - 1] === '.');
        }
        return false;
    }
    function extractDomainWithSuffix(hostname, publicSuffix) {
        const publicSuffixIndex = hostname.length - publicSuffix.length - 2;
        const lastDotBeforeSuffixIndex = hostname.lastIndexOf('.', publicSuffixIndex);
        if (lastDotBeforeSuffixIndex === -1) {
            return hostname;
        }
        return hostname.slice(lastDotBeforeSuffixIndex + 1);
    }
    function getDomain(suffix, hostname, options) {
        if (options.validHosts !== null) {
            const validHosts = options.validHosts;
            for (let i = 0; i < validHosts.length; i += 1) {
                const vhost = validHosts[i];
                if ( shareSameDomainSuffix(hostname, vhost) === true) {
                    return vhost;
                }
            }
        }
        if (suffix.length === hostname.length) {
            return null;
        }
        return  extractDomainWithSuffix(hostname, suffix);
    }

    function getDomainWithoutSuffix(domain, suffix) {
        return domain.slice(0, -suffix.length - 1);
    }

    function extractHostname(url, urlIsValidHostname) {
        let start = 0;
        let end = url.length;
        let hasUpper = false;
        if (urlIsValidHostname === false) {
            if (url.startsWith('data:') === true) {
                return null;
            }
            while (start < url.length && url.charCodeAt(start) <= 32) {
                start += 1;
            }
            while (end > start + 1 && url.charCodeAt(end - 1) <= 32) {
                end -= 1;
            }
            if (url.charCodeAt(start) === 47  &&
                url.charCodeAt(start + 1) === 47 ) {
                start += 2;
            }
            else {
                const indexOfProtocol = url.indexOf(':/', start);
                if (indexOfProtocol !== -1) {
                    const protocolSize = indexOfProtocol - start;
                    const c0 = url.charCodeAt(start);
                    const c1 = url.charCodeAt(start + 1);
                    const c2 = url.charCodeAt(start + 2);
                    const c3 = url.charCodeAt(start + 3);
                    const c4 = url.charCodeAt(start + 4);
                    if (protocolSize === 5 &&
                        c0 === 104  &&
                        c1 === 116  &&
                        c2 === 116  &&
                        c3 === 112  &&
                        c4 === 115 ) ;
                    else if (protocolSize === 4 &&
                        c0 === 104  &&
                        c1 === 116  &&
                        c2 === 116  &&
                        c3 === 112 ) ;
                    else if (protocolSize === 3 &&
                        c0 === 119  &&
                        c1 === 115  &&
                        c2 === 115 ) ;
                    else if (protocolSize === 2 &&
                        c0 === 119  &&
                        c1 === 115 ) ;
                    else {
                        for (let i = start; i < indexOfProtocol; i += 1) {
                            const lowerCaseCode = url.charCodeAt(i) | 32;
                            if (((lowerCaseCode >= 97 && lowerCaseCode <= 122) ||
                                (lowerCaseCode >= 48 && lowerCaseCode <= 57) ||
                                lowerCaseCode === 46 ||
                                lowerCaseCode === 45 ||
                                lowerCaseCode === 43) === false
                            ) {
                                return null;
                            }
                        }
                    }
                    start = indexOfProtocol + 2;
                    while (url.charCodeAt(start) === 47 ) {
                        start += 1;
                    }
                }
            }
            let indexOfIdentifier = -1;
            let indexOfClosingBracket = -1;
            let indexOfPort = -1;
            for (let i = start; i < end; i += 1) {
                const code = url.charCodeAt(i);
                if (code === 35 ||
                    code === 47 ||
                    code === 63
                ) {
                    end = i;
                    break;
                }
                else if (code === 64) {
                    indexOfIdentifier = i;
                }
                else if (code === 93) {
                    indexOfClosingBracket = i;
                }
                else if (code === 58) {
                    indexOfPort = i;
                }
                else if (code >= 65 && code <= 90) {
                    hasUpper = true;
                }
            }
            if (indexOfIdentifier !== -1 &&
                indexOfIdentifier > start &&
                indexOfIdentifier < end) {
                start = indexOfIdentifier + 1;
            }
            if (url.charCodeAt(start) === 91 ) {
                if (indexOfClosingBracket !== -1) {
                    return url.slice(start + 1, indexOfClosingBracket).toLowerCase();
                }
                return null;
            }
            else if (indexOfPort !== -1 && indexOfPort > start && indexOfPort < end) {
                end = indexOfPort;
            }
        }
        while (end > start + 1 && url.charCodeAt(end - 1) === 46 ) {
            end -= 1;
        }
        const hostname = start !== 0 || end !== url.length ? url.slice(start, end) : url;
        if (hasUpper) {
            return hostname.toLowerCase();
        }
        return hostname;
    }

    function isProbablyIpv4(hostname) {
        if (hostname.length < 7) {
            return false;
        }
        if (hostname.length > 15) {
            return false;
        }
        let numberOfDots = 0;
        for (let i = 0; i < hostname.length; i += 1) {
            const code = hostname.charCodeAt(i);
            if (code === 46 ) {
                numberOfDots += 1;
            }
            else if (code < 48  || code > 57 ) {
                return false;
            }
        }
        return (numberOfDots === 3 &&
            hostname.charCodeAt(0) !== 46  &&
            hostname.charCodeAt(hostname.length - 1) !== 46 );
    }
    function isProbablyIpv6(hostname) {
        if (hostname.length < 3) {
            return false;
        }
        let start = hostname[0] === '[' ? 1 : 0;
        let end = hostname.length;
        if (hostname[end - 1] === ']') {
            end -= 1;
        }
        if (end - start > 39) {
            return false;
        }
        let hasColon = false;
        for (; start < end; start += 1) {
            const code = hostname.charCodeAt(start);
            if (code === 58 ) {
                hasColon = true;
            }
            else if (((code >= 48 && code <= 57) ||
                (code >= 97 && code <= 102) ||
                (code >= 65 && code <= 90)) ===
                false) {
                return false;
            }
        }
        return hasColon;
    }
    function isIp$1(hostname) {
        return isProbablyIpv6(hostname) || isProbablyIpv4(hostname);
    }

    function isValidAscii(code) {
        return ((code >= 97 && code <= 122) || (code >= 48 && code <= 57) || code > 127);
    }
    function isValidHostname (hostname) {
        if (hostname.length > 255) {
            return false;
        }
        if (hostname.length === 0) {
            return false;
        }
        if ( isValidAscii(hostname.charCodeAt(0)) === false) {
            return false;
        }
        let lastDotIndex = -1;
        let lastCharCode = -1;
        const len = hostname.length;
        for (let i = 0; i < len; i += 1) {
            const code = hostname.charCodeAt(i);
            if (code === 46 ) {
                if (
                i - lastDotIndex > 64 ||
                    lastCharCode === 46 ||
                    lastCharCode === 45 ||
                    lastCharCode === 95) {
                    return false;
                }
                lastDotIndex = i;
            }
            else if (( isValidAscii(code) || code === 45 || code === 95) ===
                false) {
                return false;
            }
            lastCharCode = code;
        }
        return (
        len - lastDotIndex - 1 <= 63 &&
            lastCharCode !== 45);
    }

    function setDefaultsImpl({ allowIcannDomains = true, allowPrivateDomains = false, detectIp = true, extractHostname = true, mixedInputs = true, validHosts = null, validateHostname = true, }) {
        return {
            allowIcannDomains,
            allowPrivateDomains,
            detectIp,
            extractHostname,
            mixedInputs,
            validHosts,
            validateHostname,
        };
    }
    const DEFAULT_OPTIONS =  setDefaultsImpl({});
    function setDefaults(options) {
        if (options === undefined) {
            return DEFAULT_OPTIONS;
        }
        return  setDefaultsImpl(options);
    }

    function getSubdomain(hostname, domain) {
        if (domain.length === hostname.length) {
            return '';
        }
        return hostname.slice(0, -domain.length - 1);
    }

    function getEmptyResult() {
        return {
            domain: null,
            domainWithoutSuffix: null,
            hostname: null,
            isIcann: null,
            isIp: null,
            isPrivate: null,
            publicSuffix: null,
            subdomain: null,
        };
    }
    function resetResult(result) {
        result.domain = null;
        result.domainWithoutSuffix = null;
        result.hostname = null;
        result.isIcann = null;
        result.isIp = null;
        result.isPrivate = null;
        result.publicSuffix = null;
        result.subdomain = null;
    }
    function parseImpl(url, step, suffixLookup, partialOptions, result) {
        const options = setDefaults(partialOptions);
        if (typeof url !== 'string') {
            return result;
        }
        if (options.extractHostname === false) {
            result.hostname = url;
        }
        else if (options.mixedInputs === true) {
            result.hostname = extractHostname(url, isValidHostname(url));
        }
        else {
            result.hostname = extractHostname(url, false);
        }
        if (step === 0  || result.hostname === null) {
            return result;
        }
        if (options.detectIp === true) {
            result.isIp = isIp$1(result.hostname);
            if (result.isIp === true) {
                return result;
            }
        }
        if (options.validateHostname === true &&
            options.extractHostname === true &&
            isValidHostname(result.hostname) === false) {
            result.hostname = null;
            return result;
        }
        suffixLookup(result.hostname, options, result);
        if (step === 2  || result.publicSuffix === null) {
            return result;
        }
        result.domain = getDomain(result.publicSuffix, result.hostname, options);
        if (step === 3  || result.domain === null) {
            return result;
        }
        result.subdomain = getSubdomain(result.hostname, result.domain);
        if (step === 4 ) {
            return result;
        }
        result.domainWithoutSuffix = getDomainWithoutSuffix(result.domain, result.publicSuffix);
        return result;
    }

    function fastPathLookup (hostname, options, out) {
        if (options.allowPrivateDomains === false && hostname.length > 3) {
            const last = hostname.length - 1;
            const c3 = hostname.charCodeAt(last);
            const c2 = hostname.charCodeAt(last - 1);
            const c1 = hostname.charCodeAt(last - 2);
            const c0 = hostname.charCodeAt(last - 3);
            if (c3 === 109  &&
                c2 === 111  &&
                c1 === 99  &&
                c0 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'com';
                return true;
            }
            else if (c3 === 103  &&
                c2 === 114  &&
                c1 === 111  &&
                c0 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'org';
                return true;
            }
            else if (c3 === 117  &&
                c2 === 100  &&
                c1 === 101  &&
                c0 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'edu';
                return true;
            }
            else if (c3 === 118  &&
                c2 === 111  &&
                c1 === 103  &&
                c0 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'gov';
                return true;
            }
            else if (c3 === 116  &&
                c2 === 101  &&
                c1 === 110  &&
                c0 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'net';
                return true;
            }
            else if (c3 === 101  &&
                c2 === 100  &&
                c1 === 46 ) {
                out.isIcann = true;
                out.isPrivate = false;
                out.publicSuffix = 'de';
                return true;
            }
        }
        return false;
    }

    const exceptions = (function () {
        const _0 = { "$": 1, "succ": {} }, _1 = { "$": 0, "succ": { "city": _0 } };
        const exceptions = { "$": 0, "succ": { "ck": { "$": 0, "succ": { "www": _0 } }, "jp": { "$": 0, "succ": { "kawasaki": _1, "kitakyushu": _1, "kobe": _1, "nagoya": _1, "sapporo": _1, "sendai": _1, "yokohama": _1 } } } };
        return exceptions;
    })();
    const rules = (function () {
        const _2 = { "$": 1, "succ": {} }, _3 = { "$": 2, "succ": {} }, _4 = { "$": 1, "succ": { "gov": _2, "com": _2, "org": _2, "net": _2, "edu": _2 } }, _5 = { "$": 0, "succ": { "*": _3 } }, _6 = { "$": 1, "succ": { "blogspot": _3 } }, _7 = { "$": 1, "succ": { "gov": _2 } }, _8 = { "$": 0, "succ": { "*": _2 } }, _9 = { "$": 0, "succ": { "cloud": _3 } }, _10 = { "$": 1, "succ": { "co": _3 } }, _11 = { "$": 0, "succ": { "s3": _3 } }, _12 = { "$": 0, "succ": { "direct": _3 } }, _13 = { "$": 0, "succ": { "dualstack": _11 } }, _14 = { "$": 0, "succ": { "s3": _3, "dualstack": _11, "s3-website": _3 } }, _15 = { "$": 0, "succ": { "apps": _3 } }, _16 = { "$": 0, "succ": { "paas": _3 } }, _17 = { "$": 0, "succ": { "app": _3 } }, _18 = { "$": 2, "succ": { "eu": _3 } }, _19 = { "$": 0, "succ": { "site": _3 } }, _20 = { "$": 0, "succ": { "pages": _3 } }, _21 = { "$": 1, "succ": { "com": _2, "edu": _2, "net": _2, "org": _2 } }, _22 = { "$": 0, "succ": { "j": _3 } }, _23 = { "$": 0, "succ": { "jelastic": _3 } }, _24 = { "$": 0, "succ": { "user": _3 } }, _25 = { "$": 1, "succ": { "ybo": _3 } }, _26 = { "$": 0, "succ": { "cust": _3, "reservd": _3 } }, _27 = { "$": 0, "succ": { "cust": _3 } }, _28 = { "$": 1, "succ": { "gov": _2, "edu": _2, "mil": _2, "com": _2, "org": _2, "net": _2 } }, _29 = { "$": 1, "succ": { "edu": _2, "biz": _2, "net": _2, "org": _2, "gov": _2, "info": _2, "com": _2 } }, _30 = { "$": 1, "succ": { "gov": _2, "blogspot": _3 } }, _31 = { "$": 1, "succ": { "barsy": _3 } }, _32 = { "$": 0, "succ": { "forgot": _3 } }, _33 = { "$": 1, "succ": { "gs": _2 } }, _34 = { "$": 0, "succ": { "nes": _2 } }, _35 = { "$": 1, "succ": { "k12": _2, "cc": _2, "lib": _2 } }, _36 = { "$": 1, "succ": { "cc": _2, "lib": _2 } };
        const rules = { "$": 0, "succ": { "ac": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "net": _2, "mil": _2, "org": _2, "drr": _3 } }, "ad": { "$": 1, "succ": { "nom": _2 } }, "ae": { "$": 1, "succ": { "co": _2, "net": _2, "org": _2, "sch": _2, "ac": _2, "gov": _2, "mil": _2, "blogspot": _3 } }, "aero": { "$": 1, "succ": { "accident-investigation": _2, "accident-prevention": _2, "aerobatic": _2, "aeroclub": _2, "aerodrome": _2, "agents": _2, "aircraft": _2, "airline": _2, "airport": _2, "air-surveillance": _2, "airtraffic": _2, "air-traffic-control": _2, "ambulance": _2, "amusement": _2, "association": _2, "author": _2, "ballooning": _2, "broker": _2, "caa": _2, "cargo": _2, "catering": _2, "certification": _2, "championship": _2, "charter": _2, "civilaviation": _2, "club": _2, "conference": _2, "consultant": _2, "consulting": _2, "control": _2, "council": _2, "crew": _2, "design": _2, "dgca": _2, "educator": _2, "emergency": _2, "engine": _2, "engineer": _2, "entertainment": _2, "equipment": _2, "exchange": _2, "express": _2, "federation": _2, "flight": _2, "fuel": _2, "gliding": _2, "government": _2, "groundhandling": _2, "group": _2, "hanggliding": _2, "homebuilt": _2, "insurance": _2, "journal": _2, "journalist": _2, "leasing": _2, "logistics": _2, "magazine": _2, "maintenance": _2, "media": _2, "microlight": _2, "modelling": _2, "navigation": _2, "parachuting": _2, "paragliding": _2, "passenger-association": _2, "pilot": _2, "press": _2, "production": _2, "recreation": _2, "repbody": _2, "res": _2, "research": _2, "rotorcraft": _2, "safety": _2, "scientist": _2, "services": _2, "show": _2, "skydiving": _2, "software": _2, "student": _2, "trader": _2, "trading": _2, "trainer": _2, "union": _2, "workinggroup": _2, "works": _2 } }, "af": _4, "ag": { "$": 1, "succ": { "com": _2, "org": _2, "net": _2, "co": _2, "nom": _2 } }, "ai": { "$": 1, "succ": { "off": _2, "com": _2, "net": _2, "org": _2, "uwu": _3 } }, "al": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "mil": _2, "net": _2, "org": _2, "blogspot": _3 } }, "am": { "$": 1, "succ": { "co": _2, "com": _2, "commune": _2, "net": _2, "org": _2, "radio": _3, "blogspot": _3, "neko": _3, "nyaa": _3 } }, "ao": { "$": 1, "succ": { "ed": _2, "gv": _2, "og": _2, "co": _2, "pb": _2, "it": _2 } }, "aq": _2, "ar": { "$": 1, "succ": { "bet": _2, "com": _6, "coop": _2, "edu": _2, "gob": _2, "gov": _2, "int": _2, "mil": _2, "musica": _2, "mutual": _2, "net": _2, "org": _2, "senasa": _2, "tur": _2 } }, "arpa": { "$": 1, "succ": { "e164": _2, "in-addr": _2, "ip6": _2, "iris": _2, "uri": _2, "urn": _2 } }, "as": _7, "asia": { "$": 1, "succ": { "cloudns": _3 } }, "at": { "$": 1, "succ": { "ac": { "$": 1, "succ": { "sth": _2 } }, "co": _6, "gv": _2, "or": _2, "funkfeuer": { "$": 0, "succ": { "wien": _3 } }, "futurecms": { "$": 0, "succ": { "*": _3, "ex": _5, "in": _5 } }, "futurehosting": _3, "futuremailing": _3, "ortsinfo": { "$": 0, "succ": { "ex": _5, "kunden": _5 } }, "biz": _3, "info": _3, "priv": _3, "myspreadshop": _3, "12hp": _3, "2ix": _3, "4lima": _3, "lima-city": _3 } }, "au": { "$": 1, "succ": { "com": { "$": 1, "succ": { "blogspot": _3, "cloudlets": { "$": 0, "succ": { "mel": _3 } }, "myspreadshop": _3 } }, "net": _2, "org": _2, "edu": { "$": 1, "succ": { "act": _2, "catholic": _2, "nsw": { "$": 1, "succ": { "schools": _2 } }, "nt": _2, "qld": _2, "sa": _2, "tas": _2, "vic": _2, "wa": _2 } }, "gov": { "$": 1, "succ": { "qld": _2, "sa": _2, "tas": _2, "vic": _2, "wa": _2 } }, "asn": _2, "id": _2, "info": _2, "conf": _2, "oz": _2, "act": _2, "nsw": _2, "nt": _2, "qld": _2, "sa": _2, "tas": _2, "vic": _2, "wa": _2 } }, "aw": { "$": 1, "succ": { "com": _2 } }, "ax": { "$": 1, "succ": { "be": _3, "cat": _3, "es": _3, "eu": _3, "gg": _3, "mc": _3, "us": _3, "xy": _3 } }, "az": { "$": 1, "succ": { "com": _2, "net": _2, "int": _2, "gov": _2, "org": _2, "edu": _2, "info": _2, "pp": _2, "mil": _2, "name": _2, "pro": _2, "biz": _2 } }, "ba": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "mil": _2, "net": _2, "org": _2, "rs": _3, "blogspot": _3 } }, "bb": { "$": 1, "succ": { "biz": _2, "co": _2, "com": _2, "edu": _2, "gov": _2, "info": _2, "net": _2, "org": _2, "store": _2, "tv": _2 } }, "bd": _8, "be": { "$": 1, "succ": { "ac": _2, "webhosting": _3, "blogspot": _3, "interhostsolutions": _9, "kuleuven": { "$": 0, "succ": { "ezproxy": _3 } }, "myspreadshop": _3, "transurl": _5 } }, "bf": _7, "bg": { "$": 1, "succ": { "0": _2, "1": _2, "2": _2, "3": _2, "4": _2, "5": _2, "6": _2, "7": _2, "8": _2, "9": _2, "a": _2, "b": _2, "c": _2, "d": _2, "e": _2, "f": _2, "g": _2, "h": _2, "i": _2, "j": _2, "k": _2, "l": _2, "m": _2, "n": _2, "o": _2, "p": _2, "q": _2, "r": _2, "s": _2, "t": _2, "u": _2, "v": _2, "w": _2, "x": _2, "y": _2, "z": _2, "blogspot": _3, "barsy": _3 } }, "bh": _4, "bi": { "$": 1, "succ": { "co": _2, "com": _2, "edu": _2, "or": _2, "org": _2 } }, "biz": { "$": 1, "succ": { "cloudns": _3, "jozi": _3, "dyndns": _3, "for-better": _3, "for-more": _3, "for-some": _3, "for-the": _3, "selfip": _3, "webhop": _3, "orx": _3, "mmafan": _3, "myftp": _3, "no-ip": _3, "dscloud": _3 } }, "bj": { "$": 1, "succ": { "asso": _2, "barreau": _2, "gouv": _2, "blogspot": _3 } }, "bm": _4, "bn": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "net": _2, "org": _2, "co": _3 } }, "bo": { "$": 1, "succ": { "com": _2, "edu": _2, "gob": _2, "int": _2, "org": _2, "net": _2, "mil": _2, "tv": _2, "web": _2, "academia": _2, "agro": _2, "arte": _2, "blog": _2, "bolivia": _2, "ciencia": _2, "cooperativa": _2, "democracia": _2, "deporte": _2, "ecologia": _2, "economia": _2, "empresa": _2, "indigena": _2, "industria": _2, "info": _2, "medicina": _2, "movimiento": _2, "musica": _2, "natural": _2, "nombre": _2, "noticias": _2, "patria": _2, "politica": _2, "profesional": _2, "plurinacional": _2, "pueblo": _2, "revista": _2, "salud": _2, "tecnologia": _2, "tksat": _2, "transporte": _2, "wiki": _2 } }, "br": { "$": 1, "succ": { "9guacu": _2, "abc": _2, "adm": _2, "adv": _2, "agr": _2, "aju": _2, "am": _2, "anani": _2, "aparecida": _2, "app": _2, "arq": _2, "art": _2, "ato": _2, "b": _2, "barueri": _2, "belem": _2, "bhz": _2, "bib": _2, "bio": _2, "blog": _2, "bmd": _2, "boavista": _2, "bsb": _2, "campinagrande": _2, "campinas": _2, "caxias": _2, "cim": _2, "cng": _2, "cnt": _2, "com": { "$": 1, "succ": { "blogspot": _3, "virtualcloud": { "$": 0, "succ": { "scale": { "$": 0, "succ": { "users": _3 } } } } } }, "contagem": _2, "coop": _2, "coz": _2, "cri": _2, "cuiaba": _2, "curitiba": _2, "def": _2, "des": _2, "det": _2, "dev": _2, "ecn": _2, "eco": _2, "edu": _2, "emp": _2, "enf": _2, "eng": _2, "esp": _2, "etc": _2, "eti": _2, "far": _2, "feira": _2, "flog": _2, "floripa": _2, "fm": _2, "fnd": _2, "fortal": _2, "fot": _2, "foz": _2, "fst": _2, "g12": _2, "geo": _2, "ggf": _2, "goiania": _2, "gov": { "$": 1, "succ": { "ac": _2, "al": _2, "am": _2, "ap": _2, "ba": _2, "ce": _2, "df": _2, "es": _2, "go": _2, "ma": _2, "mg": _2, "ms": _2, "mt": _2, "pa": _2, "pb": _2, "pe": _2, "pi": _2, "pr": _2, "rj": _2, "rn": _2, "ro": _2, "rr": _2, "rs": _2, "sc": _2, "se": _2, "sp": _2, "to": _2 } }, "gru": _2, "imb": _2, "ind": _2, "inf": _2, "jab": _2, "jampa": _2, "jdf": _2, "joinville": _2, "jor": _2, "jus": _2, "leg": { "$": 1, "succ": { "ac": _3, "al": _3, "am": _3, "ap": _3, "ba": _3, "ce": _3, "df": _3, "es": _3, "go": _3, "ma": _3, "mg": _3, "ms": _3, "mt": _3, "pa": _3, "pb": _3, "pe": _3, "pi": _3, "pr": _3, "rj": _3, "rn": _3, "ro": _3, "rr": _3, "rs": _3, "sc": _3, "se": _3, "sp": _3, "to": _3 } }, "lel": _2, "log": _2, "londrina": _2, "macapa": _2, "maceio": _2, "manaus": _2, "maringa": _2, "mat": _2, "med": _2, "mil": _2, "morena": _2, "mp": _2, "mus": _2, "natal": _2, "net": _2, "niteroi": _2, "nom": _8, "not": _2, "ntr": _2, "odo": _2, "ong": _2, "org": _2, "osasco": _2, "palmas": _2, "poa": _2, "ppg": _2, "pro": _2, "psc": _2, "psi": _2, "pvh": _2, "qsl": _2, "radio": _2, "rec": _2, "recife": _2, "rep": _2, "ribeirao": _2, "rio": _2, "riobranco": _2, "riopreto": _2, "salvador": _2, "sampa": _2, "santamaria": _2, "santoandre": _2, "saobernardo": _2, "saogonca": _2, "seg": _2, "sjc": _2, "slg": _2, "slz": _2, "sorocaba": _2, "srv": _2, "taxi": _2, "tc": _2, "tec": _2, "teo": _2, "the": _2, "tmp": _2, "trd": _2, "tur": _2, "tv": _2, "udi": _2, "vet": _2, "vix": _2, "vlog": _2, "wiki": _2, "zlg": _2 } }, "bs": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "edu": _2, "gov": _2, "we": _3 } }, "bt": _4, "bv": _2, "bw": { "$": 1, "succ": { "co": _2, "org": _2 } }, "by": { "$": 1, "succ": { "gov": _2, "mil": _2, "com": _6, "of": _2, "mycloud": _3, "mediatech": _3 } }, "bz": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "edu": _2, "gov": _2, "za": _3, "gsj": _3 } }, "ca": { "$": 1, "succ": { "ab": _2, "bc": _2, "mb": _2, "nb": _2, "nf": _2, "nl": _2, "ns": _2, "nt": _2, "nu": _2, "on": _2, "pe": _2, "qc": _2, "sk": _2, "yk": _2, "gc": _2, "barsy": _3, "awdev": _5, "co": _3, "blogspot": _3, "no-ip": _3, "myspreadshop": _3 } }, "cat": _2, "cc": { "$": 1, "succ": { "cloudns": _3, "ftpaccess": _3, "game-server": _3, "myphotos": _3, "scrapping": _3, "twmail": _3, "csx": _3, "fantasyleague": _3, "spawn": { "$": 0, "succ": { "instances": _3 } } } }, "cd": _7, "cf": _6, "cg": _2, "ch": { "$": 1, "succ": { "square7": _3, "blogspot": _3, "flow": { "$": 0, "succ": { "ae": { "$": 0, "succ": { "alp1": _3 } }, "appengine": _3 } }, "linkyard-cloud": _3, "dnsking": _3, "gotdns": _3, "myspreadshop": _3, "firenet": { "$": 0, "succ": { "*": _3, "svc": _5 } }, "12hp": _3, "2ix": _3, "4lima": _3, "lima-city": _3 } }, "ci": { "$": 1, "succ": { "org": _2, "or": _2, "com": _2, "co": _2, "edu": _2, "ed": _2, "ac": _2, "net": _2, "go": _2, "asso": _2, "xn--aroport-bya": _2, "aéroport": _2, "int": _2, "presse": _2, "md": _2, "gouv": _2, "fin": _3, "nl": _3 } }, "ck": _8, "cl": { "$": 1, "succ": { "co": _2, "gob": _2, "gov": _2, "mil": _2, "blogspot": _3 } }, "cm": { "$": 1, "succ": { "co": _2, "com": _2, "gov": _2, "net": _2 } }, "cn": { "$": 1, "succ": { "ac": _2, "com": { "$": 1, "succ": { "amazonaws": { "$": 0, "succ": { "compute": _5, "eb": { "$": 0, "succ": { "cn-north-1": _3, "cn-northwest-1": _3 } }, "elb": _5, "cn-north-1": _11 } } } }, "edu": _2, "gov": _2, "net": _2, "org": _2, "mil": _2, "xn--55qx5d": _2, "公司": _2, "xn--io0a7i": _2, "网络": _2, "xn--od0alg": _2, "網絡": _2, "ah": _2, "bj": _2, "cq": _2, "fj": _2, "gd": _2, "gs": _2, "gz": _2, "gx": _2, "ha": _2, "hb": _2, "he": _2, "hi": _2, "hl": _2, "hn": _2, "jl": _2, "js": _2, "jx": _2, "ln": _2, "nm": _2, "nx": _2, "qh": _2, "sc": _2, "sd": _2, "sh": _2, "sn": _2, "sx": _2, "tj": _2, "xj": _2, "xz": _2, "yn": _2, "zj": _2, "hk": _2, "mo": _2, "tw": _2, "instantcloud": _3, "quickconnect": _12 } }, "co": { "$": 1, "succ": { "arts": _2, "com": _6, "edu": _2, "firm": _2, "gov": _2, "info": _2, "int": _2, "mil": _2, "net": _2, "nom": _2, "org": _2, "rec": _2, "web": _2, "carrd": _3, "crd": _3, "otap": _5, "leadpages": _3, "lpages": _3, "mypi": _3, "n4t": _3, "repl": { "$": 2, "succ": { "id": _3 } }, "supabase": _3 } }, "com": { "$": 1, "succ": { "devcdnaccesso": _5, "adobeaemcloud": { "$": 2, "succ": { "dev": _5 } }, "airkitapps": _3, "airkitapps-au": _3, "aivencloud": _3, "kasserver": _3, "amazonaws": { "$": 0, "succ": { "compute": _5, "compute-1": _5, "us-east-1": { "$": 2, "succ": { "dualstack": _11 } }, "elb": _5, "s3": _3, "s3-ap-northeast-1": _3, "s3-ap-northeast-2": _3, "s3-ap-south-1": _3, "s3-ap-southeast-1": _3, "s3-ap-southeast-2": _3, "s3-ca-central-1": _3, "s3-eu-central-1": _3, "s3-eu-west-1": _3, "s3-eu-west-2": _3, "s3-eu-west-3": _3, "s3-external-1": _3, "s3-fips-us-gov-west-1": _3, "s3-sa-east-1": _3, "s3-us-gov-west-1": _3, "s3-us-east-2": _3, "s3-us-west-1": _3, "s3-us-west-2": _3, "ap-northeast-2": _14, "ap-south-1": _14, "ca-central-1": _14, "eu-central-1": _14, "eu-west-2": _14, "eu-west-3": _14, "us-east-2": _14, "ap-northeast-1": _13, "ap-southeast-1": _13, "ap-southeast-2": _13, "eu-west-1": _13, "sa-east-1": _13, "s3-website-us-east-1": _3, "s3-website-us-west-1": _3, "s3-website-us-west-2": _3, "s3-website-ap-northeast-1": _3, "s3-website-ap-southeast-1": _3, "s3-website-ap-southeast-2": _3, "s3-website-eu-west-1": _3, "s3-website-sa-east-1": _3 } }, "elasticbeanstalk": { "$": 2, "succ": { "ap-northeast-1": _3, "ap-northeast-2": _3, "ap-northeast-3": _3, "ap-south-1": _3, "ap-southeast-1": _3, "ap-southeast-2": _3, "ca-central-1": _3, "eu-central-1": _3, "eu-west-1": _3, "eu-west-2": _3, "eu-west-3": _3, "sa-east-1": _3, "us-east-1": _3, "us-east-2": _3, "us-gov-west-1": _3, "us-west-1": _3, "us-west-2": _3 } }, "awsglobalaccelerator": _3, "siiites": _3, "appspacehosted": _3, "appspaceusercontent": _3, "on-aptible": _3, "myasustor": _3, "balena-devices": _3, "betainabox": _3, "boutir": _3, "bplaced": _3, "cafjs": _3, "br": _3, "cn": _3, "de": _3, "eu": _3, "jpn": _3, "mex": _3, "ru": _3, "sa": _3, "uk": _3, "us": _3, "za": _3, "ar": _3, "hu": _3, "kr": _3, "no": _3, "qc": _3, "uy": _3, "africa": _3, "gr": _3, "co": _3, "jdevcloud": _3, "wpdevcloud": _3, "cloudcontrolled": _3, "cloudcontrolapp": _3, "trycloudflare": _3, "customer-oci": { "$": 0, "succ": { "*": _3, "oci": _5, "ocp": _5, "ocs": _5 } }, "dattolocal": _3, "dattorelay": _3, "dattoweb": _3, "mydatto": _3, "builtwithdark": _3, "datadetect": { "$": 0, "succ": { "demo": _3, "instance": _3 } }, "ddns5": _3, "discordsays": _3, "discordsez": _3, "drayddns": _3, "dreamhosters": _3, "mydrobo": _3, "dyndns-at-home": _3, "dyndns-at-work": _3, "dyndns-blog": _3, "dyndns-free": _3, "dyndns-home": _3, "dyndns-ip": _3, "dyndns-mail": _3, "dyndns-office": _3, "dyndns-pics": _3, "dyndns-remote": _3, "dyndns-server": _3, "dyndns-web": _3, "dyndns-wiki": _3, "dyndns-work": _3, "blogdns": _3, "cechire": _3, "dnsalias": _3, "dnsdojo": _3, "doesntexist": _3, "dontexist": _3, "doomdns": _3, "dyn-o-saur": _3, "dynalias": _3, "est-a-la-maison": _3, "est-a-la-masion": _3, "est-le-patron": _3, "est-mon-blogueur": _3, "from-ak": _3, "from-al": _3, "from-ar": _3, "from-ca": _3, "from-ct": _3, "from-dc": _3, "from-de": _3, "from-fl": _3, "from-ga": _3, "from-hi": _3, "from-ia": _3, "from-id": _3, "from-il": _3, "from-in": _3, "from-ks": _3, "from-ky": _3, "from-ma": _3, "from-md": _3, "from-mi": _3, "from-mn": _3, "from-mo": _3, "from-ms": _3, "from-mt": _3, "from-nc": _3, "from-nd": _3, "from-ne": _3, "from-nh": _3, "from-nj": _3, "from-nm": _3, "from-nv": _3, "from-oh": _3, "from-ok": _3, "from-or": _3, "from-pa": _3, "from-pr": _3, "from-ri": _3, "from-sc": _3, "from-sd": _3, "from-tn": _3, "from-tx": _3, "from-ut": _3, "from-va": _3, "from-vt": _3, "from-wa": _3, "from-wi": _3, "from-wv": _3, "from-wy": _3, "getmyip": _3, "gotdns": _3, "hobby-site": _3, "homelinux": _3, "homeunix": _3, "iamallama": _3, "is-a-anarchist": _3, "is-a-blogger": _3, "is-a-bookkeeper": _3, "is-a-bulls-fan": _3, "is-a-caterer": _3, "is-a-chef": _3, "is-a-conservative": _3, "is-a-cpa": _3, "is-a-cubicle-slave": _3, "is-a-democrat": _3, "is-a-designer": _3, "is-a-doctor": _3, "is-a-financialadvisor": _3, "is-a-geek": _3, "is-a-green": _3, "is-a-guru": _3, "is-a-hard-worker": _3, "is-a-hunter": _3, "is-a-landscaper": _3, "is-a-lawyer": _3, "is-a-liberal": _3, "is-a-libertarian": _3, "is-a-llama": _3, "is-a-musician": _3, "is-a-nascarfan": _3, "is-a-nurse": _3, "is-a-painter": _3, "is-a-personaltrainer": _3, "is-a-photographer": _3, "is-a-player": _3, "is-a-republican": _3, "is-a-rockstar": _3, "is-a-socialist": _3, "is-a-student": _3, "is-a-teacher": _3, "is-a-techie": _3, "is-a-therapist": _3, "is-an-accountant": _3, "is-an-actor": _3, "is-an-actress": _3, "is-an-anarchist": _3, "is-an-artist": _3, "is-an-engineer": _3, "is-an-entertainer": _3, "is-certified": _3, "is-gone": _3, "is-into-anime": _3, "is-into-cars": _3, "is-into-cartoons": _3, "is-into-games": _3, "is-leet": _3, "is-not-certified": _3, "is-slick": _3, "is-uberleet": _3, "is-with-theband": _3, "isa-geek": _3, "isa-hockeynut": _3, "issmarterthanyou": _3, "likes-pie": _3, "likescandy": _3, "neat-url": _3, "saves-the-whales": _3, "selfip": _3, "sells-for-less": _3, "sells-for-u": _3, "servebbs": _3, "simple-url": _3, "space-to-rent": _3, "teaches-yoga": _3, "writesthisblog": _3, "digitaloceanspaces": _5, "ddnsfree": _3, "ddnsgeek": _3, "giize": _3, "gleeze": _3, "kozow": _3, "loseyourip": _3, "ooguy": _3, "theworkpc": _3, "mytuleap": _3, "tuleap-partners": _3, "encoreapi": _3, "evennode": { "$": 0, "succ": { "eu-1": _3, "eu-2": _3, "eu-3": _3, "eu-4": _3, "us-1": _3, "us-2": _3, "us-3": _3, "us-4": _3 } }, "onfabrica": _3, "fbsbx": _15, "fastly-terrarium": _3, "fastvps-server": _3, "mydobiss": _3, "firebaseapp": _3, "fldrv": _3, "forgeblocks": _3, "framercanvas": _3, "freebox-os": _3, "freeboxos": _3, "freemyip": _3, "gentapps": _3, "gentlentapis": _3, "githubusercontent": _3, "0emm": _5, "appspot": { "$": 2, "succ": { "r": _5 } }, "codespot": _3, "googleapis": _3, "googlecode": _3, "pagespeedmobilizer": _3, "publishproxy": _3, "withgoogle": _3, "withyoutube": _3, "blogspot": _3, "awsmppl": _3, "herokuapp": _3, "herokussl": _3, "myravendb": _3, "impertrixcdn": _3, "impertrix": _3, "smushcdn": _3, "wphostedmail": _3, "wpmucdn": _3, "pixolino": _3, "amscompute": _3, "clicketcloud": _3, "dopaas": _3, "hidora": _3, "hosted-by-previder": _16, "hosteur": { "$": 0, "succ": { "rag-cloud": _3, "rag-cloud-ch": _3 } }, "ik-server": { "$": 0, "succ": { "jcloud": _3, "jcloud-ver-jpc": _3 } }, "jelastic": { "$": 0, "succ": { "demo": _3 } }, "kilatiron": _3, "massivegrid": _16, "wafaicloud": { "$": 0, "succ": { "jed": _3, "lon": _3, "ryd": _3 } }, "joyent": { "$": 0, "succ": { "cns": _5 } }, "ktistory": _3, "lpusercontent": _3, "lmpm": _17, "linode": { "$": 0, "succ": { "members": _3, "nodebalancer": _5 } }, "linodeobjects": _5, "linodeusercontent": { "$": 0, "succ": { "ip": _3 } }, "barsycenter": _3, "barsyonline": _3, "mazeplay": _3, "miniserver": _3, "meteorapp": _18, "hostedpi": _3, "mythic-beasts": { "$": 0, "succ": { "customer": _3, "caracal": _3, "fentiger": _3, "lynx": _3, "ocelot": _3, "oncilla": _3, "onza": _3, "sphinx": _3, "vs": _3, "x": _3, "yali": _3 } }, "nospamproxy": _9, "4u": _3, "nfshost": _3, "001www": _3, "ddnslive": _3, "myiphost": _3, "blogsyte": _3, "ciscofreak": _3, "damnserver": _3, "ditchyourip": _3, "dnsiskinky": _3, "dynns": _3, "geekgalaxy": _3, "health-carereform": _3, "homesecuritymac": _3, "homesecuritypc": _3, "myactivedirectory": _3, "mysecuritycamera": _3, "net-freaks": _3, "onthewifi": _3, "point2this": _3, "quicksytes": _3, "securitytactics": _3, "serveexchange": _3, "servehumour": _3, "servep2p": _3, "servesarcasm": _3, "stufftoread": _3, "unusualperson": _3, "workisboring": _3, "3utilities": _3, "ddnsking": _3, "myvnc": _3, "servebeer": _3, "servecounterstrike": _3, "serveftp": _3, "servegame": _3, "servehalflife": _3, "servehttp": _3, "serveirc": _3, "servemp3": _3, "servepics": _3, "servequake": _3, "observableusercontent": { "$": 0, "succ": { "static": _3 } }, "orsites": _3, "operaunite": _3, "authgear-staging": _3, "authgearapps": _3, "skygearapp": _3, "outsystemscloud": _3, "ownprovider": _3, "pgfog": _3, "pagefrontapp": _3, "pagexl": _3, "paywhirl": _5, "gotpantheon": _3, "platter-app": _3, "pleskns": _3, "postman-echo": _3, "prgmr": { "$": 0, "succ": { "xen": _3 } }, "pythonanywhere": _18, "qualifioapp": _3, "qbuser": _3, "qa2": _3, "dev-myqnapcloud": _3, "alpha-myqnapcloud": _3, "myqnapcloud": _3, "quipelements": _5, "rackmaze": _3, "rhcloud": _3, "render": _17, "onrender": _3, "logoip": _3, "scrysec": _3, "firewall-gateway": _3, "myshopblocks": _3, "myshopify": _3, "shopitsite": _3, "1kapp": _3, "appchizi": _3, "applinzi": _3, "sinaapp": _3, "vipsinaapp": _3, "bounty-full": { "$": 2, "succ": { "alpha": _3, "beta": _3 } }, "try-snowplow": _3, "stackhero-network": _3, "playstation-cloud": _3, "myspreadshop": _3, "stdlib": { "$": 0, "succ": { "api": _3 } }, "temp-dns": _3, "dsmynas": _3, "familyds": _3, "tb-hosting": _19, "reservd": _3, "thingdustdata": _3, "bloxcms": _3, "townnews-staging": _3, "typeform": { "$": 0, "succ": { "pro": _3 } }, "hk": _3, "vultrobjects": _5, "wafflecell": _3, "reserve-online": _3, "hotelwithflight": _3, "remotewd": _3, "wiardweb": _20, "messwithdns": _3, "woltlab-demo": _3, "wpenginepowered": { "$": 2, "succ": { "js": _3 } }, "wixsite": _3, "xnbay": { "$": 2, "succ": { "u2": _3, "u2-local": _3 } }, "yolasite": _3 } }, "coop": _2, "cr": { "$": 1, "succ": { "ac": _2, "co": _2, "ed": _2, "fi": _2, "go": _2, "or": _2, "sa": _2 } }, "cu": { "$": 1, "succ": { "com": _2, "edu": _2, "org": _2, "net": _2, "gov": _2, "inf": _2 } }, "cv": { "$": 1, "succ": { "com": _2, "edu": _2, "int": _2, "nome": _2, "org": _2, "blogspot": _3 } }, "cw": _21, "cx": { "$": 1, "succ": { "gov": _2, "ath": _3, "info": _3 } }, "cy": { "$": 1, "succ": { "ac": _2, "biz": _2, "com": { "$": 1, "succ": { "blogspot": _3, "scaleforce": _22 } }, "ekloges": _2, "gov": _2, "ltd": _2, "mil": _2, "net": _2, "org": _2, "press": _2, "pro": _2, "tm": _2 } }, "cz": { "$": 1, "succ": { "co": _3, "realm": _3, "e4": _3, "blogspot": _3, "metacentrum": { "$": 0, "succ": { "cloud": _5, "custom": _3 } }, "muni": { "$": 0, "succ": { "cloud": { "$": 0, "succ": { "flt": _3, "usr": _3 } } } } } }, "de": { "$": 1, "succ": { "bplaced": _3, "square7": _3, "com": _3, "cosidns": { "$": 0, "succ": { "dyn": _3 } }, "dynamisches-dns": _3, "dnsupdater": _3, "internet-dns": _3, "l-o-g-i-n": _3, "dnshome": _3, "fuettertdasnetz": _3, "isteingeek": _3, "istmein": _3, "lebtimnetz": _3, "leitungsen": _3, "traeumtgerade": _3, "ddnss": { "$": 2, "succ": { "dyn": _3, "dyndns": _3 } }, "dyndns1": _3, "dyn-ip24": _3, "home-webserver": { "$": 2, "succ": { "dyn": _3 } }, "myhome-server": _3, "frusky": _5, "goip": _3, "blogspot": _3, "xn--gnstigbestellen-zvb": _3, "günstigbestellen": _3, "xn--gnstigliefern-wob": _3, "günstigliefern": _3, "hs-heilbronn": { "$": 0, "succ": { "it": _20 } }, "dyn-berlin": _3, "in-berlin": _3, "in-brb": _3, "in-butter": _3, "in-dsl": _3, "in-vpn": _3, "mein-iserv": _3, "schulserver": _3, "test-iserv": _3, "keymachine": _3, "git-repos": _3, "lcube-server": _3, "svn-repos": _3, "barsy": _3, "logoip": _3, "firewall-gateway": _3, "my-gateway": _3, "my-router": _3, "spdns": _3, "speedpartner": { "$": 0, "succ": { "customer": _3 } }, "myspreadshop": _3, "taifun-dns": _3, "12hp": _3, "2ix": _3, "4lima": _3, "lima-city": _3, "dd-dns": _3, "dray-dns": _3, "draydns": _3, "dyn-vpn": _3, "dynvpn": _3, "mein-vigor": _3, "my-vigor": _3, "my-wan": _3, "syno-ds": _3, "synology-diskstation": _3, "synology-ds": _3, "uberspace": _5, "virtualuser": _3, "virtual-user": _3, "community-pro": _3, "diskussionsbereich": _3 } }, "dj": _2, "dk": { "$": 1, "succ": { "biz": _3, "co": _3, "firm": _3, "reg": _3, "store": _3, "blogspot": _3, "myspreadshop": _3 } }, "dm": _4, "do": { "$": 1, "succ": { "art": _2, "com": _2, "edu": _2, "gob": _2, "gov": _2, "mil": _2, "net": _2, "org": _2, "sld": _2, "web": _2 } }, "dz": { "$": 1, "succ": { "art": _2, "asso": _2, "com": _2, "edu": _2, "gov": _2, "org": _2, "net": _2, "pol": _2, "soc": _2, "tm": _2 } }, "ec": { "$": 1, "succ": { "com": _2, "info": _2, "net": _2, "fin": _2, "k12": _2, "med": _2, "pro": _2, "org": _2, "edu": _2, "gov": _2, "gob": _2, "mil": _2, "base": _3, "official": _3 } }, "edu": { "$": 1, "succ": { "rit": { "$": 0, "succ": { "git-pages": _3 } } } }, "ee": { "$": 1, "succ": { "edu": _2, "gov": _2, "riik": _2, "lib": _2, "med": _2, "com": _6, "pri": _2, "aip": _2, "org": _2, "fie": _2 } }, "eg": { "$": 1, "succ": { "com": _6, "edu": _2, "eun": _2, "gov": _2, "mil": _2, "name": _2, "net": _2, "org": _2, "sci": _2 } }, "er": _8, "es": { "$": 1, "succ": { "com": _6, "nom": _2, "org": _2, "gob": _2, "edu": _2, "myspreadshop": _3 } }, "et": { "$": 1, "succ": { "com": _2, "gov": _2, "org": _2, "edu": _2, "biz": _2, "name": _2, "info": _2, "net": _2 } }, "eu": { "$": 1, "succ": { "airkitapps": _3, "mycd": _3, "cloudns": _3, "dogado": _23, "barsy": _3, "wellbeingzone": _3, "spdns": _3, "transurl": _5, "diskstation": _3 } }, "fi": { "$": 1, "succ": { "aland": _2, "dy": _3, "blogspot": _3, "xn--hkkinen-5wa": _3, "häkkinen": _3, "iki": _3, "cloudplatform": { "$": 0, "succ": { "fi": _3 } }, "datacenter": { "$": 0, "succ": { "demo": _3, "paas": _3 } }, "kapsi": _3, "myspreadshop": _3 } }, "fj": { "$": 1, "succ": { "ac": _2, "biz": _2, "com": _2, "gov": _2, "info": _2, "mil": _2, "name": _2, "net": _2, "org": _2, "pro": _2 } }, "fk": _8, "fm": { "$": 1, "succ": { "com": _2, "edu": _2, "net": _2, "org": _2, "radio": _3 } }, "fo": _2, "fr": { "$": 1, "succ": { "asso": _2, "com": _2, "gouv": _2, "nom": _2, "prd": _2, "tm": _2, "aeroport": _2, "avocat": _2, "avoues": _2, "cci": _2, "chambagri": _2, "chirurgiens-dentistes": _2, "experts-comptables": _2, "geometre-expert": _2, "greta": _2, "huissier-justice": _2, "medecin": _2, "notaires": _2, "pharmacien": _2, "port": _2, "veterinaire": _2, "en-root": _3, "fbx-os": _3, "fbxos": _3, "freebox-os": _3, "freeboxos": _3, "blogspot": _3, "goupile": _3, "on-web": _3, "chirurgiens-dentistes-en-france": _3, "myspreadshop": _3, "ynh": _3 } }, "ga": _2, "gb": _2, "gd": { "$": 1, "succ": { "edu": _2, "gov": _2 } }, "ge": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "org": _2, "mil": _2, "net": _2, "pvt": _2 } }, "gf": _2, "gg": { "$": 1, "succ": { "co": _2, "net": _2, "org": _2, "kaas": _3, "cya": _3, "panel": { "$": 2, "succ": { "daemon": _3 } } } }, "gh": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "org": _2, "mil": _2 } }, "gi": { "$": 1, "succ": { "com": _2, "ltd": _2, "gov": _2, "mod": _2, "edu": _2, "org": _2 } }, "gl": { "$": 1, "succ": { "co": _2, "com": _2, "edu": _2, "net": _2, "org": _2, "biz": _3, "xx": _3 } }, "gm": _2, "gn": { "$": 1, "succ": { "ac": _2, "com": _2, "edu": _2, "gov": _2, "org": _2, "net": _2 } }, "gov": _2, "gp": { "$": 1, "succ": { "com": _2, "net": _2, "mobi": _2, "edu": _2, "org": _2, "asso": _2, "app": _3 } }, "gq": _2, "gr": { "$": 1, "succ": { "com": _2, "edu": _2, "net": _2, "org": _2, "gov": _2, "blogspot": _3 } }, "gs": _2, "gt": { "$": 1, "succ": { "com": _2, "edu": _2, "gob": _2, "ind": _2, "mil": _2, "net": _2, "org": _2, "blog": _3, "de": _3, "to": _3 } }, "gu": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "guam": _2, "info": _2, "net": _2, "org": _2, "web": _2 } }, "gw": _2, "gy": { "$": 1, "succ": { "co": _2, "com": _2, "edu": _2, "gov": _2, "net": _2, "org": _2, "be": _3 } }, "hk": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "idv": _2, "net": _2, "org": _2, "xn--55qx5d": _2, "公司": _2, "xn--wcvs22d": _2, "教育": _2, "xn--lcvr32d": _2, "敎育": _2, "xn--mxtq1m": _2, "政府": _2, "xn--gmqw5a": _2, "個人": _2, "xn--ciqpn": _2, "个人": _2, "xn--gmq050i": _2, "箇人": _2, "xn--zf0avx": _2, "網络": _2, "xn--io0a7i": _2, "网络": _2, "xn--mk0axi": _2, "组織": _2, "xn--od0alg": _2, "網絡": _2, "xn--od0aq3b": _2, "网絡": _2, "xn--tn0ag": _2, "组织": _2, "xn--uc0atv": _2, "組織": _2, "xn--uc0ay4a": _2, "組织": _2, "blogspot": _3, "secaas": _3, "ltd": _3, "inc": _3 } }, "hm": _2, "hn": { "$": 1, "succ": { "com": _2, "edu": _2, "org": _2, "net": _2, "mil": _2, "gob": _2, "cc": _3 } }, "hr": { "$": 1, "succ": { "iz": _2, "from": _2, "name": _2, "com": _2, "blogspot": _3, "free": _3 } }, "ht": { "$": 1, "succ": { "com": _2, "shop": _2, "firm": _2, "info": _2, "adult": _2, "net": _2, "pro": _2, "org": _2, "med": _2, "art": _2, "coop": _2, "pol": _2, "asso": _2, "edu": _2, "rel": _2, "gouv": _2, "perso": _2 } }, "hu": { "$": 1, "succ": { "2000": _2, "co": _2, "info": _2, "org": _2, "priv": _2, "sport": _2, "tm": _2, "agrar": _2, "bolt": _2, "casino": _2, "city": _2, "erotica": _2, "erotika": _2, "film": _2, "forum": _2, "games": _2, "hotel": _2, "ingatlan": _2, "jogasz": _2, "konyvelo": _2, "lakas": _2, "media": _2, "news": _2, "reklam": _2, "sex": _2, "shop": _2, "suli": _2, "szex": _2, "tozsde": _2, "utazas": _2, "video": _2, "blogspot": _3 } }, "id": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _6, "desa": _2, "go": _2, "mil": _2, "my": { "$": 1, "succ": { "rss": _5 } }, "net": _2, "or": _2, "ponpes": _2, "sch": _2, "web": _2, "flap": _3, "forte": _3 } }, "ie": { "$": 1, "succ": { "gov": _2, "blogspot": _3, "myspreadshop": _3 } }, "il": { "$": 1, "succ": { "ac": _2, "co": { "$": 1, "succ": { "ravpage": _3, "blogspot": _3, "tabitorder": _3 } }, "gov": _2, "idf": _2, "k12": _2, "muni": _2, "net": _2, "org": _2 } }, "im": { "$": 1, "succ": { "ac": _2, "co": { "$": 1, "succ": { "ltd": _2, "plc": _2 } }, "com": _2, "net": _2, "org": _2, "tt": _2, "tv": _2, "ro": _3 } }, "in": { "$": 1, "succ": { "co": _2, "firm": _2, "net": _2, "org": _2, "gen": _2, "ind": _2, "nic": _2, "ac": _2, "edu": _2, "res": _2, "gov": _2, "mil": _2, "web": _3, "cloudns": _3, "blogspot": _3, "barsy": _3, "supabase": _3 } }, "info": { "$": 1, "succ": { "cloudns": _3, "dynamic-dns": _3, "dyndns": _3, "barrel-of-knowledge": _3, "barrell-of-knowledge": _3, "for-our": _3, "groks-the": _3, "groks-this": _3, "here-for-more": _3, "knowsitall": _3, "selfip": _3, "webhop": _3, "barsy": _3, "mayfirst": _3, "forumz": _3, "nsupdate": _3, "dvrcam": _3, "ilovecollege": _3, "no-ip": _3, "dnsupdate": _3, "v-info": _3 } }, "int": { "$": 1, "succ": { "eu": _2 } }, "io": { "$": 1, "succ": { "2038": _3, "com": _2, "apigee": _3, "b-data": _3, "backplaneapp": _3, "banzaicloud": { "$": 0, "succ": { "app": _3, "backyards": _5 } }, "bitbucket": _3, "bluebite": _3, "boxfuse": _3, "browsersafetymark": _3, "bigv": { "$": 0, "succ": { "uk0": _3 } }, "cleverapps": _3, "dappnode": { "$": 0, "succ": { "dyndns": _3 } }, "dedyn": _3, "drud": _3, "definima": _3, "fh-muenster": _3, "shw": _3, "forgerock": { "$": 0, "succ": { "id": _3 } }, "ghost": _3, "github": _3, "gitlab": _3, "lolipop": _3, "hasura-app": _3, "hostyhosting": _3, "moonscale": _5, "beebyte": _16, "beebyteapp": { "$": 0, "succ": { "sekd1": _3 } }, "jele": _3, "unispace": { "$": 0, "succ": { "cloud-fr1": _3 } }, "webthings": _3, "loginline": _3, "barsy": _3, "azurecontainer": _5, "ngrok": _3, "nodeart": { "$": 0, "succ": { "stage": _3 } }, "nid": _3, "pantheonsite": _3, "dyn53": _3, "pstmn": { "$": 2, "succ": { "mock": _3 } }, "protonet": _3, "qoto": _3, "qcx": { "$": 2, "succ": { "sys": _5 } }, "vaporcloud": _3, "vbrplsbx": { "$": 0, "succ": { "g": _3 } }, "on-k3s": _5, "on-rio": _5, "readthedocs": _3, "resindevice": _3, "resinstaging": { "$": 0, "succ": { "devices": _3 } }, "hzc": _3, "sandcats": _3, "shiftcrypto": _3, "shiftedit": _3, "mo-siemens": _3, "musician": _3, "lair": _15, "stolos": _5, "spacekit": _3, "utwente": _3, "s5y": _5, "edugit": _3, "telebit": _3, "thingdust": { "$": 0, "succ": { "dev": _26, "disrec": _26, "prod": _27, "testing": _26 } }, "tickets": _3, "upli": _3, "wedeploy": _3, "editorx": _3, "basicserver": _3, "virtualserver": _3 } }, "iq": _28, "ir": { "$": 1, "succ": { "ac": _2, "co": _2, "gov": _2, "id": _2, "net": _2, "org": _2, "sch": _2, "xn--mgba3a4f16a": _2, "ایران": _2, "xn--mgba3a4fra": _2, "ايران": _2 } }, "is": { "$": 1, "succ": { "net": _2, "com": _2, "edu": _2, "gov": _2, "org": _2, "int": _2, "cupcake": _3, "blogspot": _3 } }, "it": { "$": 1, "succ": { "gov": _2, "edu": _2, "abr": _2, "abruzzo": _2, "aosta-valley": _2, "aostavalley": _2, "bas": _2, "basilicata": _2, "cal": _2, "calabria": _2, "cam": _2, "campania": _2, "emilia-romagna": _2, "emiliaromagna": _2, "emr": _2, "friuli-v-giulia": _2, "friuli-ve-giulia": _2, "friuli-vegiulia": _2, "friuli-venezia-giulia": _2, "friuli-veneziagiulia": _2, "friuli-vgiulia": _2, "friuliv-giulia": _2, "friulive-giulia": _2, "friulivegiulia": _2, "friulivenezia-giulia": _2, "friuliveneziagiulia": _2, "friulivgiulia": _2, "fvg": _2, "laz": _2, "lazio": _2, "lig": _2, "liguria": _2, "lom": _2, "lombardia": _2, "lombardy": _2, "lucania": _2, "mar": _2, "marche": _2, "mol": _2, "molise": _2, "piedmont": _2, "piemonte": _2, "pmn": _2, "pug": _2, "puglia": _2, "sar": _2, "sardegna": _2, "sardinia": _2, "sic": _2, "sicilia": _2, "sicily": _2, "taa": _2, "tos": _2, "toscana": _2, "trentin-sud-tirol": _2, "xn--trentin-sd-tirol-rzb": _2, "trentin-süd-tirol": _2, "trentin-sudtirol": _2, "xn--trentin-sdtirol-7vb": _2, "trentin-südtirol": _2, "trentin-sued-tirol": _2, "trentin-suedtirol": _2, "trentino-a-adige": _2, "trentino-aadige": _2, "trentino-alto-adige": _2, "trentino-altoadige": _2, "trentino-s-tirol": _2, "trentino-stirol": _2, "trentino-sud-tirol": _2, "xn--trentino-sd-tirol-c3b": _2, "trentino-süd-tirol": _2, "trentino-sudtirol": _2, "xn--trentino-sdtirol-szb": _2, "trentino-südtirol": _2, "trentino-sued-tirol": _2, "trentino-suedtirol": _2, "trentino": _2, "trentinoa-adige": _2, "trentinoaadige": _2, "trentinoalto-adige": _2, "trentinoaltoadige": _2, "trentinos-tirol": _2, "trentinostirol": _2, "trentinosud-tirol": _2, "xn--trentinosd-tirol-rzb": _2, "trentinosüd-tirol": _2, "trentinosudtirol": _2, "xn--trentinosdtirol-7vb": _2, "trentinosüdtirol": _2, "trentinosued-tirol": _2, "trentinosuedtirol": _2, "trentinsud-tirol": _2, "xn--trentinsd-tirol-6vb": _2, "trentinsüd-tirol": _2, "trentinsudtirol": _2, "xn--trentinsdtirol-nsb": _2, "trentinsüdtirol": _2, "trentinsued-tirol": _2, "trentinsuedtirol": _2, "tuscany": _2, "umb": _2, "umbria": _2, "val-d-aosta": _2, "val-daosta": _2, "vald-aosta": _2, "valdaosta": _2, "valle-aosta": _2, "valle-d-aosta": _2, "valle-daosta": _2, "valleaosta": _2, "valled-aosta": _2, "valledaosta": _2, "vallee-aoste": _2, "xn--valle-aoste-ebb": _2, "vallée-aoste": _2, "vallee-d-aoste": _2, "xn--valle-d-aoste-ehb": _2, "vallée-d-aoste": _2, "valleeaoste": _2, "xn--valleaoste-e7a": _2, "valléeaoste": _2, "valleedaoste": _2, "xn--valledaoste-ebb": _2, "valléedaoste": _2, "vao": _2, "vda": _2, "ven": _2, "veneto": _2, "ag": _2, "agrigento": _2, "al": _2, "alessandria": _2, "alto-adige": _2, "altoadige": _2, "an": _2, "ancona": _2, "andria-barletta-trani": _2, "andria-trani-barletta": _2, "andriabarlettatrani": _2, "andriatranibarletta": _2, "ao": _2, "aosta": _2, "aoste": _2, "ap": _2, "aq": _2, "aquila": _2, "ar": _2, "arezzo": _2, "ascoli-piceno": _2, "ascolipiceno": _2, "asti": _2, "at": _2, "av": _2, "avellino": _2, "ba": _2, "balsan-sudtirol": _2, "xn--balsan-sdtirol-nsb": _2, "balsan-südtirol": _2, "balsan-suedtirol": _2, "balsan": _2, "bari": _2, "barletta-trani-andria": _2, "barlettatraniandria": _2, "belluno": _2, "benevento": _2, "bergamo": _2, "bg": _2, "bi": _2, "biella": _2, "bl": _2, "bn": _2, "bo": _2, "bologna": _2, "bolzano-altoadige": _2, "bolzano": _2, "bozen-sudtirol": _2, "xn--bozen-sdtirol-2ob": _2, "bozen-südtirol": _2, "bozen-suedtirol": _2, "bozen": _2, "br": _2, "brescia": _2, "brindisi": _2, "bs": _2, "bt": _2, "bulsan-sudtirol": _2, "xn--bulsan-sdtirol-nsb": _2, "bulsan-südtirol": _2, "bulsan-suedtirol": _2, "bulsan": _2, "bz": _2, "ca": _2, "cagliari": _2, "caltanissetta": _2, "campidano-medio": _2, "campidanomedio": _2, "campobasso": _2, "carbonia-iglesias": _2, "carboniaiglesias": _2, "carrara-massa": _2, "carraramassa": _2, "caserta": _2, "catania": _2, "catanzaro": _2, "cb": _2, "ce": _2, "cesena-forli": _2, "xn--cesena-forl-mcb": _2, "cesena-forlì": _2, "cesenaforli": _2, "xn--cesenaforl-i8a": _2, "cesenaforlì": _2, "ch": _2, "chieti": _2, "ci": _2, "cl": _2, "cn": _2, "co": _2, "como": _2, "cosenza": _2, "cr": _2, "cremona": _2, "crotone": _2, "cs": _2, "ct": _2, "cuneo": _2, "cz": _2, "dell-ogliastra": _2, "dellogliastra": _2, "en": _2, "enna": _2, "fc": _2, "fe": _2, "fermo": _2, "ferrara": _2, "fg": _2, "fi": _2, "firenze": _2, "florence": _2, "fm": _2, "foggia": _2, "forli-cesena": _2, "xn--forl-cesena-fcb": _2, "forlì-cesena": _2, "forlicesena": _2, "xn--forlcesena-c8a": _2, "forlìcesena": _2, "fr": _2, "frosinone": _2, "ge": _2, "genoa": _2, "genova": _2, "go": _2, "gorizia": _2, "gr": _2, "grosseto": _2, "iglesias-carbonia": _2, "iglesiascarbonia": _2, "im": _2, "imperia": _2, "is": _2, "isernia": _2, "kr": _2, "la-spezia": _2, "laquila": _2, "laspezia": _2, "latina": _2, "lc": _2, "le": _2, "lecce": _2, "lecco": _2, "li": _2, "livorno": _2, "lo": _2, "lodi": _2, "lt": _2, "lu": _2, "lucca": _2, "macerata": _2, "mantova": _2, "massa-carrara": _2, "massacarrara": _2, "matera": _2, "mb": _2, "mc": _2, "me": _2, "medio-campidano": _2, "mediocampidano": _2, "messina": _2, "mi": _2, "milan": _2, "milano": _2, "mn": _2, "mo": _2, "modena": _2, "monza-brianza": _2, "monza-e-della-brianza": _2, "monza": _2, "monzabrianza": _2, "monzaebrianza": _2, "monzaedellabrianza": _2, "ms": _2, "mt": _2, "na": _2, "naples": _2, "napoli": _2, "no": _2, "novara": _2, "nu": _2, "nuoro": _2, "og": _2, "ogliastra": _2, "olbia-tempio": _2, "olbiatempio": _2, "or": _2, "oristano": _2, "ot": _2, "pa": _2, "padova": _2, "padua": _2, "palermo": _2, "parma": _2, "pavia": _2, "pc": _2, "pd": _2, "pe": _2, "perugia": _2, "pesaro-urbino": _2, "pesarourbino": _2, "pescara": _2, "pg": _2, "pi": _2, "piacenza": _2, "pisa": _2, "pistoia": _2, "pn": _2, "po": _2, "pordenone": _2, "potenza": _2, "pr": _2, "prato": _2, "pt": _2, "pu": _2, "pv": _2, "pz": _2, "ra": _2, "ragusa": _2, "ravenna": _2, "rc": _2, "re": _2, "reggio-calabria": _2, "reggio-emilia": _2, "reggiocalabria": _2, "reggioemilia": _2, "rg": _2, "ri": _2, "rieti": _2, "rimini": _2, "rm": _2, "rn": _2, "ro": _2, "roma": _2, "rome": _2, "rovigo": _2, "sa": _2, "salerno": _2, "sassari": _2, "savona": _2, "si": _2, "siena": _2, "siracusa": _2, "so": _2, "sondrio": _2, "sp": _2, "sr": _2, "ss": _2, "suedtirol": _2, "xn--sdtirol-n2a": _2, "südtirol": _2, "sv": _2, "ta": _2, "taranto": _2, "te": _2, "tempio-olbia": _2, "tempioolbia": _2, "teramo": _2, "terni": _2, "tn": _2, "to": _2, "torino": _2, "tp": _2, "tr": _2, "trani-andria-barletta": _2, "trani-barletta-andria": _2, "traniandriabarletta": _2, "tranibarlettaandria": _2, "trapani": _2, "trento": _2, "treviso": _2, "trieste": _2, "ts": _2, "turin": _2, "tv": _2, "ud": _2, "udine": _2, "urbino-pesaro": _2, "urbinopesaro": _2, "va": _2, "varese": _2, "vb": _2, "vc": _2, "ve": _2, "venezia": _2, "venice": _2, "verbania": _2, "vercelli": _2, "verona": _2, "vi": _2, "vibo-valentia": _2, "vibovalentia": _2, "vicenza": _2, "viterbo": _2, "vr": _2, "vs": _2, "vt": _2, "vv": _2, "blogspot": _3, "neen": { "$": 0, "succ": { "jc": _3 } }, "tim": { "$": 0, "succ": { "open": { "$": 0, "succ": { "jelastic": _9 } } } }, "16-b": _3, "32-b": _3, "64-b": _3, "myspreadshop": _3, "syncloud": _3 } }, "je": { "$": 1, "succ": { "co": _2, "net": _2, "org": _2, "of": _3 } }, "jm": _8, "jo": { "$": 1, "succ": { "com": _2, "org": _2, "net": _2, "edu": _2, "sch": _2, "gov": _2, "mil": _2, "name": _2 } }, "jobs": _2, "jp": { "$": 1, "succ": { "ac": _2, "ad": _2, "co": _2, "ed": _2, "go": _2, "gr": _2, "lg": _2, "ne": { "$": 1, "succ": { "aseinet": _24, "gehirn": _3 } }, "or": _2, "aichi": { "$": 1, "succ": { "aisai": _2, "ama": _2, "anjo": _2, "asuke": _2, "chiryu": _2, "chita": _2, "fuso": _2, "gamagori": _2, "handa": _2, "hazu": _2, "hekinan": _2, "higashiura": _2, "ichinomiya": _2, "inazawa": _2, "inuyama": _2, "isshiki": _2, "iwakura": _2, "kanie": _2, "kariya": _2, "kasugai": _2, "kira": _2, "kiyosu": _2, "komaki": _2, "konan": _2, "kota": _2, "mihama": _2, "miyoshi": _2, "nishio": _2, "nisshin": _2, "obu": _2, "oguchi": _2, "oharu": _2, "okazaki": _2, "owariasahi": _2, "seto": _2, "shikatsu": _2, "shinshiro": _2, "shitara": _2, "tahara": _2, "takahama": _2, "tobishima": _2, "toei": _2, "togo": _2, "tokai": _2, "tokoname": _2, "toyoake": _2, "toyohashi": _2, "toyokawa": _2, "toyone": _2, "toyota": _2, "tsushima": _2, "yatomi": _2 } }, "akita": { "$": 1, "succ": { "akita": _2, "daisen": _2, "fujisato": _2, "gojome": _2, "hachirogata": _2, "happou": _2, "higashinaruse": _2, "honjo": _2, "honjyo": _2, "ikawa": _2, "kamikoani": _2, "kamioka": _2, "katagami": _2, "kazuno": _2, "kitaakita": _2, "kosaka": _2, "kyowa": _2, "misato": _2, "mitane": _2, "moriyoshi": _2, "nikaho": _2, "noshiro": _2, "odate": _2, "oga": _2, "ogata": _2, "semboku": _2, "yokote": _2, "yurihonjo": _2 } }, "aomori": { "$": 1, "succ": { "aomori": _2, "gonohe": _2, "hachinohe": _2, "hashikami": _2, "hiranai": _2, "hirosaki": _2, "itayanagi": _2, "kuroishi": _2, "misawa": _2, "mutsu": _2, "nakadomari": _2, "noheji": _2, "oirase": _2, "owani": _2, "rokunohe": _2, "sannohe": _2, "shichinohe": _2, "shingo": _2, "takko": _2, "towada": _2, "tsugaru": _2, "tsuruta": _2 } }, "chiba": { "$": 1, "succ": { "abiko": _2, "asahi": _2, "chonan": _2, "chosei": _2, "choshi": _2, "chuo": _2, "funabashi": _2, "futtsu": _2, "hanamigawa": _2, "ichihara": _2, "ichikawa": _2, "ichinomiya": _2, "inzai": _2, "isumi": _2, "kamagaya": _2, "kamogawa": _2, "kashiwa": _2, "katori": _2, "katsuura": _2, "kimitsu": _2, "kisarazu": _2, "kozaki": _2, "kujukuri": _2, "kyonan": _2, "matsudo": _2, "midori": _2, "mihama": _2, "minamiboso": _2, "mobara": _2, "mutsuzawa": _2, "nagara": _2, "nagareyama": _2, "narashino": _2, "narita": _2, "noda": _2, "oamishirasato": _2, "omigawa": _2, "onjuku": _2, "otaki": _2, "sakae": _2, "sakura": _2, "shimofusa": _2, "shirako": _2, "shiroi": _2, "shisui": _2, "sodegaura": _2, "sosa": _2, "tako": _2, "tateyama": _2, "togane": _2, "tohnosho": _2, "tomisato": _2, "urayasu": _2, "yachimata": _2, "yachiyo": _2, "yokaichiba": _2, "yokoshibahikari": _2, "yotsukaido": _2 } }, "ehime": { "$": 1, "succ": { "ainan": _2, "honai": _2, "ikata": _2, "imabari": _2, "iyo": _2, "kamijima": _2, "kihoku": _2, "kumakogen": _2, "masaki": _2, "matsuno": _2, "matsuyama": _2, "namikata": _2, "niihama": _2, "ozu": _2, "saijo": _2, "seiyo": _2, "shikokuchuo": _2, "tobe": _2, "toon": _2, "uchiko": _2, "uwajima": _2, "yawatahama": _2 } }, "fukui": { "$": 1, "succ": { "echizen": _2, "eiheiji": _2, "fukui": _2, "ikeda": _2, "katsuyama": _2, "mihama": _2, "minamiechizen": _2, "obama": _2, "ohi": _2, "ono": _2, "sabae": _2, "sakai": _2, "takahama": _2, "tsuruga": _2, "wakasa": _2 } }, "fukuoka": { "$": 1, "succ": { "ashiya": _2, "buzen": _2, "chikugo": _2, "chikuho": _2, "chikujo": _2, "chikushino": _2, "chikuzen": _2, "chuo": _2, "dazaifu": _2, "fukuchi": _2, "hakata": _2, "higashi": _2, "hirokawa": _2, "hisayama": _2, "iizuka": _2, "inatsuki": _2, "kaho": _2, "kasuga": _2, "kasuya": _2, "kawara": _2, "keisen": _2, "koga": _2, "kurate": _2, "kurogi": _2, "kurume": _2, "minami": _2, "miyako": _2, "miyama": _2, "miyawaka": _2, "mizumaki": _2, "munakata": _2, "nakagawa": _2, "nakama": _2, "nishi": _2, "nogata": _2, "ogori": _2, "okagaki": _2, "okawa": _2, "oki": _2, "omuta": _2, "onga": _2, "onojo": _2, "oto": _2, "saigawa": _2, "sasaguri": _2, "shingu": _2, "shinyoshitomi": _2, "shonai": _2, "soeda": _2, "sue": _2, "tachiarai": _2, "tagawa": _2, "takata": _2, "toho": _2, "toyotsu": _2, "tsuiki": _2, "ukiha": _2, "umi": _2, "usui": _2, "yamada": _2, "yame": _2, "yanagawa": _2, "yukuhashi": _2 } }, "fukushima": { "$": 1, "succ": { "aizubange": _2, "aizumisato": _2, "aizuwakamatsu": _2, "asakawa": _2, "bandai": _2, "date": _2, "fukushima": _2, "furudono": _2, "futaba": _2, "hanawa": _2, "higashi": _2, "hirata": _2, "hirono": _2, "iitate": _2, "inawashiro": _2, "ishikawa": _2, "iwaki": _2, "izumizaki": _2, "kagamiishi": _2, "kaneyama": _2, "kawamata": _2, "kitakata": _2, "kitashiobara": _2, "koori": _2, "koriyama": _2, "kunimi": _2, "miharu": _2, "mishima": _2, "namie": _2, "nango": _2, "nishiaizu": _2, "nishigo": _2, "okuma": _2, "omotego": _2, "ono": _2, "otama": _2, "samegawa": _2, "shimogo": _2, "shirakawa": _2, "showa": _2, "soma": _2, "sukagawa": _2, "taishin": _2, "tamakawa": _2, "tanagura": _2, "tenei": _2, "yabuki": _2, "yamato": _2, "yamatsuri": _2, "yanaizu": _2, "yugawa": _2 } }, "gifu": { "$": 1, "succ": { "anpachi": _2, "ena": _2, "gifu": _2, "ginan": _2, "godo": _2, "gujo": _2, "hashima": _2, "hichiso": _2, "hida": _2, "higashishirakawa": _2, "ibigawa": _2, "ikeda": _2, "kakamigahara": _2, "kani": _2, "kasahara": _2, "kasamatsu": _2, "kawaue": _2, "kitagata": _2, "mino": _2, "minokamo": _2, "mitake": _2, "mizunami": _2, "motosu": _2, "nakatsugawa": _2, "ogaki": _2, "sakahogi": _2, "seki": _2, "sekigahara": _2, "shirakawa": _2, "tajimi": _2, "takayama": _2, "tarui": _2, "toki": _2, "tomika": _2, "wanouchi": _2, "yamagata": _2, "yaotsu": _2, "yoro": _2 } }, "gunma": { "$": 1, "succ": { "annaka": _2, "chiyoda": _2, "fujioka": _2, "higashiagatsuma": _2, "isesaki": _2, "itakura": _2, "kanna": _2, "kanra": _2, "katashina": _2, "kawaba": _2, "kiryu": _2, "kusatsu": _2, "maebashi": _2, "meiwa": _2, "midori": _2, "minakami": _2, "naganohara": _2, "nakanojo": _2, "nanmoku": _2, "numata": _2, "oizumi": _2, "ora": _2, "ota": _2, "shibukawa": _2, "shimonita": _2, "shinto": _2, "showa": _2, "takasaki": _2, "takayama": _2, "tamamura": _2, "tatebayashi": _2, "tomioka": _2, "tsukiyono": _2, "tsumagoi": _2, "ueno": _2, "yoshioka": _2 } }, "hiroshima": { "$": 1, "succ": { "asaminami": _2, "daiwa": _2, "etajima": _2, "fuchu": _2, "fukuyama": _2, "hatsukaichi": _2, "higashihiroshima": _2, "hongo": _2, "jinsekikogen": _2, "kaita": _2, "kui": _2, "kumano": _2, "kure": _2, "mihara": _2, "miyoshi": _2, "naka": _2, "onomichi": _2, "osakikamijima": _2, "otake": _2, "saka": _2, "sera": _2, "seranishi": _2, "shinichi": _2, "shobara": _2, "takehara": _2 } }, "hokkaido": { "$": 1, "succ": { "abashiri": _2, "abira": _2, "aibetsu": _2, "akabira": _2, "akkeshi": _2, "asahikawa": _2, "ashibetsu": _2, "ashoro": _2, "assabu": _2, "atsuma": _2, "bibai": _2, "biei": _2, "bifuka": _2, "bihoro": _2, "biratori": _2, "chippubetsu": _2, "chitose": _2, "date": _2, "ebetsu": _2, "embetsu": _2, "eniwa": _2, "erimo": _2, "esan": _2, "esashi": _2, "fukagawa": _2, "fukushima": _2, "furano": _2, "furubira": _2, "haboro": _2, "hakodate": _2, "hamatonbetsu": _2, "hidaka": _2, "higashikagura": _2, "higashikawa": _2, "hiroo": _2, "hokuryu": _2, "hokuto": _2, "honbetsu": _2, "horokanai": _2, "horonobe": _2, "ikeda": _2, "imakane": _2, "ishikari": _2, "iwamizawa": _2, "iwanai": _2, "kamifurano": _2, "kamikawa": _2, "kamishihoro": _2, "kamisunagawa": _2, "kamoenai": _2, "kayabe": _2, "kembuchi": _2, "kikonai": _2, "kimobetsu": _2, "kitahiroshima": _2, "kitami": _2, "kiyosato": _2, "koshimizu": _2, "kunneppu": _2, "kuriyama": _2, "kuromatsunai": _2, "kushiro": _2, "kutchan": _2, "kyowa": _2, "mashike": _2, "matsumae": _2, "mikasa": _2, "minamifurano": _2, "mombetsu": _2, "moseushi": _2, "mukawa": _2, "muroran": _2, "naie": _2, "nakagawa": _2, "nakasatsunai": _2, "nakatombetsu": _2, "nanae": _2, "nanporo": _2, "nayoro": _2, "nemuro": _2, "niikappu": _2, "niki": _2, "nishiokoppe": _2, "noboribetsu": _2, "numata": _2, "obihiro": _2, "obira": _2, "oketo": _2, "okoppe": _2, "otaru": _2, "otobe": _2, "otofuke": _2, "otoineppu": _2, "oumu": _2, "ozora": _2, "pippu": _2, "rankoshi": _2, "rebun": _2, "rikubetsu": _2, "rishiri": _2, "rishirifuji": _2, "saroma": _2, "sarufutsu": _2, "shakotan": _2, "shari": _2, "shibecha": _2, "shibetsu": _2, "shikabe": _2, "shikaoi": _2, "shimamaki": _2, "shimizu": _2, "shimokawa": _2, "shinshinotsu": _2, "shintoku": _2, "shiranuka": _2, "shiraoi": _2, "shiriuchi": _2, "sobetsu": _2, "sunagawa": _2, "taiki": _2, "takasu": _2, "takikawa": _2, "takinoue": _2, "teshikaga": _2, "tobetsu": _2, "tohma": _2, "tomakomai": _2, "tomari": _2, "toya": _2, "toyako": _2, "toyotomi": _2, "toyoura": _2, "tsubetsu": _2, "tsukigata": _2, "urakawa": _2, "urausu": _2, "uryu": _2, "utashinai": _2, "wakkanai": _2, "wassamu": _2, "yakumo": _2, "yoichi": _2 } }, "hyogo": { "$": 1, "succ": { "aioi": _2, "akashi": _2, "ako": _2, "amagasaki": _2, "aogaki": _2, "asago": _2, "ashiya": _2, "awaji": _2, "fukusaki": _2, "goshiki": _2, "harima": _2, "himeji": _2, "ichikawa": _2, "inagawa": _2, "itami": _2, "kakogawa": _2, "kamigori": _2, "kamikawa": _2, "kasai": _2, "kasuga": _2, "kawanishi": _2, "miki": _2, "minamiawaji": _2, "nishinomiya": _2, "nishiwaki": _2, "ono": _2, "sanda": _2, "sannan": _2, "sasayama": _2, "sayo": _2, "shingu": _2, "shinonsen": _2, "shiso": _2, "sumoto": _2, "taishi": _2, "taka": _2, "takarazuka": _2, "takasago": _2, "takino": _2, "tamba": _2, "tatsuno": _2, "toyooka": _2, "yabu": _2, "yashiro": _2, "yoka": _2, "yokawa": _2 } }, "ibaraki": { "$": 1, "succ": { "ami": _2, "asahi": _2, "bando": _2, "chikusei": _2, "daigo": _2, "fujishiro": _2, "hitachi": _2, "hitachinaka": _2, "hitachiomiya": _2, "hitachiota": _2, "ibaraki": _2, "ina": _2, "inashiki": _2, "itako": _2, "iwama": _2, "joso": _2, "kamisu": _2, "kasama": _2, "kashima": _2, "kasumigaura": _2, "koga": _2, "miho": _2, "mito": _2, "moriya": _2, "naka": _2, "namegata": _2, "oarai": _2, "ogawa": _2, "omitama": _2, "ryugasaki": _2, "sakai": _2, "sakuragawa": _2, "shimodate": _2, "shimotsuma": _2, "shirosato": _2, "sowa": _2, "suifu": _2, "takahagi": _2, "tamatsukuri": _2, "tokai": _2, "tomobe": _2, "tone": _2, "toride": _2, "tsuchiura": _2, "tsukuba": _2, "uchihara": _2, "ushiku": _2, "yachiyo": _2, "yamagata": _2, "yawara": _2, "yuki": _2 } }, "ishikawa": { "$": 1, "succ": { "anamizu": _2, "hakui": _2, "hakusan": _2, "kaga": _2, "kahoku": _2, "kanazawa": _2, "kawakita": _2, "komatsu": _2, "nakanoto": _2, "nanao": _2, "nomi": _2, "nonoichi": _2, "noto": _2, "shika": _2, "suzu": _2, "tsubata": _2, "tsurugi": _2, "uchinada": _2, "wajima": _2 } }, "iwate": { "$": 1, "succ": { "fudai": _2, "fujisawa": _2, "hanamaki": _2, "hiraizumi": _2, "hirono": _2, "ichinohe": _2, "ichinoseki": _2, "iwaizumi": _2, "iwate": _2, "joboji": _2, "kamaishi": _2, "kanegasaki": _2, "karumai": _2, "kawai": _2, "kitakami": _2, "kuji": _2, "kunohe": _2, "kuzumaki": _2, "miyako": _2, "mizusawa": _2, "morioka": _2, "ninohe": _2, "noda": _2, "ofunato": _2, "oshu": _2, "otsuchi": _2, "rikuzentakata": _2, "shiwa": _2, "shizukuishi": _2, "sumita": _2, "tanohata": _2, "tono": _2, "yahaba": _2, "yamada": _2 } }, "kagawa": { "$": 1, "succ": { "ayagawa": _2, "higashikagawa": _2, "kanonji": _2, "kotohira": _2, "manno": _2, "marugame": _2, "mitoyo": _2, "naoshima": _2, "sanuki": _2, "tadotsu": _2, "takamatsu": _2, "tonosho": _2, "uchinomi": _2, "utazu": _2, "zentsuji": _2 } }, "kagoshima": { "$": 1, "succ": { "akune": _2, "amami": _2, "hioki": _2, "isa": _2, "isen": _2, "izumi": _2, "kagoshima": _2, "kanoya": _2, "kawanabe": _2, "kinko": _2, "kouyama": _2, "makurazaki": _2, "matsumoto": _2, "minamitane": _2, "nakatane": _2, "nishinoomote": _2, "satsumasendai": _2, "soo": _2, "tarumizu": _2, "yusui": _2 } }, "kanagawa": { "$": 1, "succ": { "aikawa": _2, "atsugi": _2, "ayase": _2, "chigasaki": _2, "ebina": _2, "fujisawa": _2, "hadano": _2, "hakone": _2, "hiratsuka": _2, "isehara": _2, "kaisei": _2, "kamakura": _2, "kiyokawa": _2, "matsuda": _2, "minamiashigara": _2, "miura": _2, "nakai": _2, "ninomiya": _2, "odawara": _2, "oi": _2, "oiso": _2, "sagamihara": _2, "samukawa": _2, "tsukui": _2, "yamakita": _2, "yamato": _2, "yokosuka": _2, "yugawara": _2, "zama": _2, "zushi": _2 } }, "kochi": { "$": 1, "succ": { "aki": _2, "geisei": _2, "hidaka": _2, "higashitsuno": _2, "ino": _2, "kagami": _2, "kami": _2, "kitagawa": _2, "kochi": _2, "mihara": _2, "motoyama": _2, "muroto": _2, "nahari": _2, "nakamura": _2, "nankoku": _2, "nishitosa": _2, "niyodogawa": _2, "ochi": _2, "okawa": _2, "otoyo": _2, "otsuki": _2, "sakawa": _2, "sukumo": _2, "susaki": _2, "tosa": _2, "tosashimizu": _2, "toyo": _2, "tsuno": _2, "umaji": _2, "yasuda": _2, "yusuhara": _2 } }, "kumamoto": { "$": 1, "succ": { "amakusa": _2, "arao": _2, "aso": _2, "choyo": _2, "gyokuto": _2, "kamiamakusa": _2, "kikuchi": _2, "kumamoto": _2, "mashiki": _2, "mifune": _2, "minamata": _2, "minamioguni": _2, "nagasu": _2, "nishihara": _2, "oguni": _2, "ozu": _2, "sumoto": _2, "takamori": _2, "uki": _2, "uto": _2, "yamaga": _2, "yamato": _2, "yatsushiro": _2 } }, "kyoto": { "$": 1, "succ": { "ayabe": _2, "fukuchiyama": _2, "higashiyama": _2, "ide": _2, "ine": _2, "joyo": _2, "kameoka": _2, "kamo": _2, "kita": _2, "kizu": _2, "kumiyama": _2, "kyotamba": _2, "kyotanabe": _2, "kyotango": _2, "maizuru": _2, "minami": _2, "minamiyamashiro": _2, "miyazu": _2, "muko": _2, "nagaokakyo": _2, "nakagyo": _2, "nantan": _2, "oyamazaki": _2, "sakyo": _2, "seika": _2, "tanabe": _2, "uji": _2, "ujitawara": _2, "wazuka": _2, "yamashina": _2, "yawata": _2 } }, "mie": { "$": 1, "succ": { "asahi": _2, "inabe": _2, "ise": _2, "kameyama": _2, "kawagoe": _2, "kiho": _2, "kisosaki": _2, "kiwa": _2, "komono": _2, "kumano": _2, "kuwana": _2, "matsusaka": _2, "meiwa": _2, "mihama": _2, "minamiise": _2, "misugi": _2, "miyama": _2, "nabari": _2, "shima": _2, "suzuka": _2, "tado": _2, "taiki": _2, "taki": _2, "tamaki": _2, "toba": _2, "tsu": _2, "udono": _2, "ureshino": _2, "watarai": _2, "yokkaichi": _2 } }, "miyagi": { "$": 1, "succ": { "furukawa": _2, "higashimatsushima": _2, "ishinomaki": _2, "iwanuma": _2, "kakuda": _2, "kami": _2, "kawasaki": _2, "marumori": _2, "matsushima": _2, "minamisanriku": _2, "misato": _2, "murata": _2, "natori": _2, "ogawara": _2, "ohira": _2, "onagawa": _2, "osaki": _2, "rifu": _2, "semine": _2, "shibata": _2, "shichikashuku": _2, "shikama": _2, "shiogama": _2, "shiroishi": _2, "tagajo": _2, "taiwa": _2, "tome": _2, "tomiya": _2, "wakuya": _2, "watari": _2, "yamamoto": _2, "zao": _2 } }, "miyazaki": { "$": 1, "succ": { "aya": _2, "ebino": _2, "gokase": _2, "hyuga": _2, "kadogawa": _2, "kawaminami": _2, "kijo": _2, "kitagawa": _2, "kitakata": _2, "kitaura": _2, "kobayashi": _2, "kunitomi": _2, "kushima": _2, "mimata": _2, "miyakonojo": _2, "miyazaki": _2, "morotsuka": _2, "nichinan": _2, "nishimera": _2, "nobeoka": _2, "saito": _2, "shiiba": _2, "shintomi": _2, "takaharu": _2, "takanabe": _2, "takazaki": _2, "tsuno": _2 } }, "nagano": { "$": 1, "succ": { "achi": _2, "agematsu": _2, "anan": _2, "aoki": _2, "asahi": _2, "azumino": _2, "chikuhoku": _2, "chikuma": _2, "chino": _2, "fujimi": _2, "hakuba": _2, "hara": _2, "hiraya": _2, "iida": _2, "iijima": _2, "iiyama": _2, "iizuna": _2, "ikeda": _2, "ikusaka": _2, "ina": _2, "karuizawa": _2, "kawakami": _2, "kiso": _2, "kisofukushima": _2, "kitaaiki": _2, "komagane": _2, "komoro": _2, "matsukawa": _2, "matsumoto": _2, "miasa": _2, "minamiaiki": _2, "minamimaki": _2, "minamiminowa": _2, "minowa": _2, "miyada": _2, "miyota": _2, "mochizuki": _2, "nagano": _2, "nagawa": _2, "nagiso": _2, "nakagawa": _2, "nakano": _2, "nozawaonsen": _2, "obuse": _2, "ogawa": _2, "okaya": _2, "omachi": _2, "omi": _2, "ookuwa": _2, "ooshika": _2, "otaki": _2, "otari": _2, "sakae": _2, "sakaki": _2, "saku": _2, "sakuho": _2, "shimosuwa": _2, "shinanomachi": _2, "shiojiri": _2, "suwa": _2, "suzaka": _2, "takagi": _2, "takamori": _2, "takayama": _2, "tateshina": _2, "tatsuno": _2, "togakushi": _2, "togura": _2, "tomi": _2, "ueda": _2, "wada": _2, "yamagata": _2, "yamanouchi": _2, "yasaka": _2, "yasuoka": _2 } }, "nagasaki": { "$": 1, "succ": { "chijiwa": _2, "futsu": _2, "goto": _2, "hasami": _2, "hirado": _2, "iki": _2, "isahaya": _2, "kawatana": _2, "kuchinotsu": _2, "matsuura": _2, "nagasaki": _2, "obama": _2, "omura": _2, "oseto": _2, "saikai": _2, "sasebo": _2, "seihi": _2, "shimabara": _2, "shinkamigoto": _2, "togitsu": _2, "tsushima": _2, "unzen": _2 } }, "nara": { "$": 1, "succ": { "ando": _2, "gose": _2, "heguri": _2, "higashiyoshino": _2, "ikaruga": _2, "ikoma": _2, "kamikitayama": _2, "kanmaki": _2, "kashiba": _2, "kashihara": _2, "katsuragi": _2, "kawai": _2, "kawakami": _2, "kawanishi": _2, "koryo": _2, "kurotaki": _2, "mitsue": _2, "miyake": _2, "nara": _2, "nosegawa": _2, "oji": _2, "ouda": _2, "oyodo": _2, "sakurai": _2, "sango": _2, "shimoichi": _2, "shimokitayama": _2, "shinjo": _2, "soni": _2, "takatori": _2, "tawaramoto": _2, "tenkawa": _2, "tenri": _2, "uda": _2, "yamatokoriyama": _2, "yamatotakada": _2, "yamazoe": _2, "yoshino": _2 } }, "niigata": { "$": 1, "succ": { "aga": _2, "agano": _2, "gosen": _2, "itoigawa": _2, "izumozaki": _2, "joetsu": _2, "kamo": _2, "kariwa": _2, "kashiwazaki": _2, "minamiuonuma": _2, "mitsuke": _2, "muika": _2, "murakami": _2, "myoko": _2, "nagaoka": _2, "niigata": _2, "ojiya": _2, "omi": _2, "sado": _2, "sanjo": _2, "seiro": _2, "seirou": _2, "sekikawa": _2, "shibata": _2, "tagami": _2, "tainai": _2, "tochio": _2, "tokamachi": _2, "tsubame": _2, "tsunan": _2, "uonuma": _2, "yahiko": _2, "yoita": _2, "yuzawa": _2 } }, "oita": { "$": 1, "succ": { "beppu": _2, "bungoono": _2, "bungotakada": _2, "hasama": _2, "hiji": _2, "himeshima": _2, "hita": _2, "kamitsue": _2, "kokonoe": _2, "kuju": _2, "kunisaki": _2, "kusu": _2, "oita": _2, "saiki": _2, "taketa": _2, "tsukumi": _2, "usa": _2, "usuki": _2, "yufu": _2 } }, "okayama": { "$": 1, "succ": { "akaiwa": _2, "asakuchi": _2, "bizen": _2, "hayashima": _2, "ibara": _2, "kagamino": _2, "kasaoka": _2, "kibichuo": _2, "kumenan": _2, "kurashiki": _2, "maniwa": _2, "misaki": _2, "nagi": _2, "niimi": _2, "nishiawakura": _2, "okayama": _2, "satosho": _2, "setouchi": _2, "shinjo": _2, "shoo": _2, "soja": _2, "takahashi": _2, "tamano": _2, "tsuyama": _2, "wake": _2, "yakage": _2 } }, "okinawa": { "$": 1, "succ": { "aguni": _2, "ginowan": _2, "ginoza": _2, "gushikami": _2, "haebaru": _2, "higashi": _2, "hirara": _2, "iheya": _2, "ishigaki": _2, "ishikawa": _2, "itoman": _2, "izena": _2, "kadena": _2, "kin": _2, "kitadaito": _2, "kitanakagusuku": _2, "kumejima": _2, "kunigami": _2, "minamidaito": _2, "motobu": _2, "nago": _2, "naha": _2, "nakagusuku": _2, "nakijin": _2, "nanjo": _2, "nishihara": _2, "ogimi": _2, "okinawa": _2, "onna": _2, "shimoji": _2, "taketomi": _2, "tarama": _2, "tokashiki": _2, "tomigusuku": _2, "tonaki": _2, "urasoe": _2, "uruma": _2, "yaese": _2, "yomitan": _2, "yonabaru": _2, "yonaguni": _2, "zamami": _2 } }, "osaka": { "$": 1, "succ": { "abeno": _2, "chihayaakasaka": _2, "chuo": _2, "daito": _2, "fujiidera": _2, "habikino": _2, "hannan": _2, "higashiosaka": _2, "higashisumiyoshi": _2, "higashiyodogawa": _2, "hirakata": _2, "ibaraki": _2, "ikeda": _2, "izumi": _2, "izumiotsu": _2, "izumisano": _2, "kadoma": _2, "kaizuka": _2, "kanan": _2, "kashiwara": _2, "katano": _2, "kawachinagano": _2, "kishiwada": _2, "kita": _2, "kumatori": _2, "matsubara": _2, "minato": _2, "minoh": _2, "misaki": _2, "moriguchi": _2, "neyagawa": _2, "nishi": _2, "nose": _2, "osakasayama": _2, "sakai": _2, "sayama": _2, "sennan": _2, "settsu": _2, "shijonawate": _2, "shimamoto": _2, "suita": _2, "tadaoka": _2, "taishi": _2, "tajiri": _2, "takaishi": _2, "takatsuki": _2, "tondabayashi": _2, "toyonaka": _2, "toyono": _2, "yao": _2 } }, "saga": { "$": 1, "succ": { "ariake": _2, "arita": _2, "fukudomi": _2, "genkai": _2, "hamatama": _2, "hizen": _2, "imari": _2, "kamimine": _2, "kanzaki": _2, "karatsu": _2, "kashima": _2, "kitagata": _2, "kitahata": _2, "kiyama": _2, "kouhoku": _2, "kyuragi": _2, "nishiarita": _2, "ogi": _2, "omachi": _2, "ouchi": _2, "saga": _2, "shiroishi": _2, "taku": _2, "tara": _2, "tosu": _2, "yoshinogari": _2 } }, "saitama": { "$": 1, "succ": { "arakawa": _2, "asaka": _2, "chichibu": _2, "fujimi": _2, "fujimino": _2, "fukaya": _2, "hanno": _2, "hanyu": _2, "hasuda": _2, "hatogaya": _2, "hatoyama": _2, "hidaka": _2, "higashichichibu": _2, "higashimatsuyama": _2, "honjo": _2, "ina": _2, "iruma": _2, "iwatsuki": _2, "kamiizumi": _2, "kamikawa": _2, "kamisato": _2, "kasukabe": _2, "kawagoe": _2, "kawaguchi": _2, "kawajima": _2, "kazo": _2, "kitamoto": _2, "koshigaya": _2, "kounosu": _2, "kuki": _2, "kumagaya": _2, "matsubushi": _2, "minano": _2, "misato": _2, "miyashiro": _2, "miyoshi": _2, "moroyama": _2, "nagatoro": _2, "namegawa": _2, "niiza": _2, "ogano": _2, "ogawa": _2, "ogose": _2, "okegawa": _2, "omiya": _2, "otaki": _2, "ranzan": _2, "ryokami": _2, "saitama": _2, "sakado": _2, "satte": _2, "sayama": _2, "shiki": _2, "shiraoka": _2, "soka": _2, "sugito": _2, "toda": _2, "tokigawa": _2, "tokorozawa": _2, "tsurugashima": _2, "urawa": _2, "warabi": _2, "yashio": _2, "yokoze": _2, "yono": _2, "yorii": _2, "yoshida": _2, "yoshikawa": _2, "yoshimi": _2 } }, "shiga": { "$": 1, "succ": { "aisho": _2, "gamo": _2, "higashiomi": _2, "hikone": _2, "koka": _2, "konan": _2, "kosei": _2, "koto": _2, "kusatsu": _2, "maibara": _2, "moriyama": _2, "nagahama": _2, "nishiazai": _2, "notogawa": _2, "omihachiman": _2, "otsu": _2, "ritto": _2, "ryuoh": _2, "takashima": _2, "takatsuki": _2, "torahime": _2, "toyosato": _2, "yasu": _2 } }, "shimane": { "$": 1, "succ": { "akagi": _2, "ama": _2, "gotsu": _2, "hamada": _2, "higashiizumo": _2, "hikawa": _2, "hikimi": _2, "izumo": _2, "kakinoki": _2, "masuda": _2, "matsue": _2, "misato": _2, "nishinoshima": _2, "ohda": _2, "okinoshima": _2, "okuizumo": _2, "shimane": _2, "tamayu": _2, "tsuwano": _2, "unnan": _2, "yakumo": _2, "yasugi": _2, "yatsuka": _2 } }, "shizuoka": { "$": 1, "succ": { "arai": _2, "atami": _2, "fuji": _2, "fujieda": _2, "fujikawa": _2, "fujinomiya": _2, "fukuroi": _2, "gotemba": _2, "haibara": _2, "hamamatsu": _2, "higashiizu": _2, "ito": _2, "iwata": _2, "izu": _2, "izunokuni": _2, "kakegawa": _2, "kannami": _2, "kawanehon": _2, "kawazu": _2, "kikugawa": _2, "kosai": _2, "makinohara": _2, "matsuzaki": _2, "minamiizu": _2, "mishima": _2, "morimachi": _2, "nishiizu": _2, "numazu": _2, "omaezaki": _2, "shimada": _2, "shimizu": _2, "shimoda": _2, "shizuoka": _2, "susono": _2, "yaizu": _2, "yoshida": _2 } }, "tochigi": { "$": 1, "succ": { "ashikaga": _2, "bato": _2, "haga": _2, "ichikai": _2, "iwafune": _2, "kaminokawa": _2, "kanuma": _2, "karasuyama": _2, "kuroiso": _2, "mashiko": _2, "mibu": _2, "moka": _2, "motegi": _2, "nasu": _2, "nasushiobara": _2, "nikko": _2, "nishikata": _2, "nogi": _2, "ohira": _2, "ohtawara": _2, "oyama": _2, "sakura": _2, "sano": _2, "shimotsuke": _2, "shioya": _2, "takanezawa": _2, "tochigi": _2, "tsuga": _2, "ujiie": _2, "utsunomiya": _2, "yaita": _2 } }, "tokushima": { "$": 1, "succ": { "aizumi": _2, "anan": _2, "ichiba": _2, "itano": _2, "kainan": _2, "komatsushima": _2, "matsushige": _2, "mima": _2, "minami": _2, "miyoshi": _2, "mugi": _2, "nakagawa": _2, "naruto": _2, "sanagochi": _2, "shishikui": _2, "tokushima": _2, "wajiki": _2 } }, "tokyo": { "$": 1, "succ": { "adachi": _2, "akiruno": _2, "akishima": _2, "aogashima": _2, "arakawa": _2, "bunkyo": _2, "chiyoda": _2, "chofu": _2, "chuo": _2, "edogawa": _2, "fuchu": _2, "fussa": _2, "hachijo": _2, "hachioji": _2, "hamura": _2, "higashikurume": _2, "higashimurayama": _2, "higashiyamato": _2, "hino": _2, "hinode": _2, "hinohara": _2, "inagi": _2, "itabashi": _2, "katsushika": _2, "kita": _2, "kiyose": _2, "kodaira": _2, "koganei": _2, "kokubunji": _2, "komae": _2, "koto": _2, "kouzushima": _2, "kunitachi": _2, "machida": _2, "meguro": _2, "minato": _2, "mitaka": _2, "mizuho": _2, "musashimurayama": _2, "musashino": _2, "nakano": _2, "nerima": _2, "ogasawara": _2, "okutama": _2, "ome": _2, "oshima": _2, "ota": _2, "setagaya": _2, "shibuya": _2, "shinagawa": _2, "shinjuku": _2, "suginami": _2, "sumida": _2, "tachikawa": _2, "taito": _2, "tama": _2, "toshima": _2 } }, "tottori": { "$": 1, "succ": { "chizu": _2, "hino": _2, "kawahara": _2, "koge": _2, "kotoura": _2, "misasa": _2, "nanbu": _2, "nichinan": _2, "sakaiminato": _2, "tottori": _2, "wakasa": _2, "yazu": _2, "yonago": _2 } }, "toyama": { "$": 1, "succ": { "asahi": _2, "fuchu": _2, "fukumitsu": _2, "funahashi": _2, "himi": _2, "imizu": _2, "inami": _2, "johana": _2, "kamiichi": _2, "kurobe": _2, "nakaniikawa": _2, "namerikawa": _2, "nanto": _2, "nyuzen": _2, "oyabe": _2, "taira": _2, "takaoka": _2, "tateyama": _2, "toga": _2, "tonami": _2, "toyama": _2, "unazuki": _2, "uozu": _2, "yamada": _2 } }, "wakayama": { "$": 1, "succ": { "arida": _2, "aridagawa": _2, "gobo": _2, "hashimoto": _2, "hidaka": _2, "hirogawa": _2, "inami": _2, "iwade": _2, "kainan": _2, "kamitonda": _2, "katsuragi": _2, "kimino": _2, "kinokawa": _2, "kitayama": _2, "koya": _2, "koza": _2, "kozagawa": _2, "kudoyama": _2, "kushimoto": _2, "mihama": _2, "misato": _2, "nachikatsuura": _2, "shingu": _2, "shirahama": _2, "taiji": _2, "tanabe": _2, "wakayama": _2, "yuasa": _2, "yura": _2 } }, "yamagata": { "$": 1, "succ": { "asahi": _2, "funagata": _2, "higashine": _2, "iide": _2, "kahoku": _2, "kaminoyama": _2, "kaneyama": _2, "kawanishi": _2, "mamurogawa": _2, "mikawa": _2, "murayama": _2, "nagai": _2, "nakayama": _2, "nanyo": _2, "nishikawa": _2, "obanazawa": _2, "oe": _2, "oguni": _2, "ohkura": _2, "oishida": _2, "sagae": _2, "sakata": _2, "sakegawa": _2, "shinjo": _2, "shirataka": _2, "shonai": _2, "takahata": _2, "tendo": _2, "tozawa": _2, "tsuruoka": _2, "yamagata": _2, "yamanobe": _2, "yonezawa": _2, "yuza": _2 } }, "yamaguchi": { "$": 1, "succ": { "abu": _2, "hagi": _2, "hikari": _2, "hofu": _2, "iwakuni": _2, "kudamatsu": _2, "mitou": _2, "nagato": _2, "oshima": _2, "shimonoseki": _2, "shunan": _2, "tabuse": _2, "tokuyama": _2, "toyota": _2, "ube": _2, "yuu": _2 } }, "yamanashi": { "$": 1, "succ": { "chuo": _2, "doshi": _2, "fuefuki": _2, "fujikawa": _2, "fujikawaguchiko": _2, "fujiyoshida": _2, "hayakawa": _2, "hokuto": _2, "ichikawamisato": _2, "kai": _2, "kofu": _2, "koshu": _2, "kosuge": _2, "minami-alps": _2, "minobu": _2, "nakamichi": _2, "nanbu": _2, "narusawa": _2, "nirasaki": _2, "nishikatsura": _2, "oshino": _2, "otsuki": _2, "showa": _2, "tabayama": _2, "tsuru": _2, "uenohara": _2, "yamanakako": _2, "yamanashi": _2 } }, "xn--4pvxs": _2, "栃木": _2, "xn--vgu402c": _2, "愛知": _2, "xn--c3s14m": _2, "愛媛": _2, "xn--f6qx53a": _2, "兵庫": _2, "xn--8pvr4u": _2, "熊本": _2, "xn--uist22h": _2, "茨城": _2, "xn--djrs72d6uy": _2, "北海道": _2, "xn--mkru45i": _2, "千葉": _2, "xn--0trq7p7nn": _2, "和歌山": _2, "xn--8ltr62k": _2, "長崎": _2, "xn--2m4a15e": _2, "長野": _2, "xn--efvn9s": _2, "新潟": _2, "xn--32vp30h": _2, "青森": _2, "xn--4it797k": _2, "静岡": _2, "xn--1lqs71d": _2, "東京": _2, "xn--5rtp49c": _2, "石川": _2, "xn--5js045d": _2, "埼玉": _2, "xn--ehqz56n": _2, "三重": _2, "xn--1lqs03n": _2, "京都": _2, "xn--qqqt11m": _2, "佐賀": _2, "xn--kbrq7o": _2, "大分": _2, "xn--pssu33l": _2, "大阪": _2, "xn--ntsq17g": _2, "奈良": _2, "xn--uisz3g": _2, "宮城": _2, "xn--6btw5a": _2, "宮崎": _2, "xn--1ctwo": _2, "富山": _2, "xn--6orx2r": _2, "山口": _2, "xn--rht61e": _2, "山形": _2, "xn--rht27z": _2, "山梨": _2, "xn--djty4k": _2, "岩手": _2, "xn--nit225k": _2, "岐阜": _2, "xn--rht3d": _2, "岡山": _2, "xn--klty5x": _2, "島根": _2, "xn--kltx9a": _2, "広島": _2, "xn--kltp7d": _2, "徳島": _2, "xn--uuwu58a": _2, "沖縄": _2, "xn--zbx025d": _2, "滋賀": _2, "xn--ntso0iqx3a": _2, "神奈川": _2, "xn--elqq16h": _2, "福井": _2, "xn--4it168d": _2, "福岡": _2, "xn--klt787d": _2, "福島": _2, "xn--rny31h": _2, "秋田": _2, "xn--7t0a264c": _2, "群馬": _2, "xn--5rtq34k": _2, "香川": _2, "xn--k7yn95e": _2, "高知": _2, "xn--tor131o": _2, "鳥取": _2, "xn--d5qv7z876c": _2, "鹿児島": _2, "kawasaki": _8, "kitakyushu": _8, "kobe": _8, "nagoya": _8, "sapporo": _8, "sendai": _8, "yokohama": _8, "buyshop": _3, "fashionstore": _3, "handcrafted": _3, "kawaiishop": _3, "supersale": _3, "theshop": _3, "usercontent": _3, "angry": _3, "babyblue": _3, "babymilk": _3, "backdrop": _3, "bambina": _3, "bitter": _3, "blush": _3, "boo": _3, "boy": _3, "boyfriend": _3, "but": _3, "candypop": _3, "capoo": _3, "catfood": _3, "cheap": _3, "chicappa": _3, "chillout": _3, "chips": _3, "chowder": _3, "chu": _3, "ciao": _3, "cocotte": _3, "coolblog": _3, "cranky": _3, "cutegirl": _3, "daa": _3, "deca": _3, "deci": _3, "digick": _3, "egoism": _3, "fakefur": _3, "fem": _3, "flier": _3, "floppy": _3, "fool": _3, "frenchkiss": _3, "girlfriend": _3, "girly": _3, "gloomy": _3, "gonna": _3, "greater": _3, "hacca": _3, "heavy": _3, "her": _3, "hiho": _3, "hippy": _3, "holy": _3, "hungry": _3, "icurus": _3, "itigo": _3, "jellybean": _3, "kikirara": _3, "kill": _3, "kilo": _3, "kuron": _3, "littlestar": _3, "lolitapunk": _3, "lomo": _3, "lovepop": _3, "lovesick": _3, "main": _3, "mods": _3, "mond": _3, "mongolian": _3, "moo": _3, "namaste": _3, "nikita": _3, "nobushi": _3, "noor": _3, "oops": _3, "parallel": _3, "parasite": _3, "pecori": _3, "peewee": _3, "penne": _3, "pepper": _3, "perma": _3, "pigboat": _3, "pinoko": _3, "punyu": _3, "pupu": _3, "pussycat": _3, "pya": _3, "raindrop": _3, "readymade": _3, "sadist": _3, "schoolbus": _3, "secret": _3, "staba": _3, "stripper": _3, "sub": _3, "sunnyday": _3, "thick": _3, "tonkotsu": _3, "under": _3, "upper": _3, "velvet": _3, "verse": _3, "versus": _3, "vivian": _3, "watson": _3, "weblike": _3, "whitesnow": _3, "zombie": _3, "blogspot": _3 } }, "ke": { "$": 1, "succ": { "ac": _2, "co": _6, "go": _2, "info": _2, "me": _2, "mobi": _2, "ne": _2, "or": _2, "sc": _2 } }, "kg": { "$": 1, "succ": { "org": _2, "net": _2, "com": _2, "edu": _2, "gov": _2, "mil": _2, "blog": _3, "io": _3, "jp": _3, "tv": _3, "uk": _3, "us": _3 } }, "kh": _8, "ki": _29, "km": { "$": 1, "succ": { "org": _2, "nom": _2, "gov": _2, "prd": _2, "tm": _2, "edu": _2, "mil": _2, "ass": _2, "com": _2, "coop": _2, "asso": _2, "presse": _2, "medecin": _2, "notaires": _2, "pharmaciens": _2, "veterinaire": _2, "gouv": _2 } }, "kn": { "$": 1, "succ": { "net": _2, "org": _2, "edu": _2, "gov": _2 } }, "kp": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "org": _2, "rep": _2, "tra": _2 } }, "kr": { "$": 1, "succ": { "ac": _2, "co": _2, "es": _2, "go": _2, "hs": _2, "kg": _2, "mil": _2, "ms": _2, "ne": _2, "or": _2, "pe": _2, "re": _2, "sc": _2, "busan": _2, "chungbuk": _2, "chungnam": _2, "daegu": _2, "daejeon": _2, "gangwon": _2, "gwangju": _2, "gyeongbuk": _2, "gyeonggi": _2, "gyeongnam": _2, "incheon": _2, "jeju": _2, "jeonbuk": _2, "jeonnam": _2, "seoul": _2, "ulsan": _2, "blogspot": _3 } }, "kw": { "$": 1, "succ": { "com": _2, "edu": _2, "emb": _2, "gov": _2, "ind": _2, "net": _2, "org": _2 } }, "ky": _21, "kz": { "$": 1, "succ": { "org": _2, "edu": _2, "net": _2, "gov": _2, "mil": _2, "com": _2, "jcloud": _3, "kazteleport": { "$": 0, "succ": { "upaas": _3 } } } }, "la": { "$": 1, "succ": { "int": _2, "net": _2, "info": _2, "edu": _2, "gov": _2, "per": _2, "com": _2, "org": _2, "bnr": _3, "c": _3 } }, "lb": _4, "lc": { "$": 1, "succ": { "com": _2, "net": _2, "co": _2, "org": _2, "edu": _2, "gov": _2, "oy": _3 } }, "li": { "$": 1, "succ": { "blogspot": _3, "caa": _3 } }, "lk": { "$": 1, "succ": { "gov": _2, "sch": _2, "net": _2, "int": _2, "com": _2, "org": _2, "edu": _2, "ngo": _2, "soc": _2, "web": _2, "ltd": _2, "assn": _2, "grp": _2, "hotel": _2, "ac": _2 } }, "lr": _4, "ls": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _2, "edu": _2, "gov": _2, "info": _2, "net": _2, "org": _2, "sc": _2, "de": _3 } }, "lt": _30, "lu": _6, "lv": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "org": _2, "mil": _2, "id": _2, "net": _2, "asn": _2, "conf": _2 } }, "ly": { "$": 1, "succ": { "com": _2, "net": _2, "gov": _2, "plc": _2, "edu": _2, "sch": _2, "med": _2, "org": _2, "id": _2 } }, "ma": { "$": 1, "succ": { "co": _2, "net": _2, "gov": _2, "org": _2, "ac": _2, "press": _2 } }, "mc": { "$": 1, "succ": { "tm": _2, "asso": _2 } }, "md": { "$": 1, "succ": { "blogspot": _3, "at": _3, "de": _3, "jp": _3, "to": _3 } }, "me": { "$": 1, "succ": { "co": _2, "net": _2, "org": _2, "edu": _2, "ac": _2, "gov": _2, "its": _2, "priv": _2, "c66": _3, "daplie": { "$": 2, "succ": { "localhost": _3 } }, "edgestack": _3, "filegear": _3, "filegear-au": _3, "filegear-de": _3, "filegear-gb": _3, "filegear-ie": _3, "filegear-jp": _3, "filegear-sg": _3, "glitch": _3, "ravendb": _3, "lohmus": _3, "barsy": _3, "mcpe": _3, "mcdir": _3, "soundcast": _3, "tcp4": _3, "brasilia": _3, "ddns": _3, "dnsfor": _3, "hopto": _3, "loginto": _3, "noip": _3, "webhop": _3, "vp4": _3, "diskstation": _3, "dscloud": _3, "i234": _3, "myds": _3, "synology": _3, "tbits": _3, "transip": _19, "wedeploy": _3, "yombo": _3, "nohost": _3 } }, "mg": { "$": 1, "succ": { "org": _2, "nom": _2, "gov": _2, "prd": _2, "tm": _2, "edu": _2, "mil": _2, "com": _2, "co": _2 } }, "mh": _2, "mil": _2, "mk": { "$": 1, "succ": { "com": _2, "org": _2, "net": _2, "edu": _2, "gov": _2, "inf": _2, "name": _2, "blogspot": _3 } }, "ml": { "$": 1, "succ": { "com": _2, "edu": _2, "gouv": _2, "gov": _2, "net": _2, "org": _2, "presse": _2 } }, "mm": _8, "mn": { "$": 1, "succ": { "gov": _2, "edu": _2, "org": _2, "nyc": _3 } }, "mo": _4, "mobi": { "$": 1, "succ": { "barsy": _3, "dscloud": _3 } }, "mp": { "$": 1, "succ": { "ju": _3 } }, "mq": _2, "mr": _30, "ms": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "net": _2, "org": _2, "lab": _3, "minisite": _3 } }, "mt": { "$": 1, "succ": { "com": _6, "edu": _2, "net": _2, "org": _2 } }, "mu": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "ac": _2, "co": _2, "or": _2 } }, "museum": { "$": 1, "succ": { "academy": _2, "agriculture": _2, "air": _2, "airguard": _2, "alabama": _2, "alaska": _2, "amber": _2, "ambulance": _2, "american": _2, "americana": _2, "americanantiques": _2, "americanart": _2, "amsterdam": _2, "and": _2, "annefrank": _2, "anthro": _2, "anthropology": _2, "antiques": _2, "aquarium": _2, "arboretum": _2, "archaeological": _2, "archaeology": _2, "architecture": _2, "art": _2, "artanddesign": _2, "artcenter": _2, "artdeco": _2, "arteducation": _2, "artgallery": _2, "arts": _2, "artsandcrafts": _2, "asmatart": _2, "assassination": _2, "assisi": _2, "association": _2, "astronomy": _2, "atlanta": _2, "austin": _2, "australia": _2, "automotive": _2, "aviation": _2, "axis": _2, "badajoz": _2, "baghdad": _2, "bahn": _2, "bale": _2, "baltimore": _2, "barcelona": _2, "baseball": _2, "basel": _2, "baths": _2, "bauern": _2, "beauxarts": _2, "beeldengeluid": _2, "bellevue": _2, "bergbau": _2, "berkeley": _2, "berlin": _2, "bern": _2, "bible": _2, "bilbao": _2, "bill": _2, "birdart": _2, "birthplace": _2, "bonn": _2, "boston": _2, "botanical": _2, "botanicalgarden": _2, "botanicgarden": _2, "botany": _2, "brandywinevalley": _2, "brasil": _2, "bristol": _2, "british": _2, "britishcolumbia": _2, "broadcast": _2, "brunel": _2, "brussel": _2, "brussels": _2, "bruxelles": _2, "building": _2, "burghof": _2, "bus": _2, "bushey": _2, "cadaques": _2, "california": _2, "cambridge": _2, "can": _2, "canada": _2, "capebreton": _2, "carrier": _2, "cartoonart": _2, "casadelamoneda": _2, "castle": _2, "castres": _2, "celtic": _2, "center": _2, "chattanooga": _2, "cheltenham": _2, "chesapeakebay": _2, "chicago": _2, "children": _2, "childrens": _2, "childrensgarden": _2, "chiropractic": _2, "chocolate": _2, "christiansburg": _2, "cincinnati": _2, "cinema": _2, "circus": _2, "civilisation": _2, "civilization": _2, "civilwar": _2, "clinton": _2, "clock": _2, "coal": _2, "coastaldefence": _2, "cody": _2, "coldwar": _2, "collection": _2, "colonialwilliamsburg": _2, "coloradoplateau": _2, "columbia": _2, "columbus": _2, "communication": _2, "communications": _2, "community": _2, "computer": _2, "computerhistory": _2, "xn--comunicaes-v6a2o": _2, "comunicações": _2, "contemporary": _2, "contemporaryart": _2, "convent": _2, "copenhagen": _2, "corporation": _2, "xn--correios-e-telecomunicaes-ghc29a": _2, "correios-e-telecomunicações": _2, "corvette": _2, "costume": _2, "countryestate": _2, "county": _2, "crafts": _2, "cranbrook": _2, "creation": _2, "cultural": _2, "culturalcenter": _2, "culture": _2, "cyber": _2, "cymru": _2, "dali": _2, "dallas": _2, "database": _2, "ddr": _2, "decorativearts": _2, "delaware": _2, "delmenhorst": _2, "denmark": _2, "depot": _2, "design": _2, "detroit": _2, "dinosaur": _2, "discovery": _2, "dolls": _2, "donostia": _2, "durham": _2, "eastafrica": _2, "eastcoast": _2, "education": _2, "educational": _2, "egyptian": _2, "eisenbahn": _2, "elburg": _2, "elvendrell": _2, "embroidery": _2, "encyclopedic": _2, "england": _2, "entomology": _2, "environment": _2, "environmentalconservation": _2, "epilepsy": _2, "essex": _2, "estate": _2, "ethnology": _2, "exeter": _2, "exhibition": _2, "family": _2, "farm": _2, "farmequipment": _2, "farmers": _2, "farmstead": _2, "field": _2, "figueres": _2, "filatelia": _2, "film": _2, "fineart": _2, "finearts": _2, "finland": _2, "flanders": _2, "florida": _2, "force": _2, "fortmissoula": _2, "fortworth": _2, "foundation": _2, "francaise": _2, "frankfurt": _2, "franziskaner": _2, "freemasonry": _2, "freiburg": _2, "fribourg": _2, "frog": _2, "fundacio": _2, "furniture": _2, "gallery": _2, "garden": _2, "gateway": _2, "geelvinck": _2, "gemological": _2, "geology": _2, "georgia": _2, "giessen": _2, "glas": _2, "glass": _2, "gorge": _2, "grandrapids": _2, "graz": _2, "guernsey": _2, "halloffame": _2, "hamburg": _2, "handson": _2, "harvestcelebration": _2, "hawaii": _2, "health": _2, "heimatunduhren": _2, "hellas": _2, "helsinki": _2, "hembygdsforbund": _2, "heritage": _2, "histoire": _2, "historical": _2, "historicalsociety": _2, "historichouses": _2, "historisch": _2, "historisches": _2, "history": _2, "historyofscience": _2, "horology": _2, "house": _2, "humanities": _2, "illustration": _2, "imageandsound": _2, "indian": _2, "indiana": _2, "indianapolis": _2, "indianmarket": _2, "intelligence": _2, "interactive": _2, "iraq": _2, "iron": _2, "isleofman": _2, "jamison": _2, "jefferson": _2, "jerusalem": _2, "jewelry": _2, "jewish": _2, "jewishart": _2, "jfk": _2, "journalism": _2, "judaica": _2, "judygarland": _2, "juedisches": _2, "juif": _2, "karate": _2, "karikatur": _2, "kids": _2, "koebenhavn": _2, "koeln": _2, "kunst": _2, "kunstsammlung": _2, "kunstunddesign": _2, "labor": _2, "labour": _2, "lajolla": _2, "lancashire": _2, "landes": _2, "lans": _2, "xn--lns-qla": _2, "läns": _2, "larsson": _2, "lewismiller": _2, "lincoln": _2, "linz": _2, "living": _2, "livinghistory": _2, "localhistory": _2, "london": _2, "losangeles": _2, "louvre": _2, "loyalist": _2, "lucerne": _2, "luxembourg": _2, "luzern": _2, "mad": _2, "madrid": _2, "mallorca": _2, "manchester": _2, "mansion": _2, "mansions": _2, "manx": _2, "marburg": _2, "maritime": _2, "maritimo": _2, "maryland": _2, "marylhurst": _2, "media": _2, "medical": _2, "medizinhistorisches": _2, "meeres": _2, "memorial": _2, "mesaverde": _2, "michigan": _2, "midatlantic": _2, "military": _2, "mill": _2, "miners": _2, "mining": _2, "minnesota": _2, "missile": _2, "missoula": _2, "modern": _2, "moma": _2, "money": _2, "monmouth": _2, "monticello": _2, "montreal": _2, "moscow": _2, "motorcycle": _2, "muenchen": _2, "muenster": _2, "mulhouse": _2, "muncie": _2, "museet": _2, "museumcenter": _2, "museumvereniging": _2, "music": _2, "national": _2, "nationalfirearms": _2, "nationalheritage": _2, "nativeamerican": _2, "naturalhistory": _2, "naturalhistorymuseum": _2, "naturalsciences": _2, "nature": _2, "naturhistorisches": _2, "natuurwetenschappen": _2, "naumburg": _2, "naval": _2, "nebraska": _2, "neues": _2, "newhampshire": _2, "newjersey": _2, "newmexico": _2, "newport": _2, "newspaper": _2, "newyork": _2, "niepce": _2, "norfolk": _2, "north": _2, "nrw": _2, "nyc": _2, "nyny": _2, "oceanographic": _2, "oceanographique": _2, "omaha": _2, "online": _2, "ontario": _2, "openair": _2, "oregon": _2, "oregontrail": _2, "otago": _2, "oxford": _2, "pacific": _2, "paderborn": _2, "palace": _2, "paleo": _2, "palmsprings": _2, "panama": _2, "paris": _2, "pasadena": _2, "pharmacy": _2, "philadelphia": _2, "philadelphiaarea": _2, "philately": _2, "phoenix": _2, "photography": _2, "pilots": _2, "pittsburgh": _2, "planetarium": _2, "plantation": _2, "plants": _2, "plaza": _2, "portal": _2, "portland": _2, "portlligat": _2, "posts-and-telecommunications": _2, "preservation": _2, "presidio": _2, "press": _2, "project": _2, "public": _2, "pubol": _2, "quebec": _2, "railroad": _2, "railway": _2, "research": _2, "resistance": _2, "riodejaneiro": _2, "rochester": _2, "rockart": _2, "roma": _2, "russia": _2, "saintlouis": _2, "salem": _2, "salvadordali": _2, "salzburg": _2, "sandiego": _2, "sanfrancisco": _2, "santabarbara": _2, "santacruz": _2, "santafe": _2, "saskatchewan": _2, "satx": _2, "savannahga": _2, "schlesisches": _2, "schoenbrunn": _2, "schokoladen": _2, "school": _2, "schweiz": _2, "science": _2, "scienceandhistory": _2, "scienceandindustry": _2, "sciencecenter": _2, "sciencecenters": _2, "science-fiction": _2, "sciencehistory": _2, "sciences": _2, "sciencesnaturelles": _2, "scotland": _2, "seaport": _2, "settlement": _2, "settlers": _2, "shell": _2, "sherbrooke": _2, "sibenik": _2, "silk": _2, "ski": _2, "skole": _2, "society": _2, "sologne": _2, "soundandvision": _2, "southcarolina": _2, "southwest": _2, "space": _2, "spy": _2, "square": _2, "stadt": _2, "stalbans": _2, "starnberg": _2, "state": _2, "stateofdelaware": _2, "station": _2, "steam": _2, "steiermark": _2, "stjohn": _2, "stockholm": _2, "stpetersburg": _2, "stuttgart": _2, "suisse": _2, "surgeonshall": _2, "surrey": _2, "svizzera": _2, "sweden": _2, "sydney": _2, "tank": _2, "tcm": _2, "technology": _2, "telekommunikation": _2, "television": _2, "texas": _2, "textile": _2, "theater": _2, "time": _2, "timekeeping": _2, "topology": _2, "torino": _2, "touch": _2, "town": _2, "transport": _2, "tree": _2, "trolley": _2, "trust": _2, "trustee": _2, "uhren": _2, "ulm": _2, "undersea": _2, "university": _2, "usa": _2, "usantiques": _2, "usarts": _2, "uscountryestate": _2, "usculture": _2, "usdecorativearts": _2, "usgarden": _2, "ushistory": _2, "ushuaia": _2, "uslivinghistory": _2, "utah": _2, "uvic": _2, "valley": _2, "vantaa": _2, "versailles": _2, "viking": _2, "village": _2, "virginia": _2, "virtual": _2, "virtuel": _2, "vlaanderen": _2, "volkenkunde": _2, "wales": _2, "wallonie": _2, "war": _2, "washingtondc": _2, "watchandclock": _2, "watch-and-clock": _2, "western": _2, "westfalen": _2, "whaling": _2, "wildlife": _2, "williamsburg": _2, "windmill": _2, "workshop": _2, "york": _2, "yorkshire": _2, "yosemite": _2, "youth": _2, "zoological": _2, "zoology": _2, "xn--9dbhblg6di": _2, "ירושלים": _2, "xn--h1aegh": _2, "иком": _2 } }, "mv": { "$": 1, "succ": { "aero": _2, "biz": _2, "com": _2, "coop": _2, "edu": _2, "gov": _2, "info": _2, "int": _2, "mil": _2, "museum": _2, "name": _2, "net": _2, "org": _2, "pro": _2 } }, "mw": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _2, "com": _2, "coop": _2, "edu": _2, "gov": _2, "int": _2, "museum": _2, "net": _2, "org": _2 } }, "mx": { "$": 1, "succ": { "com": _2, "org": _2, "gob": _2, "edu": _2, "net": _2, "blogspot": _3 } }, "my": { "$": 1, "succ": { "biz": _2, "com": _2, "edu": _2, "gov": _2, "mil": _2, "name": _2, "net": _2, "org": _2, "blogspot": _3 } }, "mz": { "$": 1, "succ": { "ac": _2, "adv": _2, "co": _2, "edu": _2, "gov": _2, "mil": _2, "net": _2, "org": _2 } }, "na": { "$": 1, "succ": { "info": _2, "pro": _2, "name": _2, "school": _2, "or": _2, "dr": _2, "us": _2, "mx": _2, "ca": _2, "in": _2, "cc": _2, "tv": _2, "ws": _2, "mobi": _2, "co": _2, "com": _2, "org": _2 } }, "name": { "$": 1, "succ": { "her": _32, "his": _32 } }, "nc": { "$": 1, "succ": { "asso": _2, "nom": _2 } }, "ne": _2, "net": { "$": 1, "succ": { "adobeaemcloud": _3, "alwaysdata": _3, "cloudfront": _3, "t3l3p0rt": _3, "appudo": _3, "atlassian-dev": { "$": 0, "succ": { "prod": { "$": 0, "succ": { "cdn": _3 } } } }, "myfritz": _3, "onavstack": _3, "shopselect": _3, "blackbaudcdn": _3, "boomla": _3, "bplaced": _3, "square7": _3, "gb": _3, "hu": _3, "jp": _3, "se": _3, "uk": _3, "in": _3, "clickrising": _3, "cloudaccess": _3, "cdn77-ssl": _3, "cdn77": { "$": 0, "succ": { "r": _3 } }, "feste-ip": _3, "knx-server": _3, "static-access": _3, "cryptonomic": _5, "dattolocal": _3, "mydatto": _3, "debian": _3, "bitbridge": _3, "at-band-camp": _3, "blogdns": _3, "broke-it": _3, "buyshouses": _3, "dnsalias": _3, "dnsdojo": _3, "does-it": _3, "dontexist": _3, "dynalias": _3, "dynathome": _3, "endofinternet": _3, "from-az": _3, "from-co": _3, "from-la": _3, "from-ny": _3, "gets-it": _3, "ham-radio-op": _3, "homeftp": _3, "homeip": _3, "homelinux": _3, "homeunix": _3, "in-the-band": _3, "is-a-chef": _3, "is-a-geek": _3, "isa-geek": _3, "kicks-ass": _3, "office-on-the": _3, "podzone": _3, "scrapper-site": _3, "selfip": _3, "sells-it": _3, "servebbs": _3, "serveftp": _3, "thruhere": _3, "webhop": _3, "definima": _3, "casacam": _3, "dynu": _3, "dynv6": _3, "twmail": _3, "ru": _3, "channelsdvr": { "$": 2, "succ": { "u": _3 } }, "fastlylb": { "$": 2, "succ": { "map": _3 } }, "fastly": { "$": 0, "succ": { "freetls": _3, "map": _3, "prod": { "$": 0, "succ": { "a": _3, "global": _3 } }, "ssl": { "$": 0, "succ": { "a": _3, "b": _3, "global": _3 } } } }, "edgeapp": _3, "flynnhosting": _3, "cdn-edges": _3, "heteml": _3, "cloudfunctions": _3, "moonscale": _3, "in-dsl": _3, "in-vpn": _3, "ipifony": _3, "iobb": _3, "cloudjiffy": { "$": 2, "succ": { "fra1-de": _3, "west1-us": _3 } }, "elastx": { "$": 0, "succ": { "jls-sto1": _3, "jls-sto2": _3, "jls-sto3": _3 } }, "faststacks": _3, "massivegrid": { "$": 0, "succ": { "paas": { "$": 0, "succ": { "fr-1": _3, "lon-1": _3, "lon-2": _3, "ny-1": _3, "ny-2": _3, "sg-1": _3 } } } }, "saveincloud": { "$": 0, "succ": { "jelastic": _3, "nordeste-idc": _3 } }, "scaleforce": _22, "tsukaeru": _23, "kinghost": _3, "uni5": _3, "krellian": _3, "barsy": _3, "memset": _3, "azurewebsites": _3, "azure-mobile": _3, "cloudapp": _3, "azurestaticapps": { "$": 2, "succ": { "centralus": _3, "eastasia": _3, "eastus2": _3, "westeurope": _3, "westus2": _3 } }, "dnsup": _3, "hicam": _3, "now-dns": _3, "ownip": _3, "vpndns": _3, "eating-organic": _3, "mydissent": _3, "myeffect": _3, "mymediapc": _3, "mypsx": _3, "mysecuritycamera": _3, "nhlfan": _3, "no-ip": _3, "pgafan": _3, "privatizehealthinsurance": _3, "bounceme": _3, "ddns": _3, "redirectme": _3, "serveblog": _3, "serveminecraft": _3, "sytes": _3, "cloudycluster": _3, "ovh": { "$": 0, "succ": { "webpaas": _5, "hosting": _5 } }, "bar0": _3, "bar1": _3, "bar2": _3, "rackmaze": _3, "schokokeks": _3, "firewall-gateway": _3, "seidat": _3, "senseering": _3, "siteleaf": _3, "vps-host": { "$": 2, "succ": { "jelastic": { "$": 0, "succ": { "atl": _3, "njs": _3, "ric": _3 } } } }, "myspreadshop": _3, "srcf": { "$": 0, "succ": { "soc": _3, "user": _3 } }, "supabase": _3, "dsmynas": _3, "familyds": _3, "tailscale": { "$": 0, "succ": { "beta": _3 } }, "ts": _3, "torproject": { "$": 2, "succ": { "pages": _3 } }, "reserve-online": _3, "community-pro": _3, "meinforum": _3, "yandexcloud": { "$": 2, "succ": { "storage": _3, "website": _3 } }, "za": _3 } }, "nf": { "$": 1, "succ": { "com": _2, "net": _2, "per": _2, "rec": _2, "web": _2, "arts": _2, "firm": _2, "info": _2, "other": _2, "store": _2 } }, "ng": { "$": 1, "succ": { "com": _6, "edu": _2, "gov": _2, "i": _2, "mil": _2, "mobi": _2, "name": _2, "net": _2, "org": _2, "sch": _2, "col": _3, "firm": _3, "gen": _3, "ltd": _3, "ngo": _3 } }, "ni": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _2, "com": _2, "edu": _2, "gob": _2, "in": _2, "info": _2, "int": _2, "mil": _2, "net": _2, "nom": _2, "org": _2, "web": _2 } }, "nl": { "$": 1, "succ": { "co": _3, "hosting-cluster": _3, "blogspot": _3, "khplay": _3, "myspreadshop": _3, "transurl": _5, "cistron": _3, "demon": _3 } }, "no": { "$": 1, "succ": { "fhs": _2, "vgs": _2, "fylkesbibl": _2, "folkebibl": _2, "museum": _2, "idrett": _2, "priv": _2, "mil": _2, "stat": _2, "dep": _2, "kommune": _2, "herad": _2, "aa": _33, "ah": _33, "bu": _33, "fm": _33, "hl": _33, "hm": _33, "jan-mayen": _33, "mr": _33, "nl": _33, "nt": _33, "of": _33, "ol": _33, "oslo": _33, "rl": _33, "sf": _33, "st": _33, "svalbard": _33, "tm": _33, "tr": _33, "va": _33, "vf": _33, "akrehamn": _2, "xn--krehamn-dxa": _2, "åkrehamn": _2, "algard": _2, "xn--lgrd-poac": _2, "ålgård": _2, "arna": _2, "brumunddal": _2, "bryne": _2, "bronnoysund": _2, "xn--brnnysund-m8ac": _2, "brønnøysund": _2, "drobak": _2, "xn--drbak-wua": _2, "drøbak": _2, "egersund": _2, "fetsund": _2, "floro": _2, "xn--flor-jra": _2, "florø": _2, "fredrikstad": _2, "hokksund": _2, "honefoss": _2, "xn--hnefoss-q1a": _2, "hønefoss": _2, "jessheim": _2, "jorpeland": _2, "xn--jrpeland-54a": _2, "jørpeland": _2, "kirkenes": _2, "kopervik": _2, "krokstadelva": _2, "langevag": _2, "xn--langevg-jxa": _2, "langevåg": _2, "leirvik": _2, "mjondalen": _2, "xn--mjndalen-64a": _2, "mjøndalen": _2, "mo-i-rana": _2, "mosjoen": _2, "xn--mosjen-eya": _2, "mosjøen": _2, "nesoddtangen": _2, "orkanger": _2, "osoyro": _2, "xn--osyro-wua": _2, "osøyro": _2, "raholt": _2, "xn--rholt-mra": _2, "råholt": _2, "sandnessjoen": _2, "xn--sandnessjen-ogb": _2, "sandnessjøen": _2, "skedsmokorset": _2, "slattum": _2, "spjelkavik": _2, "stathelle": _2, "stavern": _2, "stjordalshalsen": _2, "xn--stjrdalshalsen-sqb": _2, "stjørdalshalsen": _2, "tananger": _2, "tranby": _2, "vossevangen": _2, "afjord": _2, "xn--fjord-lra": _2, "åfjord": _2, "agdenes": _2, "al": _2, "xn--l-1fa": _2, "ål": _2, "alesund": _2, "xn--lesund-hua": _2, "ålesund": _2, "alstahaug": _2, "alta": _2, "xn--lt-liac": _2, "áltá": _2, "alaheadju": _2, "xn--laheadju-7ya": _2, "álaheadju": _2, "alvdal": _2, "amli": _2, "xn--mli-tla": _2, "åmli": _2, "amot": _2, "xn--mot-tla": _2, "åmot": _2, "andebu": _2, "andoy": _2, "xn--andy-ira": _2, "andøy": _2, "andasuolo": _2, "ardal": _2, "xn--rdal-poa": _2, "årdal": _2, "aremark": _2, "arendal": _2, "xn--s-1fa": _2, "ås": _2, "aseral": _2, "xn--seral-lra": _2, "åseral": _2, "asker": _2, "askim": _2, "askvoll": _2, "askoy": _2, "xn--asky-ira": _2, "askøy": _2, "asnes": _2, "xn--snes-poa": _2, "åsnes": _2, "audnedaln": _2, "aukra": _2, "aure": _2, "aurland": _2, "aurskog-holand": _2, "xn--aurskog-hland-jnb": _2, "aurskog-høland": _2, "austevoll": _2, "austrheim": _2, "averoy": _2, "xn--avery-yua": _2, "averøy": _2, "balestrand": _2, "ballangen": _2, "balat": _2, "xn--blt-elab": _2, "bálát": _2, "balsfjord": _2, "bahccavuotna": _2, "xn--bhccavuotna-k7a": _2, "báhccavuotna": _2, "bamble": _2, "bardu": _2, "beardu": _2, "beiarn": _2, "bajddar": _2, "xn--bjddar-pta": _2, "bájddar": _2, "baidar": _2, "xn--bidr-5nac": _2, "báidár": _2, "berg": _2, "bergen": _2, "berlevag": _2, "xn--berlevg-jxa": _2, "berlevåg": _2, "bearalvahki": _2, "xn--bearalvhki-y4a": _2, "bearalváhki": _2, "bindal": _2, "birkenes": _2, "bjarkoy": _2, "xn--bjarky-fya": _2, "bjarkøy": _2, "bjerkreim": _2, "bjugn": _2, "bodo": _2, "xn--bod-2na": _2, "bodø": _2, "badaddja": _2, "xn--bdddj-mrabd": _2, "bådåddjå": _2, "budejju": _2, "bokn": _2, "bremanger": _2, "bronnoy": _2, "xn--brnny-wuac": _2, "brønnøy": _2, "bygland": _2, "bykle": _2, "barum": _2, "xn--brum-voa": _2, "bærum": _2, "telemark": { "$": 0, "succ": { "bo": _2, "xn--b-5ga": _2, "bø": _2 } }, "nordland": { "$": 0, "succ": { "bo": _2, "xn--b-5ga": _2, "bø": _2, "heroy": _2, "xn--hery-ira": _2, "herøy": _2 } }, "bievat": _2, "xn--bievt-0qa": _2, "bievát": _2, "bomlo": _2, "xn--bmlo-gra": _2, "bømlo": _2, "batsfjord": _2, "xn--btsfjord-9za": _2, "båtsfjord": _2, "bahcavuotna": _2, "xn--bhcavuotna-s4a": _2, "báhcavuotna": _2, "dovre": _2, "drammen": _2, "drangedal": _2, "dyroy": _2, "xn--dyry-ira": _2, "dyrøy": _2, "donna": _2, "xn--dnna-gra": _2, "dønna": _2, "eid": _2, "eidfjord": _2, "eidsberg": _2, "eidskog": _2, "eidsvoll": _2, "eigersund": _2, "elverum": _2, "enebakk": _2, "engerdal": _2, "etne": _2, "etnedal": _2, "evenes": _2, "evenassi": _2, "xn--eveni-0qa01ga": _2, "evenášši": _2, "evje-og-hornnes": _2, "farsund": _2, "fauske": _2, "fuossko": _2, "fuoisku": _2, "fedje": _2, "fet": _2, "finnoy": _2, "xn--finny-yua": _2, "finnøy": _2, "fitjar": _2, "fjaler": _2, "fjell": _2, "flakstad": _2, "flatanger": _2, "flekkefjord": _2, "flesberg": _2, "flora": _2, "fla": _2, "xn--fl-zia": _2, "flå": _2, "folldal": _2, "forsand": _2, "fosnes": _2, "frei": _2, "frogn": _2, "froland": _2, "frosta": _2, "frana": _2, "xn--frna-woa": _2, "fræna": _2, "froya": _2, "xn--frya-hra": _2, "frøya": _2, "fusa": _2, "fyresdal": _2, "forde": _2, "xn--frde-gra": _2, "førde": _2, "gamvik": _2, "gangaviika": _2, "xn--ggaviika-8ya47h": _2, "gáŋgaviika": _2, "gaular": _2, "gausdal": _2, "gildeskal": _2, "xn--gildeskl-g0a": _2, "gildeskål": _2, "giske": _2, "gjemnes": _2, "gjerdrum": _2, "gjerstad": _2, "gjesdal": _2, "gjovik": _2, "xn--gjvik-wua": _2, "gjøvik": _2, "gloppen": _2, "gol": _2, "gran": _2, "grane": _2, "granvin": _2, "gratangen": _2, "grimstad": _2, "grong": _2, "kraanghke": _2, "xn--kranghke-b0a": _2, "kråanghke": _2, "grue": _2, "gulen": _2, "hadsel": _2, "halden": _2, "halsa": _2, "hamar": _2, "hamaroy": _2, "habmer": _2, "xn--hbmer-xqa": _2, "hábmer": _2, "hapmir": _2, "xn--hpmir-xqa": _2, "hápmir": _2, "hammerfest": _2, "hammarfeasta": _2, "xn--hmmrfeasta-s4ac": _2, "hámmárfeasta": _2, "haram": _2, "hareid": _2, "harstad": _2, "hasvik": _2, "aknoluokta": _2, "xn--koluokta-7ya57h": _2, "ákŋoluokta": _2, "hattfjelldal": _2, "aarborte": _2, "haugesund": _2, "hemne": _2, "hemnes": _2, "hemsedal": _2, "more-og-romsdal": { "$": 0, "succ": { "heroy": _2, "sande": _2 } }, "xn--mre-og-romsdal-qqb": { "$": 0, "succ": { "xn--hery-ira": _2, "sande": _2 } }, "møre-og-romsdal": { "$": 0, "succ": { "herøy": _2, "sande": _2 } }, "hitra": _2, "hjartdal": _2, "hjelmeland": _2, "hobol": _2, "xn--hobl-ira": _2, "hobøl": _2, "hof": _2, "hol": _2, "hole": _2, "holmestrand": _2, "holtalen": _2, "xn--holtlen-hxa": _2, "holtålen": _2, "hornindal": _2, "horten": _2, "hurdal": _2, "hurum": _2, "hvaler": _2, "hyllestad": _2, "hagebostad": _2, "xn--hgebostad-g3a": _2, "hægebostad": _2, "hoyanger": _2, "xn--hyanger-q1a": _2, "høyanger": _2, "hoylandet": _2, "xn--hylandet-54a": _2, "høylandet": _2, "ha": _2, "xn--h-2fa": _2, "hå": _2, "ibestad": _2, "inderoy": _2, "xn--indery-fya": _2, "inderøy": _2, "iveland": _2, "jevnaker": _2, "jondal": _2, "jolster": _2, "xn--jlster-bya": _2, "jølster": _2, "karasjok": _2, "karasjohka": _2, "xn--krjohka-hwab49j": _2, "kárášjohka": _2, "karlsoy": _2, "galsa": _2, "xn--gls-elac": _2, "gálsá": _2, "karmoy": _2, "xn--karmy-yua": _2, "karmøy": _2, "kautokeino": _2, "guovdageaidnu": _2, "klepp": _2, "klabu": _2, "xn--klbu-woa": _2, "klæbu": _2, "kongsberg": _2, "kongsvinger": _2, "kragero": _2, "xn--krager-gya": _2, "kragerø": _2, "kristiansand": _2, "kristiansund": _2, "krodsherad": _2, "xn--krdsherad-m8a": _2, "krødsherad": _2, "kvalsund": _2, "rahkkeravju": _2, "xn--rhkkervju-01af": _2, "ráhkkerávju": _2, "kvam": _2, "kvinesdal": _2, "kvinnherad": _2, "kviteseid": _2, "kvitsoy": _2, "xn--kvitsy-fya": _2, "kvitsøy": _2, "kvafjord": _2, "xn--kvfjord-nxa": _2, "kvæfjord": _2, "giehtavuoatna": _2, "kvanangen": _2, "xn--kvnangen-k0a": _2, "kvænangen": _2, "navuotna": _2, "xn--nvuotna-hwa": _2, "návuotna": _2, "kafjord": _2, "xn--kfjord-iua": _2, "kåfjord": _2, "gaivuotna": _2, "xn--givuotna-8ya": _2, "gáivuotna": _2, "larvik": _2, "lavangen": _2, "lavagis": _2, "loabat": _2, "xn--loabt-0qa": _2, "loabát": _2, "lebesby": _2, "davvesiida": _2, "leikanger": _2, "leirfjord": _2, "leka": _2, "leksvik": _2, "lenvik": _2, "leangaviika": _2, "xn--leagaviika-52b": _2, "leaŋgaviika": _2, "lesja": _2, "levanger": _2, "lier": _2, "lierne": _2, "lillehammer": _2, "lillesand": _2, "lindesnes": _2, "lindas": _2, "xn--linds-pra": _2, "lindås": _2, "lom": _2, "loppa": _2, "lahppi": _2, "xn--lhppi-xqa": _2, "láhppi": _2, "lund": _2, "lunner": _2, "luroy": _2, "xn--lury-ira": _2, "lurøy": _2, "luster": _2, "lyngdal": _2, "lyngen": _2, "ivgu": _2, "lardal": _2, "lerdal": _2, "xn--lrdal-sra": _2, "lærdal": _2, "lodingen": _2, "xn--ldingen-q1a": _2, "lødingen": _2, "lorenskog": _2, "xn--lrenskog-54a": _2, "lørenskog": _2, "loten": _2, "xn--lten-gra": _2, "løten": _2, "malvik": _2, "masoy": _2, "xn--msy-ula0h": _2, "måsøy": _2, "muosat": _2, "xn--muost-0qa": _2, "muosát": _2, "mandal": _2, "marker": _2, "marnardal": _2, "masfjorden": _2, "meland": _2, "meldal": _2, "melhus": _2, "meloy": _2, "xn--mely-ira": _2, "meløy": _2, "meraker": _2, "xn--merker-kua": _2, "meråker": _2, "moareke": _2, "xn--moreke-jua": _2, "moåreke": _2, "midsund": _2, "midtre-gauldal": _2, "modalen": _2, "modum": _2, "molde": _2, "moskenes": _2, "moss": _2, "mosvik": _2, "malselv": _2, "xn--mlselv-iua": _2, "målselv": _2, "malatvuopmi": _2, "xn--mlatvuopmi-s4a": _2, "málatvuopmi": _2, "namdalseid": _2, "aejrie": _2, "namsos": _2, "namsskogan": _2, "naamesjevuemie": _2, "xn--nmesjevuemie-tcba": _2, "nååmesjevuemie": _2, "laakesvuemie": _2, "nannestad": _2, "narvik": _2, "narviika": _2, "naustdal": _2, "nedre-eiker": _2, "akershus": _34, "buskerud": _34, "nesna": _2, "nesodden": _2, "nesseby": _2, "unjarga": _2, "xn--unjrga-rta": _2, "unjárga": _2, "nesset": _2, "nissedal": _2, "nittedal": _2, "nord-aurdal": _2, "nord-fron": _2, "nord-odal": _2, "norddal": _2, "nordkapp": _2, "davvenjarga": _2, "xn--davvenjrga-y4a": _2, "davvenjárga": _2, "nordre-land": _2, "nordreisa": _2, "raisa": _2, "xn--risa-5na": _2, "ráisa": _2, "nore-og-uvdal": _2, "notodden": _2, "naroy": _2, "xn--nry-yla5g": _2, "nærøy": _2, "notteroy": _2, "xn--nttery-byae": _2, "nøtterøy": _2, "odda": _2, "oksnes": _2, "xn--ksnes-uua": _2, "øksnes": _2, "oppdal": _2, "oppegard": _2, "xn--oppegrd-ixa": _2, "oppegård": _2, "orkdal": _2, "orland": _2, "xn--rland-uua": _2, "ørland": _2, "orskog": _2, "xn--rskog-uua": _2, "ørskog": _2, "orsta": _2, "xn--rsta-fra": _2, "ørsta": _2, "hedmark": { "$": 0, "succ": { "os": _2, "valer": _2, "xn--vler-qoa": _2, "våler": _2 } }, "hordaland": { "$": 0, "succ": { "os": _2 } }, "osen": _2, "osteroy": _2, "xn--ostery-fya": _2, "osterøy": _2, "ostre-toten": _2, "xn--stre-toten-zcb": _2, "østre-toten": _2, "overhalla": _2, "ovre-eiker": _2, "xn--vre-eiker-k8a": _2, "øvre-eiker": _2, "oyer": _2, "xn--yer-zna": _2, "øyer": _2, "oygarden": _2, "xn--ygarden-p1a": _2, "øygarden": _2, "oystre-slidre": _2, "xn--ystre-slidre-ujb": _2, "øystre-slidre": _2, "porsanger": _2, "porsangu": _2, "xn--porsgu-sta26f": _2, "porsáŋgu": _2, "porsgrunn": _2, "radoy": _2, "xn--rady-ira": _2, "radøy": _2, "rakkestad": _2, "rana": _2, "ruovat": _2, "randaberg": _2, "rauma": _2, "rendalen": _2, "rennebu": _2, "rennesoy": _2, "xn--rennesy-v1a": _2, "rennesøy": _2, "rindal": _2, "ringebu": _2, "ringerike": _2, "ringsaker": _2, "rissa": _2, "risor": _2, "xn--risr-ira": _2, "risør": _2, "roan": _2, "rollag": _2, "rygge": _2, "ralingen": _2, "xn--rlingen-mxa": _2, "rælingen": _2, "rodoy": _2, "xn--rdy-0nab": _2, "rødøy": _2, "romskog": _2, "xn--rmskog-bya": _2, "rømskog": _2, "roros": _2, "xn--rros-gra": _2, "røros": _2, "rost": _2, "xn--rst-0na": _2, "røst": _2, "royken": _2, "xn--ryken-vua": _2, "røyken": _2, "royrvik": _2, "xn--ryrvik-bya": _2, "røyrvik": _2, "rade": _2, "xn--rde-ula": _2, "råde": _2, "salangen": _2, "siellak": _2, "saltdal": _2, "salat": _2, "xn--slt-elab": _2, "sálát": _2, "xn--slat-5na": _2, "sálat": _2, "samnanger": _2, "vestfold": { "$": 0, "succ": { "sande": _2 } }, "sandefjord": _2, "sandnes": _2, "sandoy": _2, "xn--sandy-yua": _2, "sandøy": _2, "sarpsborg": _2, "sauda": _2, "sauherad": _2, "sel": _2, "selbu": _2, "selje": _2, "seljord": _2, "sigdal": _2, "siljan": _2, "sirdal": _2, "skaun": _2, "skedsmo": _2, "ski": _2, "skien": _2, "skiptvet": _2, "skjervoy": _2, "xn--skjervy-v1a": _2, "skjervøy": _2, "skierva": _2, "xn--skierv-uta": _2, "skiervá": _2, "skjak": _2, "xn--skjk-soa": _2, "skjåk": _2, "skodje": _2, "skanland": _2, "xn--sknland-fxa": _2, "skånland": _2, "skanit": _2, "xn--sknit-yqa": _2, "skánit": _2, "smola": _2, "xn--smla-hra": _2, "smøla": _2, "snillfjord": _2, "snasa": _2, "xn--snsa-roa": _2, "snåsa": _2, "snoasa": _2, "snaase": _2, "xn--snase-nra": _2, "snåase": _2, "sogndal": _2, "sokndal": _2, "sola": _2, "solund": _2, "songdalen": _2, "sortland": _2, "spydeberg": _2, "stange": _2, "stavanger": _2, "steigen": _2, "steinkjer": _2, "stjordal": _2, "xn--stjrdal-s1a": _2, "stjørdal": _2, "stokke": _2, "stor-elvdal": _2, "stord": _2, "stordal": _2, "storfjord": _2, "omasvuotna": _2, "strand": _2, "stranda": _2, "stryn": _2, "sula": _2, "suldal": _2, "sund": _2, "sunndal": _2, "surnadal": _2, "sveio": _2, "svelvik": _2, "sykkylven": _2, "sogne": _2, "xn--sgne-gra": _2, "søgne": _2, "somna": _2, "xn--smna-gra": _2, "sømna": _2, "sondre-land": _2, "xn--sndre-land-0cb": _2, "søndre-land": _2, "sor-aurdal": _2, "xn--sr-aurdal-l8a": _2, "sør-aurdal": _2, "sor-fron": _2, "xn--sr-fron-q1a": _2, "sør-fron": _2, "sor-odal": _2, "xn--sr-odal-q1a": _2, "sør-odal": _2, "sor-varanger": _2, "xn--sr-varanger-ggb": _2, "sør-varanger": _2, "matta-varjjat": _2, "xn--mtta-vrjjat-k7af": _2, "mátta-várjjat": _2, "sorfold": _2, "xn--srfold-bya": _2, "sørfold": _2, "sorreisa": _2, "xn--srreisa-q1a": _2, "sørreisa": _2, "sorum": _2, "xn--srum-gra": _2, "sørum": _2, "tana": _2, "deatnu": _2, "time": _2, "tingvoll": _2, "tinn": _2, "tjeldsund": _2, "dielddanuorri": _2, "tjome": _2, "xn--tjme-hra": _2, "tjøme": _2, "tokke": _2, "tolga": _2, "torsken": _2, "tranoy": _2, "xn--trany-yua": _2, "tranøy": _2, "tromso": _2, "xn--troms-zua": _2, "tromsø": _2, "tromsa": _2, "romsa": _2, "trondheim": _2, "troandin": _2, "trysil": _2, "trana": _2, "xn--trna-woa": _2, "træna": _2, "trogstad": _2, "xn--trgstad-r1a": _2, "trøgstad": _2, "tvedestrand": _2, "tydal": _2, "tynset": _2, "tysfjord": _2, "divtasvuodna": _2, "divttasvuotna": _2, "tysnes": _2, "tysvar": _2, "xn--tysvr-vra": _2, "tysvær": _2, "tonsberg": _2, "xn--tnsberg-q1a": _2, "tønsberg": _2, "ullensaker": _2, "ullensvang": _2, "ulvik": _2, "utsira": _2, "vadso": _2, "xn--vads-jra": _2, "vadsø": _2, "cahcesuolo": _2, "xn--hcesuolo-7ya35b": _2, "čáhcesuolo": _2, "vaksdal": _2, "valle": _2, "vang": _2, "vanylven": _2, "vardo": _2, "xn--vard-jra": _2, "vardø": _2, "varggat": _2, "xn--vrggt-xqad": _2, "várggát": _2, "vefsn": _2, "vaapste": _2, "vega": _2, "vegarshei": _2, "xn--vegrshei-c0a": _2, "vegårshei": _2, "vennesla": _2, "verdal": _2, "verran": _2, "vestby": _2, "vestnes": _2, "vestre-slidre": _2, "vestre-toten": _2, "vestvagoy": _2, "xn--vestvgy-ixa6o": _2, "vestvågøy": _2, "vevelstad": _2, "vik": _2, "vikna": _2, "vindafjord": _2, "volda": _2, "voss": _2, "varoy": _2, "xn--vry-yla5g": _2, "værøy": _2, "vagan": _2, "xn--vgan-qoa": _2, "vågan": _2, "voagat": _2, "vagsoy": _2, "xn--vgsy-qoa0j": _2, "vågsøy": _2, "vaga": _2, "xn--vg-yiab": _2, "vågå": _2, "ostfold": { "$": 0, "succ": { "valer": _2 } }, "xn--stfold-9xa": { "$": 0, "succ": { "xn--vler-qoa": _2 } }, "østfold": { "$": 0, "succ": { "våler": _2 } }, "co": _3, "blogspot": _3, "myspreadshop": _3 } }, "np": _8, "nr": _29, "nu": { "$": 1, "succ": { "merseine": _3, "mine": _3, "shacknet": _3, "enterprisecloud": _3 } }, "nz": { "$": 1, "succ": { "ac": _2, "co": _6, "cri": _2, "geek": _2, "gen": _2, "govt": _2, "health": _2, "iwi": _2, "kiwi": _2, "maori": _2, "mil": _2, "xn--mori-qsa": _2, "māori": _2, "net": _2, "org": _2, "parliament": _2, "school": _2 } }, "om": { "$": 1, "succ": { "co": _2, "com": _2, "edu": _2, "gov": _2, "med": _2, "museum": _2, "net": _2, "org": _2, "pro": _2 } }, "onion": _2, "org": { "$": 1, "succ": { "altervista": _3, "amune": { "$": 0, "succ": { "tele": _3 } }, "pimienta": _3, "poivron": _3, "potager": _3, "sweetpepper": _3, "ae": _3, "us": _3, "certmgr": _3, "cdn77": { "$": 0, "succ": { "c": _3, "rsc": _3 } }, "cdn77-secure": { "$": 0, "succ": { "origin": { "$": 0, "succ": { "ssl": _3 } } } }, "cloudns": _3, "duckdns": _3, "tunk": _3, "dyndns": { "$": 2, "succ": { "go": _3, "home": _3 } }, "blogdns": _3, "blogsite": _3, "boldlygoingnowhere": _3, "dnsalias": _3, "dnsdojo": _3, "doesntexist": _3, "dontexist": _3, "doomdns": _3, "dvrdns": _3, "dynalias": _3, "endofinternet": _3, "endoftheinternet": _3, "from-me": _3, "game-host": _3, "gotdns": _3, "hobby-site": _3, "homedns": _3, "homeftp": _3, "homelinux": _3, "homeunix": _3, "is-a-bruinsfan": _3, "is-a-candidate": _3, "is-a-celticsfan": _3, "is-a-chef": _3, "is-a-geek": _3, "is-a-knight": _3, "is-a-linux-user": _3, "is-a-patsfan": _3, "is-a-soxfan": _3, "is-found": _3, "is-lost": _3, "is-saved": _3, "is-very-bad": _3, "is-very-evil": _3, "is-very-good": _3, "is-very-nice": _3, "is-very-sweet": _3, "isa-geek": _3, "kicks-ass": _3, "misconfused": _3, "podzone": _3, "readmyblog": _3, "selfip": _3, "sellsyourhome": _3, "servebbs": _3, "serveftp": _3, "servegame": _3, "stuff-4-sale": _3, "webhop": _3, "ddnss": _3, "accesscam": _3, "camdvr": _3, "freeddns": _3, "mywire": _3, "webredirect": _3, "eu": { "$": 2, "succ": { "al": _3, "asso": _3, "at": _3, "au": _3, "be": _3, "bg": _3, "ca": _3, "cd": _3, "ch": _3, "cn": _3, "cy": _3, "cz": _3, "de": _3, "dk": _3, "edu": _3, "ee": _3, "es": _3, "fi": _3, "fr": _3, "gr": _3, "hr": _3, "hu": _3, "ie": _3, "il": _3, "in": _3, "int": _3, "is": _3, "it": _3, "jp": _3, "kr": _3, "lt": _3, "lu": _3, "lv": _3, "mc": _3, "me": _3, "mk": _3, "mt": _3, "my": _3, "net": _3, "ng": _3, "nl": _3, "no": _3, "nz": _3, "paris": _3, "pl": _3, "pt": _3, "q-a": _3, "ro": _3, "ru": _3, "se": _3, "si": _3, "sk": _3, "tr": _3, "uk": _3, "us": _3 } }, "twmail": _3, "fedorainfracloud": _3, "fedorapeople": _3, "fedoraproject": { "$": 0, "succ": { "cloud": _3, "os": _17, "stg": { "$": 0, "succ": { "os": _17 } } } }, "freedesktop": _3, "hepforge": _3, "in-dsl": _3, "in-vpn": _3, "js": _3, "barsy": _3, "mayfirst": _3, "mozilla-iot": _3, "bmoattachments": _3, "dynserv": _3, "now-dns": _3, "cable-modem": _3, "collegefan": _3, "couchpotatofries": _3, "mlbfan": _3, "mysecuritycamera": _3, "nflfan": _3, "read-books": _3, "ufcfan": _3, "hopto": _3, "myftp": _3, "no-ip": _3, "zapto": _3, "httpbin": _3, "pubtls": _3, "my-firewall": _3, "myfirewall": _3, "spdns": _3, "small-web": _3, "dsmynas": _3, "familyds": _3, "teckids": _11, "tuxfamily": _3, "diskstation": _3, "hk": _3, "wmflabs": _3, "toolforge": _3, "wmcloud": _3, "za": _3 } }, "pa": { "$": 1, "succ": { "ac": _2, "gob": _2, "com": _2, "org": _2, "sld": _2, "edu": _2, "net": _2, "ing": _2, "abo": _2, "med": _2, "nom": _2 } }, "pe": { "$": 1, "succ": { "edu": _2, "gob": _2, "nom": _2, "mil": _2, "org": _2, "com": _2, "net": _2, "blogspot": _3 } }, "pf": { "$": 1, "succ": { "com": _2, "org": _2, "edu": _2 } }, "pg": _8, "ph": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "edu": _2, "ngo": _2, "mil": _2, "i": _2 } }, "pk": { "$": 1, "succ": { "com": _2, "net": _2, "edu": _2, "org": _2, "fam": _2, "biz": _2, "web": _2, "gov": _2, "gob": _2, "gok": _2, "gon": _2, "gop": _2, "gos": _2, "info": _2 } }, "pl": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "aid": _2, "agro": _2, "atm": _2, "auto": _2, "biz": _2, "edu": _2, "gmina": _2, "gsm": _2, "info": _2, "mail": _2, "miasta": _2, "media": _2, "mil": _2, "nieruchomosci": _2, "nom": _2, "pc": _2, "powiat": _2, "priv": _2, "realestate": _2, "rel": _2, "sex": _2, "shop": _2, "sklep": _2, "sos": _2, "szkola": _2, "targi": _2, "tm": _2, "tourism": _2, "travel": _2, "turystyka": _2, "gov": { "$": 1, "succ": { "ap": _2, "ic": _2, "is": _2, "us": _2, "kmpsp": _2, "kppsp": _2, "kwpsp": _2, "psp": _2, "wskr": _2, "kwp": _2, "mw": _2, "ug": _2, "um": _2, "umig": _2, "ugim": _2, "upow": _2, "uw": _2, "starostwo": _2, "pa": _2, "po": _2, "psse": _2, "pup": _2, "rzgw": _2, "sa": _2, "so": _2, "sr": _2, "wsa": _2, "sko": _2, "uzs": _2, "wiih": _2, "winb": _2, "pinb": _2, "wios": _2, "witd": _2, "wzmiuw": _2, "piw": _2, "wiw": _2, "griw": _2, "wif": _2, "oum": _2, "sdn": _2, "zp": _2, "uppo": _2, "mup": _2, "wuoz": _2, "konsulat": _2, "oirm": _2 } }, "augustow": _2, "babia-gora": _2, "bedzin": _2, "beskidy": _2, "bialowieza": _2, "bialystok": _2, "bielawa": _2, "bieszczady": _2, "boleslawiec": _2, "bydgoszcz": _2, "bytom": _2, "cieszyn": _2, "czeladz": _2, "czest": _2, "dlugoleka": _2, "elblag": _2, "elk": _2, "glogow": _2, "gniezno": _2, "gorlice": _2, "grajewo": _2, "ilawa": _2, "jaworzno": _2, "jelenia-gora": _2, "jgora": _2, "kalisz": _2, "kazimierz-dolny": _2, "karpacz": _2, "kartuzy": _2, "kaszuby": _2, "katowice": _2, "kepno": _2, "ketrzyn": _2, "klodzko": _2, "kobierzyce": _2, "kolobrzeg": _2, "konin": _2, "konskowola": _2, "kutno": _2, "lapy": _2, "lebork": _2, "legnica": _2, "lezajsk": _2, "limanowa": _2, "lomza": _2, "lowicz": _2, "lubin": _2, "lukow": _2, "malbork": _2, "malopolska": _2, "mazowsze": _2, "mazury": _2, "mielec": _2, "mielno": _2, "mragowo": _2, "naklo": _2, "nowaruda": _2, "nysa": _2, "olawa": _2, "olecko": _2, "olkusz": _2, "olsztyn": _2, "opoczno": _2, "opole": _2, "ostroda": _2, "ostroleka": _2, "ostrowiec": _2, "ostrowwlkp": _2, "pila": _2, "pisz": _2, "podhale": _2, "podlasie": _2, "polkowice": _2, "pomorze": _2, "pomorskie": _2, "prochowice": _2, "pruszkow": _2, "przeworsk": _2, "pulawy": _2, "radom": _2, "rawa-maz": _2, "rybnik": _2, "rzeszow": _2, "sanok": _2, "sejny": _2, "slask": _2, "slupsk": _2, "sosnowiec": _2, "stalowa-wola": _2, "skoczow": _2, "starachowice": _2, "stargard": _2, "suwalki": _2, "swidnica": _2, "swiebodzin": _2, "swinoujscie": _2, "szczecin": _2, "szczytno": _2, "tarnobrzeg": _2, "tgory": _2, "turek": _2, "tychy": _2, "ustka": _2, "walbrzych": _2, "warmia": _2, "warszawa": _2, "waw": _2, "wegrow": _2, "wielun": _2, "wlocl": _2, "wloclawek": _2, "wodzislaw": _2, "wolomin": _2, "wroclaw": _2, "zachpomor": _2, "zagan": _2, "zarow": _2, "zgora": _2, "zgorzelec": _2, "beep": _3, "ecommerce-shop": _3, "shoparena": _3, "homesklep": _3, "sdscloud": _3, "unicloud": _3, "krasnik": _3, "leczna": _3, "lubartow": _3, "lublin": _3, "poniatowa": _3, "swidnik": _3, "co": _3, "art": _3, "gliwice": _3, "krakow": _3, "poznan": _3, "wroc": _3, "zakopane": _3, "myspreadshop": _3, "gda": _3, "gdansk": _3, "gdynia": _3, "med": _3, "sopot": _3 } }, "pm": { "$": 1, "succ": { "own": _3 } }, "pn": { "$": 1, "succ": { "gov": _2, "co": _2, "org": _2, "edu": _2, "net": _2 } }, "post": _2, "pr": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "edu": _2, "isla": _2, "pro": _2, "biz": _2, "info": _2, "name": _2, "est": _2, "prof": _2, "ac": _2 } }, "pro": { "$": 1, "succ": { "aaa": _2, "aca": _2, "acct": _2, "avocat": _2, "bar": _2, "cpa": _2, "eng": _2, "jur": _2, "law": _2, "med": _2, "recht": _2, "cloudns": _3, "dnstrace": { "$": 0, "succ": { "bci": _3 } }, "barsy": _3 } }, "ps": { "$": 1, "succ": { "edu": _2, "gov": _2, "sec": _2, "plo": _2, "com": _2, "org": _2, "net": _2 } }, "pt": { "$": 1, "succ": { "net": _2, "gov": _2, "org": _2, "edu": _2, "int": _2, "publ": _2, "com": _2, "nome": _2, "blogspot": _3 } }, "pw": { "$": 1, "succ": { "co": _2, "ne": _2, "or": _2, "ed": _2, "go": _2, "belau": _2, "cloudns": _3, "x443": _3 } }, "py": { "$": 1, "succ": { "com": _2, "coop": _2, "edu": _2, "gov": _2, "mil": _2, "net": _2, "org": _2 } }, "qa": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "mil": _2, "name": _2, "net": _2, "org": _2, "sch": _2, "blogspot": _3 } }, "re": { "$": 1, "succ": { "asso": _2, "com": _2, "nom": _2, "blogspot": _3 } }, "ro": { "$": 1, "succ": { "arts": _2, "com": _2, "firm": _2, "info": _2, "nom": _2, "nt": _2, "org": _2, "rec": _2, "store": _2, "tm": _2, "www": _2, "co": _3, "shop": _3, "blogspot": _3, "barsy": _3 } }, "rs": { "$": 1, "succ": { "ac": _2, "co": _2, "edu": _2, "gov": _2, "in": _2, "org": _2, "brendly": { "$": 0, "succ": { "shop": _3 } }, "blogspot": _3, "ua": _3, "ox": _3 } }, "ru": { "$": 1, "succ": { "ac": _3, "edu": _3, "gov": _3, "int": _3, "mil": _3, "test": _3, "eurodir": _3, "adygeya": _3, "bashkiria": _3, "bir": _3, "cbg": _3, "com": _3, "dagestan": _3, "grozny": _3, "kalmykia": _3, "kustanai": _3, "marine": _3, "mordovia": _3, "msk": _3, "mytis": _3, "nalchik": _3, "nov": _3, "pyatigorsk": _3, "spb": _3, "vladikavkaz": _3, "vladimir": _3, "blogspot": _3, "na4u": _3, "mircloud": _3, "regruhosting": _23, "myjino": { "$": 2, "succ": { "hosting": _5, "landing": _5, "spectrum": _5, "vps": _5 } }, "cldmail": { "$": 0, "succ": { "hb": _3 } }, "mcdir": { "$": 2, "succ": { "vps": _3 } }, "mcpre": _3, "net": _3, "org": _3, "pp": _3, "lk3": _3, "ras": _3 } }, "rw": { "$": 1, "succ": { "ac": _2, "co": _2, "coop": _2, "gov": _2, "mil": _2, "net": _2, "org": _2 } }, "sa": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "med": _2, "pub": _2, "edu": _2, "sch": _2 } }, "sb": _4, "sc": _4, "sd": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "edu": _2, "med": _2, "tv": _2, "gov": _2, "info": _2 } }, "se": { "$": 1, "succ": { "a": _2, "ac": _2, "b": _2, "bd": _2, "brand": _2, "c": _2, "d": _2, "e": _2, "f": _2, "fh": _2, "fhsk": _2, "fhv": _2, "g": _2, "h": _2, "i": _2, "k": _2, "komforb": _2, "kommunalforbund": _2, "komvux": _2, "l": _2, "lanbib": _2, "m": _2, "n": _2, "naturbruksgymn": _2, "o": _2, "org": _2, "p": _2, "parti": _2, "pp": _2, "press": _2, "r": _2, "s": _2, "t": _2, "tm": _2, "u": _2, "w": _2, "x": _2, "y": _2, "z": _2, "com": _3, "blogspot": _3, "conf": _3, "iopsys": _3, "itcouldbewor": _3, "myspreadshop": _3, "paba": { "$": 0, "succ": { "su": _3 } } } }, "sg": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "edu": _2, "per": _2, "blogspot": _3, "enscaled": _3 } }, "sh": { "$": 1, "succ": { "com": _2, "net": _2, "gov": _2, "org": _2, "mil": _2, "bip": _3, "hashbang": _3, "platform": { "$": 0, "succ": { "bc": _3, "ent": _3, "eu": _3, "us": _3 } }, "now": _3, "vxl": _3, "wedeploy": _3 } }, "si": { "$": 1, "succ": { "gitapp": _3, "gitpage": _3, "blogspot": _3 } }, "sj": _2, "sk": _6, "sl": _4, "sm": _2, "sn": { "$": 1, "succ": { "art": _2, "com": _2, "edu": _2, "gouv": _2, "org": _2, "perso": _2, "univ": _2, "blogspot": _3 } }, "so": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "me": _2, "net": _2, "org": _2, "sch": _3 } }, "sr": _2, "ss": { "$": 1, "succ": { "biz": _2, "com": _2, "edu": _2, "gov": _2, "me": _2, "net": _2, "org": _2, "sch": _2 } }, "st": { "$": 1, "succ": { "co": _2, "com": _2, "consulado": _2, "edu": _2, "embaixada": _2, "mil": _2, "net": _2, "org": _2, "principe": _2, "saotome": _2, "store": _2, "noho": _3 } }, "su": { "$": 1, "succ": { "abkhazia": _3, "adygeya": _3, "aktyubinsk": _3, "arkhangelsk": _3, "armenia": _3, "ashgabad": _3, "azerbaijan": _3, "balashov": _3, "bashkiria": _3, "bryansk": _3, "bukhara": _3, "chimkent": _3, "dagestan": _3, "east-kazakhstan": _3, "exnet": _3, "georgia": _3, "grozny": _3, "ivanovo": _3, "jambyl": _3, "kalmykia": _3, "kaluga": _3, "karacol": _3, "karaganda": _3, "karelia": _3, "khakassia": _3, "krasnodar": _3, "kurgan": _3, "kustanai": _3, "lenug": _3, "mangyshlak": _3, "mordovia": _3, "msk": _3, "murmansk": _3, "nalchik": _3, "navoi": _3, "north-kazakhstan": _3, "nov": _3, "obninsk": _3, "penza": _3, "pokrovsk": _3, "sochi": _3, "spb": _3, "tashkent": _3, "termez": _3, "togliatti": _3, "troitsk": _3, "tselinograd": _3, "tula": _3, "tuva": _3, "vladikavkaz": _3, "vladimir": _3, "vologda": _3 } }, "sv": { "$": 1, "succ": { "com": _2, "edu": _2, "gob": _2, "org": _2, "red": _2 } }, "sx": _7, "sy": _28, "sz": { "$": 1, "succ": { "co": _2, "ac": _2, "org": _2 } }, "tc": { "$": 1, "succ": { "ch": _3, "me": _3, "we": _3 } }, "td": _6, "tel": _2, "tf": _2, "tg": _2, "th": { "$": 1, "succ": { "ac": _2, "co": _2, "go": _2, "in": _2, "mi": _2, "net": _2, "or": _2, "online": _3, "shop": _3 } }, "tj": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _2, "com": _2, "edu": _2, "go": _2, "gov": _2, "int": _2, "mil": _2, "name": _2, "net": _2, "nic": _2, "org": _2, "test": _2, "web": _2 } }, "tk": _2, "tl": _7, "tm": { "$": 1, "succ": { "com": _2, "co": _2, "org": _2, "net": _2, "nom": _2, "gov": _2, "mil": _2, "edu": _2 } }, "tn": { "$": 1, "succ": { "com": _2, "ens": _2, "fin": _2, "gov": _2, "ind": _2, "info": _2, "intl": _2, "mincom": _2, "nat": _2, "net": _2, "org": _2, "perso": _2, "tourism": _2, "orangecloud": _3 } }, "to": { "$": 1, "succ": { "611": _3, "com": _2, "gov": _2, "net": _2, "org": _2, "edu": _2, "mil": _2, "oya": _3, "rdv": _3, "vpnplus": _3, "quickconnect": _12, "nyan": _3 } }, "tr": { "$": 1, "succ": { "av": _2, "bbs": _2, "bel": _2, "biz": _2, "com": _6, "dr": _2, "edu": _2, "gen": _2, "gov": _2, "info": _2, "mil": _2, "k12": _2, "kep": _2, "name": _2, "net": _2, "org": _2, "pol": _2, "tel": _2, "tsk": _2, "tv": _2, "web": _2, "nc": _7 } }, "tt": { "$": 1, "succ": { "co": _2, "com": _2, "org": _2, "net": _2, "biz": _2, "info": _2, "pro": _2, "int": _2, "coop": _2, "jobs": _2, "mobi": _2, "travel": _2, "museum": _2, "aero": _2, "name": _2, "gov": _2, "edu": _2 } }, "tv": { "$": 1, "succ": { "dyndns": _3, "better-than": _3, "on-the-web": _3, "worse-than": _3 } }, "tw": { "$": 1, "succ": { "edu": _2, "gov": _2, "mil": _2, "com": { "$": 1, "succ": { "mymailer": _3 } }, "net": _2, "org": _2, "idv": _2, "game": _2, "ebiz": _2, "club": _2, "xn--zf0ao64a": _2, "網路": _2, "xn--uc0atv": _2, "組織": _2, "xn--czrw28b": _2, "商業": _2, "url": _3, "blogspot": _3 } }, "tz": { "$": 1, "succ": { "ac": _2, "co": _2, "go": _2, "hotel": _2, "info": _2, "me": _2, "mil": _2, "mobi": _2, "ne": _2, "or": _2, "sc": _2, "tv": _2 } }, "ua": { "$": 1, "succ": { "com": _2, "edu": _2, "gov": _2, "in": _2, "net": _2, "org": _2, "cherkassy": _2, "cherkasy": _2, "chernigov": _2, "chernihiv": _2, "chernivtsi": _2, "chernovtsy": _2, "ck": _2, "cn": _2, "cr": _2, "crimea": _2, "cv": _2, "dn": _2, "dnepropetrovsk": _2, "dnipropetrovsk": _2, "donetsk": _2, "dp": _2, "if": _2, "ivano-frankivsk": _2, "kh": _2, "kharkiv": _2, "kharkov": _2, "kherson": _2, "khmelnitskiy": _2, "khmelnytskyi": _2, "kiev": _2, "kirovograd": _2, "km": _2, "kr": _2, "krym": _2, "ks": _2, "kv": _2, "kyiv": _2, "lg": _2, "lt": _2, "lugansk": _2, "lutsk": _2, "lv": _2, "lviv": _2, "mk": _2, "mykolaiv": _2, "nikolaev": _2, "od": _2, "odesa": _2, "odessa": _2, "pl": _2, "poltava": _2, "rivne": _2, "rovno": _2, "rv": _2, "sb": _2, "sebastopol": _2, "sevastopol": _2, "sm": _2, "sumy": _2, "te": _2, "ternopil": _2, "uz": _2, "uzhgorod": _2, "vinnica": _2, "vinnytsia": _2, "vn": _2, "volyn": _2, "yalta": _2, "zaporizhzhe": _2, "zaporizhzhia": _2, "zhitomir": _2, "zhytomyr": _2, "zp": _2, "zt": _2, "cc": _3, "inf": _3, "ltd": _3, "cx": _3, "biz": _3, "co": _3, "pp": _3, "v": _3 } }, "ug": { "$": 1, "succ": { "co": _2, "or": _2, "ac": _2, "sc": _2, "go": _2, "ne": _2, "com": _2, "org": _2, "blogspot": _3 } }, "uk": { "$": 1, "succ": { "ac": _2, "co": { "$": 1, "succ": { "bytemark": { "$": 0, "succ": { "dh": _3, "vm": _3 } }, "blogspot": _3, "layershift": _22, "barsy": _3, "barsyonline": _3, "retrosnub": _27, "nh-serv": _3, "no-ip": _3, "wellbeingzone": _3, "adimo": _3, "myspreadshop": _3, "gwiddle": _3 } }, "gov": { "$": 1, "succ": { "campaign": _3, "service": _3, "api": _3, "homeoffice": _3 } }, "ltd": _2, "me": _2, "net": _2, "nhs": _2, "org": { "$": 1, "succ": { "glug": _3, "lug": _3, "lugs": _3, "affinitylottery": _3, "raffleentry": _3, "weeklylottery": _3 } }, "plc": _2, "police": _2, "sch": _8, "conn": _3, "copro": _3, "hosp": _3, "independent-commission": _3, "independent-inquest": _3, "independent-inquiry": _3, "independent-panel": _3, "independent-review": _3, "public-inquiry": _3, "royal-commission": _3, "pymnt": _3, "barsy": _3 } }, "us": { "$": 1, "succ": { "dni": _2, "fed": _2, "isa": _2, "kids": _2, "nsn": _2, "ak": _35, "al": _35, "ar": _35, "as": _35, "az": _35, "ca": _35, "co": _35, "ct": _35, "dc": _35, "de": { "$": 1, "succ": { "k12": _2, "cc": _2, "lib": _3 } }, "fl": _35, "ga": _35, "gu": _35, "hi": _36, "ia": _35, "id": _35, "il": _35, "in": _35, "ks": _35, "ky": _35, "la": _35, "ma": { "$": 1, "succ": { "k12": { "$": 1, "succ": { "pvt": _2, "chtr": _2, "paroch": _2 } }, "cc": _2, "lib": _2 } }, "md": _35, "me": _35, "mi": { "$": 1, "succ": { "k12": _2, "cc": _2, "lib": _2, "ann-arbor": _2, "cog": _2, "dst": _2, "eaton": _2, "gen": _2, "mus": _2, "tec": _2, "washtenaw": _2 } }, "mn": _35, "mo": _35, "ms": _35, "mt": _35, "nc": _35, "nd": _36, "ne": _35, "nh": _35, "nj": _35, "nm": _35, "nv": _35, "ny": _35, "oh": _35, "ok": _35, "or": _35, "pa": _35, "pr": _35, "ri": _36, "sc": _35, "sd": _36, "tn": _35, "tx": _35, "ut": _35, "vi": _35, "vt": _35, "va": _35, "wa": _35, "wi": _35, "wv": { "$": 1, "succ": { "cc": _2 } }, "wy": _35, "graphox": _3, "cloudns": _3, "drud": _3, "is-by": _3, "land-4-sale": _3, "stuff-4-sale": _3, "enscaled": { "$": 0, "succ": { "phx": _3 } }, "mircloud": _3, "freeddns": _3, "golffan": _3, "noip": _3, "pointto": _3, "platterp": _3 } }, "uy": { "$": 1, "succ": { "com": _6, "edu": _2, "gub": _2, "mil": _2, "net": _2, "org": _2 } }, "uz": { "$": 1, "succ": { "co": _2, "com": _2, "net": _2, "org": _2 } }, "va": _2, "vc": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "mil": _2, "edu": _2, "gv": { "$": 2, "succ": { "d": _3 } }, "0e": _3 } }, "ve": { "$": 1, "succ": { "arts": _2, "bib": _2, "co": _2, "com": _2, "e12": _2, "edu": _2, "firm": _2, "gob": _2, "gov": _2, "info": _2, "int": _2, "mil": _2, "net": _2, "nom": _2, "org": _2, "rar": _2, "rec": _2, "store": _2, "tec": _2, "web": _2 } }, "vg": { "$": 1, "succ": { "at": _3 } }, "vi": { "$": 1, "succ": { "co": _2, "com": _2, "k12": _2, "net": _2, "org": _2 } }, "vn": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "edu": _2, "gov": _2, "int": _2, "ac": _2, "biz": _2, "info": _2, "name": _2, "pro": _2, "health": _2, "blogspot": _3 } }, "vu": { "$": 1, "succ": { "com": _2, "edu": _2, "net": _2, "org": _2, "cn": _3, "blog": _3, "dev": _3, "me": _3 } }, "wf": _2, "ws": { "$": 1, "succ": { "com": _2, "net": _2, "org": _2, "gov": _2, "edu": _2, "advisor": _5, "cloud66": _3, "dyndns": _3, "mypets": _3 } }, "yt": { "$": 1, "succ": { "org": _3 } }, "xn--mgbaam7a8h": _2, "امارات": _2, "xn--y9a3aq": _2, "հայ": _2, "xn--54b7fta0cc": _2, "বাংলা": _2, "xn--90ae": _2, "бг": _2, "xn--mgbcpq6gpa1a": _2, "البحرين": _2, "xn--90ais": _2, "бел": _2, "xn--fiqs8s": _2, "中国": _2, "xn--fiqz9s": _2, "中國": _2, "xn--lgbbat1ad8j": _2, "الجزائر": _2, "xn--wgbh1c": _2, "مصر": _2, "xn--e1a4c": _2, "ею": _2, "xn--qxa6a": _2, "ευ": _2, "xn--mgbah1a3hjkrd": _2, "موريتانيا": _2, "xn--node": _2, "გე": _2, "xn--qxam": _2, "ελ": _2, "xn--j6w193g": { "$": 1, "succ": { "xn--55qx5d": _2, "xn--wcvs22d": _2, "xn--mxtq1m": _2, "xn--gmqw5a": _2, "xn--od0alg": _2, "xn--uc0atv": _2 } }, "香港": { "$": 1, "succ": { "公司": _2, "教育": _2, "政府": _2, "個人": _2, "網絡": _2, "組織": _2 } }, "xn--2scrj9c": _2, "ಭಾರತ": _2, "xn--3hcrj9c": _2, "ଭାରତ": _2, "xn--45br5cyl": _2, "ভাৰত": _2, "xn--h2breg3eve": _2, "भारतम्": _2, "xn--h2brj9c8c": _2, "भारोत": _2, "xn--mgbgu82a": _2, "ڀارت": _2, "xn--rvc1e0am3e": _2, "ഭാരതം": _2, "xn--h2brj9c": _2, "भारत": _2, "xn--mgbbh1a": _2, "بارت": _2, "xn--mgbbh1a71e": _2, "بھارت": _2, "xn--fpcrj9c3d": _2, "భారత్": _2, "xn--gecrj9c": _2, "ભારત": _2, "xn--s9brj9c": _2, "ਭਾਰਤ": _2, "xn--45brj9c": _2, "ভারত": _2, "xn--xkc2dl3a5ee0h": _2, "இந்தியா": _2, "xn--mgba3a4f16a": _2, "ایران": _2, "xn--mgba3a4fra": _2, "ايران": _2, "xn--mgbtx2b": _2, "عراق": _2, "xn--mgbayh7gpa": _2, "الاردن": _2, "xn--3e0b707e": _2, "한국": _2, "xn--80ao21a": _2, "қаз": _2, "xn--q7ce6a": _2, "ລາວ": _2, "xn--fzc2c9e2c": _2, "ලංකා": _2, "xn--xkc2al3hye2a": _2, "இலங்கை": _2, "xn--mgbc0a9azcg": _2, "المغرب": _2, "xn--d1alf": _2, "мкд": _2, "xn--l1acc": _2, "мон": _2, "xn--mix891f": _2, "澳門": _2, "xn--mix082f": _2, "澳门": _2, "xn--mgbx4cd0ab": _2, "مليسيا": _2, "xn--mgb9awbf": _2, "عمان": _2, "xn--mgbai9azgqp6j": _2, "پاکستان": _2, "xn--mgbai9a5eva00b": _2, "پاكستان": _2, "xn--ygbi2ammx": _2, "فلسطين": _2, "xn--90a3ac": { "$": 1, "succ": { "xn--o1ac": _2, "xn--c1avg": _2, "xn--90azh": _2, "xn--d1at": _2, "xn--o1ach": _2, "xn--80au": _2 } }, "срб": { "$": 1, "succ": { "пр": _2, "орг": _2, "обр": _2, "од": _2, "упр": _2, "ак": _2 } }, "xn--p1ai": _2, "рф": _2, "xn--wgbl6a": _2, "قطر": _2, "xn--mgberp4a5d4ar": _2, "السعودية": _2, "xn--mgberp4a5d4a87g": _2, "السعودیة": _2, "xn--mgbqly7c0a67fbc": _2, "السعودیۃ": _2, "xn--mgbqly7cvafr": _2, "السعوديه": _2, "xn--mgbpl2fh": _2, "سودان": _2, "xn--yfro4i67o": _2, "新加坡": _2, "xn--clchc0ea0b2g2a9gcd": _2, "சிங்கப்பூர்": _2, "xn--ogbpf8fl": _2, "سورية": _2, "xn--mgbtf8fl": _2, "سوريا": _2, "xn--o3cw4h": { "$": 1, "succ": { "xn--12c1fe0br": _2, "xn--12co0c3b4eva": _2, "xn--h3cuzk1di": _2, "xn--o3cyx2a": _2, "xn--m3ch0j3a": _2, "xn--12cfi8ixb8l": _2 } }, "ไทย": { "$": 1, "succ": { "ศึกษา": _2, "ธุรกิจ": _2, "รัฐบาล": _2, "ทหาร": _2, "เน็ต": _2, "องค์กร": _2 } }, "xn--pgbs0dh": _2, "تونس": _2, "xn--kpry57d": _2, "台灣": _2, "xn--kprw13d": _2, "台湾": _2, "xn--nnx388a": _2, "臺灣": _2, "xn--j1amh": _2, "укр": _2, "xn--mgb2ddes": _2, "اليمن": _2, "xxx": _2, "ye": _28, "za": { "$": 0, "succ": { "ac": _2, "agric": _2, "alt": _2, "co": _6, "edu": _2, "gov": _2, "grondar": _2, "law": _2, "mil": _2, "net": _2, "ngo": _2, "nic": _2, "nis": _2, "nom": _2, "org": _2, "school": _2, "tm": _2, "web": _2 } }, "zm": { "$": 1, "succ": { "ac": _2, "biz": _2, "co": _2, "com": _2, "edu": _2, "gov": _2, "info": _2, "mil": _2, "net": _2, "org": _2, "sch": _2 } }, "zw": { "$": 1, "succ": { "ac": _2, "co": _2, "gov": _2, "mil": _2, "org": _2 } }, "aaa": _2, "aarp": _2, "abarth": _2, "abb": _2, "abbott": _2, "abbvie": _2, "abc": _2, "able": _2, "abogado": _2, "abudhabi": _2, "academy": { "$": 1, "succ": { "official": _3 } }, "accenture": _2, "accountant": _2, "accountants": _2, "aco": _2, "actor": _2, "adac": _2, "ads": _2, "adult": _2, "aeg": _2, "aetna": _2, "afl": _2, "africa": _2, "agakhan": _2, "agency": _2, "aig": _2, "airbus": _2, "airforce": _2, "airtel": _2, "akdn": _2, "alfaromeo": _2, "alibaba": _2, "alipay": _2, "allfinanz": _2, "allstate": _2, "ally": _2, "alsace": _2, "alstom": _2, "amazon": _2, "americanexpress": _2, "americanfamily": _2, "amex": _2, "amfam": _2, "amica": _2, "amsterdam": _2, "analytics": _2, "android": _2, "anquan": _2, "anz": _2, "aol": _2, "apartments": _2, "app": { "$": 1, "succ": { "beget": _5, "clerk": _3, "clerkstage": _3, "wnext": _3, "platform0": _3, "deta": _3, "ondigitalocean": _3, "encr": _3, "edgecompute": _3, "fireweb": _3, "onflashdrive": _3, "framer": _3, "run": { "$": 2, "succ": { "a": _3 } }, "web": _3, "hasura": _3, "loginline": _3, "netlify": _3, "developer": _5, "noop": _3, "northflank": _5, "telebit": _3, "typedream": _3, "vercel": _3, "bookonline": _3 } }, "apple": _2, "aquarelle": _2, "arab": _2, "aramco": _2, "archi": _2, "army": _2, "art": _2, "arte": _2, "asda": _2, "associates": _2, "athleta": _2, "attorney": _2, "auction": _2, "audi": _2, "audible": _2, "audio": _2, "auspost": _2, "author": _2, "auto": _2, "autos": _2, "avianca": _2, "aws": _2, "axa": _2, "azure": _2, "baby": _2, "baidu": _2, "banamex": _2, "bananarepublic": _2, "band": _2, "bank": _2, "bar": _2, "barcelona": _2, "barclaycard": _2, "barclays": _2, "barefoot": _2, "bargains": _2, "baseball": _2, "basketball": { "$": 1, "succ": { "aus": _3, "nz": _3 } }, "bauhaus": _2, "bayern": _2, "bbc": _2, "bbt": _2, "bbva": _2, "bcg": _2, "bcn": _2, "beats": _2, "beauty": _2, "beer": _2, "bentley": _2, "berlin": _2, "best": _2, "bestbuy": _2, "bet": _2, "bharti": _2, "bible": _2, "bid": _2, "bike": _2, "bing": _2, "bingo": _2, "bio": _2, "black": _2, "blackfriday": _2, "blockbuster": _2, "blog": _2, "bloomberg": _2, "blue": _2, "bms": _2, "bmw": _2, "bnpparibas": _2, "boats": _2, "boehringer": _2, "bofa": _2, "bom": _2, "bond": _2, "boo": _2, "book": _2, "booking": _2, "bosch": _2, "bostik": _2, "boston": _2, "bot": _2, "boutique": _2, "box": _2, "bradesco": _2, "bridgestone": _2, "broadway": _2, "broker": _2, "brother": _2, "brussels": _2, "bugatti": _2, "build": _2, "builders": { "$": 1, "succ": { "cloudsite": _3 } }, "business": _10, "buy": _2, "buzz": _2, "bzh": _2, "cab": _2, "cafe": _2, "cal": _2, "call": _2, "calvinklein": _2, "cam": _2, "camera": _2, "camp": _2, "cancerresearch": _2, "canon": _2, "capetown": _2, "capital": _2, "capitalone": _2, "car": _2, "caravan": _2, "cards": _2, "care": _2, "career": _2, "careers": _2, "cars": _2, "casa": { "$": 1, "succ": { "nabu": { "$": 0, "succ": { "ui": _3 } } } }, "case": _2, "cash": _2, "casino": _2, "catering": _2, "catholic": _2, "cba": _2, "cbn": _2, "cbre": _2, "cbs": _2, "center": _2, "ceo": _2, "cern": _2, "cfa": _2, "cfd": _2, "chanel": _2, "channel": _2, "charity": _2, "chase": _2, "chat": _2, "cheap": _2, "chintai": _2, "christmas": _2, "chrome": _2, "church": _2, "cipriani": _2, "circle": _2, "cisco": _2, "citadel": _2, "citi": _2, "citic": _2, "city": _2, "cityeats": _2, "claims": _2, "cleaning": _2, "click": _2, "clinic": _2, "clinique": _2, "clothing": _2, "cloud": { "$": 1, "succ": { "banzai": _5, "elementor": _3, "encoway": { "$": 0, "succ": { "eu": _3 } }, "statics": _5, "ravendb": _3, "axarnet": { "$": 0, "succ": { "es-1": _3 } }, "diadem": _3, "jelastic": { "$": 0, "succ": { "vip": _3 } }, "jele": _3, "jenv-aruba": { "$": 0, "succ": { "aruba": { "$": 0, "succ": { "eur": { "$": 0, "succ": { "it1": _3 } } } }, "it1": _3 } }, "keliweb": { "$": 2, "succ": { "cs": _3 } }, "oxa": { "$": 2, "succ": { "tn": _3, "uk": _3 } }, "primetel": { "$": 2, "succ": { "uk": _3 } }, "reclaim": { "$": 0, "succ": { "ca": _3, "uk": _3, "us": _3 } }, "trendhosting": { "$": 0, "succ": { "ch": _3, "de": _3 } }, "jotelulu": _3, "kuleuven": _3, "linkyard": _3, "magentosite": _5, "perspecta": _3, "vapor": _3, "on-rancher": _5, "sensiosite": _5, "trafficplex": _3, "urown": _3, "voorloper": _3 } }, "club": { "$": 1, "succ": { "cloudns": _3, "jele": _3, "barsy": _3, "pony": _3 } }, "clubmed": _2, "coach": _2, "codes": { "$": 1, "succ": { "owo": _5 } }, "coffee": _2, "college": _2, "cologne": _2, "comcast": _2, "commbank": _2, "community": { "$": 1, "succ": { "nog": _3, "ravendb": _3, "myforum": _3 } }, "company": _2, "compare": _2, "computer": _2, "comsec": _2, "condos": _2, "construction": _2, "consulting": _2, "contact": _2, "contractors": _2, "cooking": _2, "cookingchannel": _2, "cool": { "$": 1, "succ": { "elementor": _3, "de": _3 } }, "corsica": _2, "country": _2, "coupon": _2, "coupons": _2, "courses": _2, "cpa": _2, "credit": _2, "creditcard": _2, "creditunion": _2, "cricket": _2, "crown": _2, "crs": _2, "cruise": _2, "cruises": _2, "cuisinella": _2, "cymru": _2, "cyou": _2, "dabur": _2, "dad": _2, "dance": _2, "data": _2, "date": _2, "dating": _2, "datsun": _2, "day": _2, "dclk": _2, "dds": _2, "deal": _2, "dealer": _2, "deals": _2, "degree": _2, "delivery": _2, "dell": _2, "deloitte": _2, "delta": _2, "democrat": _2, "dental": _2, "dentist": _2, "desi": _2, "design": { "$": 1, "succ": { "bss": _3 } }, "dev": { "$": 1, "succ": { "lcl": _5, "lclstage": _5, "stg": _5, "stgstage": _5, "pages": _3, "workers": _3, "curv": _3, "deno": _3, "deno-staging": _3, "deta": _3, "fly": _3, "githubpreview": _3, "gateway": _5, "iserv": _3, "localcert": { "$": 0, "succ": { "user": _5 } }, "loginline": _3, "mediatech": _3, "platter-app": _3, "shiftcrypto": _3, "vercel": _3, "webhare": _5 } }, "dhl": _2, "diamonds": _2, "diet": _2, "digital": { "$": 1, "succ": { "cloudapps": { "$": 2, "succ": { "london": _3 } } } }, "direct": _2, "directory": _2, "discount": _2, "discover": _2, "dish": _2, "diy": _2, "dnp": _2, "docs": _2, "doctor": _2, "dog": _2, "domains": _2, "dot": _2, "download": _2, "drive": _2, "dtv": _2, "dubai": _2, "dunlop": _2, "dupont": _2, "durban": _2, "dvag": _2, "dvr": _2, "earth": { "$": 1, "succ": { "dapps": { "$": 0, "succ": { "*": _3, "bzz": _5 } } } }, "eat": _2, "eco": _2, "edeka": _2, "education": _10, "email": _2, "emerck": _2, "energy": _2, "engineer": _2, "engineering": _2, "enterprises": _2, "epson": _2, "equipment": _2, "ericsson": _2, "erni": _2, "esq": _2, "estate": { "$": 1, "succ": { "compute": _5 } }, "etisalat": _2, "eurovision": _2, "eus": { "$": 1, "succ": { "party": _24 } }, "events": { "$": 1, "succ": { "koobin": _3, "co": _3 } }, "exchange": _2, "expert": _2, "exposed": _2, "express": _2, "extraspace": _2, "fage": _2, "fail": _2, "fairwinds": _2, "faith": _25, "family": _2, "fan": _2, "fans": _2, "farm": { "$": 1, "succ": { "storj": _3 } }, "farmers": _2, "fashion": { "$": 1, "succ": { "of": _3 } }, "fast": _2, "fedex": _2, "feedback": _2, "ferrari": _2, "ferrero": _2, "fiat": _2, "fidelity": _2, "fido": _2, "film": _2, "final": _2, "finance": _2, "financial": _10, "fire": _2, "firestone": _2, "firmdale": _2, "fish": _2, "fishing": _2, "fit": _2, "fitness": _2, "flickr": _2, "flights": _2, "flir": _2, "florist": _2, "flowers": _2, "fly": _2, "foo": _2, "food": _2, "foodnetwork": _2, "football": _2, "ford": _2, "forex": _2, "forsale": _2, "forum": _2, "foundation": _2, "fox": _2, "free": _2, "fresenius": _2, "frl": _2, "frogans": _2, "frontdoor": _2, "frontier": _2, "ftr": _2, "fujitsu": _2, "fun": _2, "fund": _2, "furniture": _2, "futbol": _2, "fyi": _2, "gal": _2, "gallery": _2, "gallo": _2, "gallup": _2, "game": _2, "games": _2, "gap": _2, "garden": _2, "gay": _2, "gbiz": _2, "gdn": { "$": 1, "succ": { "cnpy": _3 } }, "gea": _2, "gent": _2, "genting": _2, "george": _2, "ggee": _2, "gift": _2, "gifts": _2, "gives": _2, "giving": _2, "glass": _2, "gle": _2, "global": _2, "globo": _2, "gmail": _2, "gmbh": _2, "gmo": _2, "gmx": _2, "godaddy": _2, "gold": _2, "goldpoint": _2, "golf": _2, "goo": _2, "goodyear": _2, "goog": { "$": 1, "succ": { "cloud": _3, "translate": _3, "usercontent": _5 } }, "google": _2, "gop": _2, "got": _2, "grainger": _2, "graphics": _2, "gratis": _2, "green": _2, "gripe": _2, "grocery": _2, "group": { "$": 1, "succ": { "discourse": _3 } }, "guardian": _2, "gucci": _2, "guge": _2, "guide": _2, "guitars": _2, "guru": _2, "hair": _2, "hamburg": _2, "hangout": _2, "haus": _2, "hbo": _2, "hdfc": _2, "hdfcbank": _2, "health": { "$": 1, "succ": { "hra": _3 } }, "healthcare": _2, "help": _2, "helsinki": _2, "here": _2, "hermes": _2, "hgtv": _2, "hiphop": _2, "hisamitsu": _2, "hitachi": _2, "hiv": _2, "hkt": _2, "hockey": _2, "holdings": _2, "holiday": _2, "homedepot": _2, "homegoods": _2, "homes": _2, "homesense": _2, "honda": _2, "horse": _2, "hospital": _2, "host": { "$": 1, "succ": { "cloudaccess": _3, "freesite": _3, "fastvps": _3, "myfast": _3, "tempurl": _3, "wpmudev": _3, "jele": _3, "mircloud": _3, "pcloud": _3, "half": _3 } }, "hosting": { "$": 1, "succ": { "opencraft": _3 } }, "hot": _2, "hoteles": _2, "hotels": _2, "hotmail": _2, "house": _2, "how": _2, "hsbc": _2, "hughes": _2, "hyatt": _2, "hyundai": _2, "ibm": _2, "icbc": _2, "ice": _2, "icu": _2, "ieee": _2, "ifm": _2, "ikano": _2, "imamat": _2, "imdb": _2, "immo": _2, "immobilien": _2, "inc": _2, "industries": _2, "infiniti": _2, "ing": _2, "ink": _2, "institute": _2, "insurance": _2, "insure": _2, "international": _2, "intuit": _2, "investments": _2, "ipiranga": _2, "irish": _2, "ismaili": _2, "ist": _2, "istanbul": _2, "itau": _2, "itv": _2, "jaguar": _2, "java": _2, "jcb": _2, "jeep": _2, "jetzt": _2, "jewelry": _2, "jio": _2, "jll": _2, "jmp": _2, "jnj": _2, "joburg": _2, "jot": _2, "joy": _2, "jpmorgan": _2, "jprs": _2, "juegos": _2, "juniper": _2, "kaufen": _2, "kddi": _2, "kerryhotels": _2, "kerrylogistics": _2, "kerryproperties": _2, "kfh": _2, "kia": _2, "kids": _2, "kim": _2, "kinder": _2, "kindle": _2, "kitchen": _2, "kiwi": _2, "koeln": _2, "komatsu": _2, "kosher": _2, "kpmg": _2, "kpn": _2, "krd": { "$": 1, "succ": { "co": _3, "edu": _3 } }, "kred": _2, "kuokgroup": _2, "kyoto": _2, "lacaixa": _2, "lamborghini": _2, "lamer": _2, "lancaster": _2, "lancia": _2, "land": { "$": 1, "succ": { "static": { "$": 2, "succ": { "dev": _3, "sites": _3 } } } }, "landrover": _2, "lanxess": _2, "lasalle": _2, "lat": _2, "latino": _2, "latrobe": _2, "law": _2, "lawyer": _2, "lds": _2, "lease": _2, "leclerc": _2, "lefrak": _2, "legal": _2, "lego": _2, "lexus": _2, "lgbt": _2, "lidl": _2, "life": _2, "lifeinsurance": _2, "lifestyle": _2, "lighting": _2, "like": _2, "lilly": _2, "limited": _2, "limo": _2, "lincoln": _2, "linde": _2, "link": { "$": 1, "succ": { "cyon": _3, "mypep": _3, "dweb": _5 } }, "lipsy": _2, "live": { "$": 1, "succ": { "hlx": _3 } }, "living": _2, "llc": _2, "llp": _2, "loan": _2, "loans": _2, "locker": _2, "locus": _2, "loft": _2, "lol": { "$": 1, "succ": { "omg": _3 } }, "london": { "$": 1, "succ": { "in": _3, "of": _3 } }, "lotte": _2, "lotto": _2, "love": _2, "lpl": _2, "lplfinancial": _2, "ltd": _2, "ltda": _2, "lundbeck": _2, "luxe": _2, "luxury": _2, "macys": _2, "madrid": _2, "maif": _2, "maison": _2, "makeup": _2, "man": _2, "management": { "$": 1, "succ": { "router": _3 } }, "mango": _2, "map": _2, "market": _2, "marketing": { "$": 1, "succ": { "from": _3, "with": _3 } }, "markets": _2, "marriott": _2, "marshalls": _2, "maserati": _2, "mattel": _2, "mba": _2, "mckinsey": _2, "med": _2, "media": _2, "meet": _2, "melbourne": _2, "meme": _2, "memorial": _2, "men": { "$": 1, "succ": { "for": _3, "repair": _3 } }, "menu": _31, "merckmsd": _2, "miami": _2, "microsoft": _2, "mini": _2, "mint": _2, "mit": _2, "mitsubishi": _2, "mlb": _2, "mls": _2, "mma": _2, "mobile": _2, "moda": _2, "moe": _2, "moi": _2, "mom": { "$": 1, "succ": { "and": _3, "for": _3 } }, "monash": _2, "money": _2, "monster": _2, "mormon": _2, "mortgage": _2, "moscow": _2, "moto": _2, "motorcycles": _2, "mov": _2, "movie": _2, "msd": _2, "mtn": _2, "mtr": _2, "music": _2, "mutual": _2, "nab": _2, "nagoya": _2, "natura": _2, "navy": _2, "nba": _2, "nec": _2, "netbank": _2, "netflix": _2, "network": { "$": 1, "succ": { "alces": _5, "co": _3, "arvo": _3, "azimuth": _3, "tlon": _3 } }, "neustar": _2, "new": _2, "news": { "$": 1, "succ": { "noticeable": _3 } }, "next": _2, "nextdirect": _2, "nexus": _2, "nfl": _2, "ngo": _2, "nhk": _2, "nico": _2, "nike": _2, "nikon": _2, "ninja": _2, "nissan": _2, "nissay": _2, "nokia": _2, "northwesternmutual": _2, "norton": _2, "now": _2, "nowruz": _2, "nowtv": _2, "nra": _2, "nrw": _2, "ntt": _2, "nyc": _2, "obi": _2, "observer": _2, "office": _2, "okinawa": _2, "olayan": _2, "olayangroup": _2, "oldnavy": _2, "ollo": _2, "omega": _2, "one": { "$": 1, "succ": { "onred": { "$": 2, "succ": { "staging": _3 } }, "for": _3, "under": _3, "service": _3, "homelink": _3 } }, "ong": _2, "onl": _2, "online": { "$": 1, "succ": { "eero": _3, "eero-stage": _3, "barsy": _3 } }, "ooo": _2, "open": _2, "oracle": _2, "orange": { "$": 1, "succ": { "tech": _3 } }, "organic": _2, "origins": _2, "osaka": _2, "otsuka": _2, "ott": _2, "ovh": { "$": 1, "succ": { "nerdpol": _3 } }, "page": { "$": 1, "succ": { "hlx": _3, "hlx3": _3, "translated": _3, "codeberg": _3, "pdns": _3, "plesk": _3, "prvcy": _3, "rocky": _3, "magnet": _3 } }, "panasonic": _2, "paris": _2, "pars": _2, "partners": _2, "parts": _2, "party": _25, "passagens": _2, "pay": _2, "pccw": _2, "pet": _2, "pfizer": _2, "pharmacy": _2, "phd": _2, "philips": _2, "phone": _2, "photo": _2, "photography": _2, "photos": _2, "physio": _2, "pics": _2, "pictet": _2, "pictures": { "$": 1, "succ": { "1337": _3 } }, "pid": _2, "pin": _2, "ping": _2, "pink": _2, "pioneer": _2, "pizza": _2, "place": _10, "play": _2, "playstation": _2, "plumbing": _2, "plus": _2, "pnc": _2, "pohl": _2, "poker": _2, "politie": _2, "porn": { "$": 1, "succ": { "indie": _3 } }, "pramerica": _2, "praxi": _2, "press": _2, "prime": _2, "prod": _2, "productions": _2, "prof": _2, "progressive": _2, "promo": _2, "properties": _2, "property": _2, "protection": _2, "pru": _2, "prudential": _2, "pub": _31, "pwc": _2, "qpon": _2, "quebec": _2, "quest": _2, "racing": _2, "radio": _2, "read": _2, "realestate": _2, "realtor": _2, "realty": _2, "recipes": _2, "red": _2, "redstone": _2, "redumbrella": _2, "rehab": _2, "reise": _2, "reisen": _2, "reit": _2, "reliance": _2, "ren": _2, "rent": _2, "rentals": _2, "repair": _2, "report": _2, "republican": _2, "rest": _2, "restaurant": _2, "review": _25, "reviews": _2, "rexroth": _2, "rich": _2, "richardli": _2, "ricoh": _2, "ril": _2, "rio": _2, "rip": { "$": 1, "succ": { "clan": _3 } }, "rocher": _2, "rocks": { "$": 1, "succ": { "myddns": _3, "lima-city": _3, "webspace": _3 } }, "rodeo": _2, "rogers": _2, "room": _2, "rsvp": _2, "rugby": _2, "ruhr": _2, "run": { "$": 1, "succ": { "hs": _3, "development": _3, "ravendb": _3, "servers": _3, "build": _5, "code": _5, "database": _5, "migration": _5, "onporter": _3, "repl": _3 } }, "rwe": _2, "ryukyu": _2, "saarland": _2, "safe": _2, "safety": _2, "sakura": _2, "sale": { "$": 1, "succ": { "for": _3 } }, "salon": _2, "samsclub": _2, "samsung": _2, "sandvik": _2, "sandvikcoromant": _2, "sanofi": _2, "sap": _2, "sarl": _2, "sas": _2, "save": _2, "saxo": _2, "sbi": _2, "sbs": _2, "sca": _2, "scb": _2, "schaeffler": _2, "schmidt": _2, "scholarships": _2, "school": _2, "schule": _2, "schwarz": _2, "science": _25, "scot": { "$": 1, "succ": { "edu": _3, "gov": { "$": 2, "succ": { "service": _3 } } } }, "search": _2, "seat": _2, "secure": _2, "security": _2, "seek": _2, "select": _2, "sener": _2, "services": { "$": 1, "succ": { "loginline": _3 } }, "ses": _2, "seven": _2, "sew": _2, "sex": _2, "sexy": _2, "sfr": _2, "shangrila": _2, "sharp": _2, "shaw": _2, "shell": _2, "shia": _2, "shiksha": _2, "shoes": _2, "shop": { "$": 1, "succ": { "base": _3, "hoplix": _3, "barsy": _3 } }, "shopping": _2, "shouji": _2, "show": _2, "showtime": _2, "silk": _2, "sina": _2, "singles": _2, "site": { "$": 1, "succ": { "cloudera": _5, "cyon": _3, "fnwk": _3, "folionetwork": _3, "fastvps": _3, "jele": _3, "lelux": _3, "loginline": _3, "barsy": _3, "mintere": _3, "omniwe": _3, "opensocial": _3, "platformsh": _5, "tst": _5, "byen": _3, "srht": _3, "novecore": _3 } }, "ski": _2, "skin": _2, "sky": _2, "skype": _2, "sling": _2, "smart": _2, "smile": _2, "sncf": _2, "soccer": _2, "social": _2, "softbank": _2, "software": _2, "sohu": _2, "solar": _2, "solutions": { "$": 1, "succ": { "diher": _5 } }, "song": _2, "sony": _2, "soy": _2, "spa": _2, "space": { "$": 1, "succ": { "myfast": _3, "uber": _3, "xs4all": _3 } }, "sport": _2, "spot": _2, "srl": _2, "stada": _2, "staples": _2, "star": _2, "statebank": _2, "statefarm": _2, "stc": _2, "stcgroup": _2, "stockholm": _2, "storage": _2, "store": { "$": 1, "succ": { "sellfy": _3, "shopware": _3, "storebase": _3 } }, "stream": _2, "studio": _2, "study": _2, "style": _2, "sucks": _2, "supplies": _2, "supply": _2, "support": _31, "surf": _2, "surgery": _2, "suzuki": _2, "swatch": _2, "swiss": _2, "sydney": _2, "systems": { "$": 1, "succ": { "knightpoint": _3 } }, "tab": _2, "taipei": _2, "talk": _2, "taobao": _2, "target": _2, "tatamotors": _2, "tatar": _2, "tattoo": _2, "tax": _2, "taxi": _2, "tci": _2, "tdk": _2, "team": { "$": 1, "succ": { "discourse": _3, "jelastic": _3 } }, "tech": _2, "technology": _10, "temasek": _2, "tennis": _2, "teva": _2, "thd": _2, "theater": _2, "theatre": _2, "tiaa": _2, "tickets": _2, "tienda": _2, "tiffany": _2, "tips": _2, "tires": _2, "tirol": _2, "tjmaxx": _2, "tjx": _2, "tkmaxx": _2, "tmall": _2, "today": { "$": 1, "succ": { "prequalifyme": _3 } }, "tokyo": _2, "tools": _2, "top": { "$": 1, "succ": { "now-dns": _3, "ntdll": _3 } }, "toray": _2, "toshiba": _2, "total": _2, "tours": _2, "town": _2, "toyota": _2, "toys": _2, "trade": _25, "trading": _2, "training": _2, "travel": _2, "travelchannel": _2, "travelers": _2, "travelersinsurance": _2, "trust": _2, "trv": _2, "tube": _2, "tui": _2, "tunes": _2, "tushu": _2, "tvs": _2, "ubank": _2, "ubs": _2, "unicom": _2, "university": _2, "uno": _2, "uol": _2, "ups": _2, "vacations": _2, "vana": _2, "vanguard": _2, "vegas": _2, "ventures": _2, "verisign": _2, "versicherung": _2, "vet": _2, "viajes": _2, "video": _2, "vig": _2, "viking": _2, "villas": _2, "vin": _2, "vip": _2, "virgin": _2, "visa": _2, "vision": _2, "viva": _2, "vivo": _2, "vlaanderen": _2, "vodka": _2, "volkswagen": _2, "volvo": _2, "vote": _2, "voting": _2, "voto": _2, "voyage": _2, "vuelos": _2, "wales": _2, "walmart": _2, "walter": _2, "wang": _2, "wanggou": _2, "watch": _2, "watches": _2, "weather": _2, "weatherchannel": _2, "webcam": _2, "weber": _2, "website": _2, "wedding": _2, "weibo": _2, "weir": _2, "whoswho": _2, "wien": _2, "wiki": _2, "williamhill": _2, "win": { "$": 1, "succ": { "that": _3 } }, "windows": _2, "wine": _2, "winners": _2, "wme": _2, "wolterskluwer": _2, "woodside": _2, "work": { "$": 1, "succ": { "from": _3, "to": _3 } }, "works": _2, "world": _2, "wow": _2, "wtc": _2, "wtf": _2, "xbox": _2, "xerox": _2, "xfinity": _2, "xihuan": _2, "xin": _2, "xn--11b4c3d": _2, "कॉम": _2, "xn--1ck2e1b": _2, "セール": _2, "xn--1qqw23a": _2, "佛山": _2, "xn--30rr7y": _2, "慈善": _2, "xn--3bst00m": _2, "集团": _2, "xn--3ds443g": _2, "在线": _2, "xn--3pxu8k": _2, "点看": _2, "xn--42c2d9a": _2, "คอม": _2, "xn--45q11c": _2, "八卦": _2, "xn--4gbrim": _2, "موقع": _2, "xn--55qw42g": _2, "公益": _2, "xn--55qx5d": _2, "公司": _2, "xn--5su34j936bgsg": _2, "香格里拉": _2, "xn--5tzm5g": _2, "网站": _2, "xn--6frz82g": _2, "移动": _2, "xn--6qq986b3xl": _2, "我爱你": _2, "xn--80adxhks": _2, "москва": _2, "xn--80aqecdr1a": _2, "католик": _2, "xn--80asehdb": _2, "онлайн": _2, "xn--80aswg": _2, "сайт": _2, "xn--8y0a063a": _2, "联通": _2, "xn--9dbq2a": _2, "קום": _2, "xn--9et52u": _2, "时尚": _2, "xn--9krt00a": _2, "微博": _2, "xn--b4w605ferd": _2, "淡马锡": _2, "xn--bck1b9a5dre4c": _2, "ファッション": _2, "xn--c1avg": _2, "орг": _2, "xn--c2br7g": _2, "नेट": _2, "xn--cck2b3b": _2, "ストア": _2, "xn--cckwcxetd": _2, "アマゾン": _2, "xn--cg4bki": _2, "삼성": _2, "xn--czr694b": _2, "商标": _2, "xn--czrs0t": _2, "商店": _2, "xn--czru2d": _2, "商城": _2, "xn--d1acj3b": _2, "дети": _2, "xn--eckvdtc9d": _2, "ポイント": _2, "xn--efvy88h": _2, "新闻": _2, "xn--fct429k": _2, "家電": _2, "xn--fhbei": _2, "كوم": _2, "xn--fiq228c5hs": _2, "中文网": _2, "xn--fiq64b": _2, "中信": _2, "xn--fjq720a": _2, "娱乐": _2, "xn--flw351e": _2, "谷歌": _2, "xn--fzys8d69uvgm": _2, "電訊盈科": _2, "xn--g2xx48c": _2, "购物": _2, "xn--gckr3f0f": _2, "クラウド": _2, "xn--gk3at1e": _2, "通販": _2, "xn--hxt814e": _2, "网店": _2, "xn--i1b6b1a6a2e": _2, "संगठन": _2, "xn--imr513n": _2, "餐厅": _2, "xn--io0a7i": _2, "网络": _2, "xn--j1aef": _2, "ком": _2, "xn--jlq480n2rg": _2, "亚马逊": _2, "xn--jlq61u9w7b": _2, "诺基亚": _2, "xn--jvr189m": _2, "食品": _2, "xn--kcrx77d1x4a": _2, "飞利浦": _2, "xn--kput3i": _2, "手机": _2, "xn--mgba3a3ejt": _2, "ارامكو": _2, "xn--mgba7c0bbn0a": _2, "العليان": _2, "xn--mgbaakc7dvf": _2, "اتصالات": _2, "xn--mgbab2bd": _2, "بازار": _2, "xn--mgbca7dzdo": _2, "ابوظبي": _2, "xn--mgbi4ecexp": _2, "كاثوليك": _2, "xn--mgbt3dhd": _2, "همراه": _2, "xn--mk1bu44c": _2, "닷컴": _2, "xn--mxtq1m": _2, "政府": _2, "xn--ngbc5azd": _2, "شبكة": _2, "xn--ngbe9e0a": _2, "بيتك": _2, "xn--ngbrx": _2, "عرب": _2, "xn--nqv7f": _2, "机构": _2, "xn--nqv7fs00ema": _2, "组织机构": _2, "xn--nyqy26a": _2, "健康": _2, "xn--otu796d": _2, "招聘": _2, "xn--p1acf": { "$": 1, "succ": { "xn--90amc": _3, "xn--j1aef": _3, "xn--j1ael8b": _3, "xn--h1ahn": _3, "xn--j1adp": _3, "xn--c1avg": _3, "xn--80aaa0cvac": _3, "xn--h1aliz": _3, "xn--90a1af": _3, "xn--41a": _3 } }, "рус": { "$": 1, "succ": { "биз": _3, "ком": _3, "крым": _3, "мир": _3, "мск": _3, "орг": _3, "самара": _3, "сочи": _3, "спб": _3, "я": _3 } }, "xn--pssy2u": _2, "大拿": _2, "xn--q9jyb4c": _2, "みんな": _2, "xn--qcka1pmc": _2, "グーグル": _2, "xn--rhqv96g": _2, "世界": _2, "xn--rovu88b": _2, "書籍": _2, "xn--ses554g": _2, "网址": _2, "xn--t60b56a": _2, "닷넷": _2, "xn--tckwe": _2, "コム": _2, "xn--tiq49xqyj": _2, "天主教": _2, "xn--unup4y": _2, "游戏": _2, "xn--vermgensberater-ctb": _2, "vermögensberater": _2, "xn--vermgensberatung-pwb": _2, "vermögensberatung": _2, "xn--vhquv": _2, "企业": _2, "xn--vuq861b": _2, "信息": _2, "xn--w4r85el8fhu5dnra": _2, "嘉里大酒店": _2, "xn--w4rs40l": _2, "嘉里": _2, "xn--xhq521b": _2, "广东": _2, "xn--zfr164b": _2, "政务": _2, "xyz": { "$": 1, "succ": { "blogsite": _3, "localzone": _3, "crafting": _3, "zapto": _3, "telebit": _5 } }, "yachts": _2, "yahoo": _2, "yamaxun": _2, "yandex": _2, "yodobashi": _2, "yoga": _2, "yokohama": _2, "you": _2, "youtube": _2, "yun": _2, "zappos": _2, "zara": _2, "zero": _2, "zip": _2, "zone": { "$": 1, "succ": { "cloud66": _3, "hs": _3, "triton": _5, "lima": _3 } }, "zuerich": _2 } };
        return rules;
    })();

    function lookupInTrie(parts, trie, index, allowedMask) {
        let result = null;
        let node = trie;
        while (node !== undefined) {
            if ((node.$ & allowedMask) !== 0) {
                result = {
                    index: index + 1,
                    isIcann: node.$ === 1 ,
                    isPrivate: node.$ === 2 ,
                };
            }
            if (index === -1) {
                break;
            }
            const succ = node.succ;
            node = succ && (succ[parts[index]] || succ['*']);
            index -= 1;
        }
        return result;
    }
    function suffixLookup(hostname, options, out) {
        if (fastPathLookup(hostname, options, out) === true) {
            return;
        }
        const hostnameParts = hostname.split('.');
        const allowedMask = (options.allowPrivateDomains === true ? 2  : 0) |
            (options.allowIcannDomains === true ? 1  : 0);
        const exceptionMatch = lookupInTrie(hostnameParts, exceptions, hostnameParts.length - 1, allowedMask);
        if (exceptionMatch !== null) {
            out.isIcann = exceptionMatch.isIcann;
            out.isPrivate = exceptionMatch.isPrivate;
            out.publicSuffix = hostnameParts.slice(exceptionMatch.index + 1).join('.');
            return;
        }
        const rulesMatch = lookupInTrie(hostnameParts, rules, hostnameParts.length - 1, allowedMask);
        if (rulesMatch !== null) {
            out.isIcann = rulesMatch.isIcann;
            out.isPrivate = rulesMatch.isPrivate;
            out.publicSuffix = hostnameParts.slice(rulesMatch.index).join('.');
            return;
        }
        out.isIcann = false;
        out.isPrivate = false;
        out.publicSuffix = hostnameParts[hostnameParts.length - 1];
    }

    const RESULT = getEmptyResult();
    function parse(url, options = {}) {
        return parseImpl(url, 5 , suffixLookup, options, getEmptyResult());
    }
    function getHostname(url, options = {}) {
         resetResult(RESULT);
        return parseImpl(url, 0 , suffixLookup, options, RESULT).hostname;
    }
    function getPublicSuffix(url, options = {}) {
         resetResult(RESULT);
        return parseImpl(url, 2 , suffixLookup, options, RESULT)
            .publicSuffix;
    }

    /**
     * This is a helper class that is used specifically to work
     * with domains restrictions.
     *
     * There are two options how you can add a domain restriction:
     * * `$domain` modifier: https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#domain-modifier
     * * domains list for the cosmetic rules
     *
     * The only difference between them is that in one case we use `|` as a separator,
     * and in the other case - `,`.
     *
     * Examples:
     * * `||example.org^$domain=example.com|~sub.example.com` -- network rule
     * * `example.com,~sub.example.com##banner` -- cosmetic rule
     */
    var DomainModifier = /** @class */ (function () {
        /**
         * Parses the `domains` string and initializes the object.
         *
         * @param domains - domains string
         * @param sep - separator (`,` or `|`)
         *
         * @throws an error if the domains string is empty or invalid
         */
        function DomainModifier(domains, sep) {
            if (!domains) {
                throw new SyntaxError('Modifier $domain cannot be empty');
            }
            var permittedDomains = [];
            var restrictedDomains = [];
            var parts = domains.split(sep);
            for (var i = 0; i < parts.length; i += 1) {
                var domain = parts[i].toLocaleLowerCase();
                var restricted = false;
                if (domain.startsWith('~')) {
                    restricted = true;
                    domain = domain.substring(1).trim();
                }
                if (domain === '') {
                    throw new SyntaxError("Empty domain specified in \"".concat(domains, "\""));
                }
                if (restricted) {
                    restrictedDomains.push(domain);
                }
                else {
                    permittedDomains.push(domain);
                }
            }
            this.restrictedDomains = restrictedDomains.length > 0 ? restrictedDomains : null;
            this.permittedDomains = permittedDomains.length > 0 ? permittedDomains : null;
        }
        /**
         * isDomainOrSubdomainOfAny checks if `domain` is the same or a subdomain
         * of any of `domains`.
         *
         * @param domain - domain to check
         * @param domains - domains list to check against
         */
        DomainModifier.isDomainOrSubdomainOfAny = function (domain, domains) {
            for (var i = 0; i < domains.length; i += 1) {
                var d = domains[i];
                if (DomainModifier.isWildcardDomain(d)) {
                    if (DomainModifier.matchAsWildcard(d, domain)) {
                        return true;
                    }
                }
                if (domain === d || (domain.endsWith(d) && domain.endsWith(".".concat(d)))) {
                    return true;
                }
            }
            return false;
        };
        /**
         * Checks if domain ends with wildcard
         *
         * @param domain
         */
        DomainModifier.isWildcardDomain = function (domain) {
            return domain.endsWith('.*');
        };
        /**
         * Checks if wildcard matches domain
         *
         * @param wildcard
         * @param domainNameToCheck
         */
        DomainModifier.matchAsWildcard = function (wildcard, domainNameToCheck) {
            var wildcardedDomainToCheck = DomainModifier.genTldWildcard(domainNameToCheck);
            if (wildcardedDomainToCheck) {
                return wildcardedDomainToCheck === wildcard
                    || (wildcardedDomainToCheck.endsWith(wildcard) && wildcardedDomainToCheck.endsWith(".".concat(wildcard)));
            }
            return false;
        };
        /**
         * Generates from domain tld wildcard e.g. google.com -> google.* ; youtube.co.uk -> youtube.*
         *
         * @param {string} domainName
         * @returns {string} string is empty if tld for provided domain name doesn't exists
         */
        DomainModifier.genTldWildcard = function (domainName) {
            var tld = getPublicSuffix(domainName);
            if (tld) {
                return "".concat(domainName.slice(0, domainName.indexOf(".".concat(tld))), ".*");
            }
            return '';
        };
        return DomainModifier;
    }());
    /**
     * Comma separator
     */
    var COMMA_SEPARATOR = ',';
    /**
     * Pipe separator
     */
    var PIPE_SEPARATOR = '|';

    /**
     * Replace modifier class
     */
    var ReplaceModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         */
        function ReplaceModifier(value) {
            var parsed = ReplaceModifier.parseReplaceOption(value);
            this.replaceOption = parsed.optionText;
            this.replaceApply = parsed.apply;
        }
        /**
         *
         * @param option
         */
        ReplaceModifier.parseReplaceOption = function (option) {
            if (!option) {
                return {
                    apply: function (x) { return x; },
                    optionText: '',
                };
            }
            var parts = splitByDelimiterWithEscapeCharacter(option, '/', '\\', true);
            if (parts.length < 2 || parts.length > 3) {
                throw new Error("Cannot parse ".concat(option));
            }
            var modifiers = (parts[2] || '');
            if (modifiers.indexOf('g') < 0) {
                modifiers += 'g';
            }
            var pattern = new RegExp(parts[0], modifiers);
            // unescape replacement alias 
            var replacement = parts[1].replace(/\\\$/g, '$');
            var apply = function (input) { return input.replace(pattern, replacement); };
            return {
                apply: apply,
                optionText: option,
            };
        };
        /**
         * Replace content
         */
        ReplaceModifier.prototype.getValue = function () {
            return this.replaceOption;
        };
        /**
         * Replace apply function
         */
        ReplaceModifier.prototype.getApplyFunc = function () {
            return this.replaceApply;
        };
        return ReplaceModifier;
    }());

    /**
     * Csp modifier class
     */
    var CspModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         * @param isAllowlist
         */
        function CspModifier(value, isAllowlist) {
            this.cspDirective = value;
            this.isAllowlist = isAllowlist;
            this.validateCspDirective();
        }
        /**
         * Csp directive
         */
        CspModifier.prototype.getValue = function () {
            return this.cspDirective;
        };
        /**
         * Validates CSP rule
         */
        CspModifier.prototype.validateCspDirective = function () {
            /**
             * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/685
             * CSP directive may be empty in case of allowlist rule,
             * it means to disable all $csp rules matching the allowlist rule
             */
            if (!this.isAllowlist && !this.cspDirective) {
                throw new Error('Invalid $CSP rule: CSP directive must not be empty');
            }
            if (this.cspDirective) {
                /**
                 * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/685#issue-228287090
                 * Forbids report-to and report-uri directives
                 */
                var cspDirective = this.cspDirective.toLowerCase();
                if (cspDirective.indexOf('report-') >= 0) {
                    throw new Error("Forbidden CSP directive: ".concat(cspDirective));
                }
            }
        };
        return CspModifier;
    }());

    /**
     * Cookie modifier class
     *
     * Learn more about it here:
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/961
     */
    var CookieModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         */
        function CookieModifier(value) {
            // Save the source text of the option modifier
            this.optionValue = value || '';
            this.regex = null;
            this.cookieName = null;
            this.sameSite = null;
            this.maxAge = null;
            // Parse cookie name/regex
            var parts = this.optionValue.split(/;/);
            if (parts.length < 1) {
                throw new Error("Cannot parse ".concat(this.optionValue));
            }
            var cookieName = parts[0];
            if (cookieName.startsWith('/') && cookieName.endsWith('/')) {
                var pattern = cookieName.substring(1, cookieName.length - 1);
                // Save regex to be used further for matching cookies
                this.regex = new RegExp(pattern);
            }
            else {
                // Match by cookie name
                this.cookieName = cookieName;
            }
            // Parse other cookie options
            if (parts.length > 1) {
                for (var i = 1; i < parts.length; i += 1) {
                    var nameValue = parts[i].split('=');
                    var optionName = nameValue[0];
                    var optionValue = nameValue[1];
                    if (optionName === CookieModifier.MAX_AGE) {
                        this.maxAge = parseInt(optionValue, 10);
                    }
                    else if (optionName === CookieModifier.SAME_SITE) {
                        this.sameSite = optionValue;
                    }
                    else {
                        throw new Error("Unknown $cookie option: ".concat(optionName));
                    }
                }
            }
        }
        /**
         * Modifier value
         */
        CookieModifier.prototype.getValue = function () {
            return this.optionValue;
        };
        /**
         * First cookie name
         */
        CookieModifier.prototype.getCookieName = function () {
            return this.cookieName;
        };
        /**
         * Max age cookie value
         */
        CookieModifier.prototype.getMaxAge = function () {
            return this.maxAge;
        };
        /**
         * Same site cookie value
         */
        CookieModifier.prototype.getSameSite = function () {
            return this.sameSite;
        };
        /**
         * Checks if cookie with the specified name matches this option
         *
         * @param {string} name Cookie name
         * @return {boolean} true if it does
         */
        CookieModifier.prototype.matches = function (name) {
            if (!name) {
                return false;
            }
            if (this.regex) {
                return this.regex.test(name);
            }
            if (this.cookieName) {
                return this.cookieName === name;
            }
            // Empty regex and cookieName means that we must match all cookies
            return true;
        };
        /**
         * Checks if cookie rule has an empty $cookie option
         *
         * @return {boolean} True if $cookie option is empty
         */
        CookieModifier.prototype.isEmpty = function () {
            return !this.regex && !this.cookieName;
        };
        /**
         * Cookie name maxAge
         */
        CookieModifier.MAX_AGE = 'maxAge';
        /**
         * Cookie name sameSite
         */
        CookieModifier.SAME_SITE = 'sameSite';
        return CookieModifier;
    }());

    var NETWORK_RULE_OPTIONS = {
        THIRD_PARTY: 'third-party',
        FIRST_PARTY: 'first-party',
        MATCH_CASE: 'match-case',
        IMPORTANT: 'important',
        DOMAIN: 'domain',
        DENYALLOW: 'denyallow',
        ELEMHIDE: 'elemhide',
        GENERICHIDE: 'generichide',
        SPECIFICHIDE: 'specifichide',
        GENERICBLOCK: 'genericblock',
        JSINJECT: 'jsinject',
        URLBLOCK: 'urlblock',
        CONTENT: 'content',
        DOCUMENT: 'document',
        DOC: 'doc',
        STEALTH: 'stealth',
        POPUP: 'popup',
        EMPTY: 'empty',
        MP4: 'mp4',
        SCRIPT: 'script',
        STYLESHEET: 'stylesheet',
        SUBDOCUMENT: 'subdocument',
        OBJECT: 'object',
        IMAGE: 'image',
        XMLHTTPREQUEST: 'xmlhttprequest',
        MEDIA: 'media',
        FONT: 'font',
        WEBSOCKET: 'websocket',
        OTHER: 'other',
        PING: 'ping',
        WEBRTC: 'webrtc',
        BADFILTER: 'badfilter',
        CSP: 'csp',
        REPLACE: 'replace',
        COOKIE: 'cookie',
        REDIRECT: 'redirect',
        REDIRECTRULE: 'redirect-rule',
        REMOVEPARAM: 'removeparam',
        REMOVEHEADER: 'removeheader',
        APP: 'app',
        NETWORK: 'network',
        EXTENSION: 'extension',
        NOOP: '_',
        CLIENT: 'client',
        DNSREWRITE: 'dnsrewrite',
        DNSTYPE: 'dnstype',
        CTAG: 'ctag',
    };
    var OPTIONS_DELIMITER = '$';
    var MASK_ALLOWLIST = '@@';
    var NOT_MARK = '~';
    var ESCAPE_CHARACTER = '\\';

    /**
     * Redirect modifier class
     */
    var RedirectModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         * @param ruleText
         * @param isAllowlist
         * @param isRedirectingOnlyBlocked is redirect-rule modifier
         */
        function RedirectModifier(value, ruleText, isAllowlist, isRedirectingOnlyBlocked) {
            if (isRedirectingOnlyBlocked === void 0) { isRedirectingOnlyBlocked = false; }
            /**
             * Is redirecting only blocked requests
             * See $redirect-rule options
             */
            this.isRedirectingOnlyBlocked = false;
            RedirectModifier.validate(ruleText, value, isAllowlist);
            this.redirectTitle = value;
            this.isRedirectingOnlyBlocked = isRedirectingOnlyBlocked;
        }
        /**
         * Redirect title
         */
        RedirectModifier.prototype.getValue = function () {
            return this.redirectTitle;
        };
        /**
         * Validates redirect rule
         *
         * @param ruleText
         * @param redirectTitle
         * @param isAllowlist
         */
        RedirectModifier.validate = function (ruleText, redirectTitle, isAllowlist) {
            if (isAllowlist && !redirectTitle) {
                return;
            }
            if (!redirectTitle) {
                throw new SyntaxError('Invalid $redirect rule, redirect value must not be empty');
            }
            var redirects = scriptlets.redirects;
            var ruleTextToValidate = ruleText.replace(NETWORK_RULE_OPTIONS.REDIRECTRULE, NETWORK_RULE_OPTIONS.REDIRECT);
            if (!redirects.isAdgRedirectRule(ruleTextToValidate) || !redirects.isValidAdgRedirectRule(ruleTextToValidate)) {
                throw new SyntaxError('$redirect modifier is invalid');
            }
        };
        return RedirectModifier;
    }());

    /**
     * Splits url into parts
     *
     * @param url
     */
    function splitUrl(url) {
        var strippedUrl = url;
        var hash = '';
        var hashIndex = url.indexOf('#');
        if (hashIndex >= 0) {
            hash = url.slice(hashIndex);
            strippedUrl = url.slice(0, hashIndex);
        }
        var query = '';
        var queryIndex = url.indexOf('?');
        if (queryIndex >= 0) {
            query = strippedUrl.slice(queryIndex + 1);
            strippedUrl = strippedUrl.slice(0, queryIndex);
        }
        return {
            path: strippedUrl,
            query: query,
            hash: hash,
        };
    }
    /**
     * Normalizes url query parameters
     *
     * @param query
     */
    function normalizeQuery(query) {
        // Cleanup empty params (p0=0&=2&=3)
        var result = query
            .split('&')
            .filter(function (x) { return x && !x.startsWith('='); })
            .join('&');
        // If we've collapsed the URL to the point where there's an '&' against the '?'
        // then we need to get rid of that.
        while (result.charAt(0) === '&') {
            result = result.substr(1);
        }
        return result;
    }
    /**
     * Removes query params from url by regexp
     *
     * @param url
     * @param regExp
     * @param invert remove every parameter in url except the ones matched regexp
     */
    function cleanUrlParamByRegExp(url, regExp, invert) {
        if (invert === void 0) { invert = false; }
        var searchIndex = url.indexOf('?');
        // If no params, nothing to modify
        if (searchIndex === -1) {
            return url;
        }
        var split = splitUrl(url);
        var modifiedQuery;
        if (invert) {
            modifiedQuery = split.query
                .split('&')
                .filter(function (x) { return x; })
                .filter(function (x) { return x && x.match(regExp); })
                .join('&');
        }
        else {
            modifiedQuery = split.query
                .split('&')
                .filter(function (x) {
                var test = x.includes('=') ? x : "".concat(x, "=");
                return !test.match(regExp);
            })
                .join('&');
        }
        // Do not normalize if regexp is not applied
        if (modifiedQuery === split.query) {
            return url;
        }
        modifiedQuery = normalizeQuery(modifiedQuery);
        var result = split.path;
        if (modifiedQuery) {
            result += "?".concat(modifiedQuery);
        }
        return result + split.hash;
    }
    /**
     * Checks third party relation
     *
     * @param requestUrl
     * @param referrer
     */
    function isThirdPartyRequest(requestUrl, referrer) {
        var tldResult = parse(requestUrl);
        var sourceTldResult = parse(referrer);
        return tldResult.domain !== sourceTldResult.domain;
    }
    /**
     * Extract url host
     *
     * @param url
     */
    function getHost(url) {
        var firstIdx = url.indexOf('//');
        if (firstIdx === -1) {
            /**
             * It's non hierarchical structured URL (e.g. stun: or turn:)
             * https://tools.ietf.org/html/rfc4395#section-2.2
             * https://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-08#appendix-B
             */
            firstIdx = url.indexOf(':');
            if (firstIdx === -1) {
                return null;
            }
            firstIdx -= 1;
        }
        var nextSlashIdx = url.indexOf('/', firstIdx + 2);
        var startParamsIdx = url.indexOf('?', firstIdx + 2);
        var lastIdx = nextSlashIdx;
        if (startParamsIdx > 0 && (startParamsIdx < nextSlashIdx || nextSlashIdx < 0)) {
            lastIdx = startParamsIdx;
        }
        var host = lastIdx === -1 ? url.substring(firstIdx + 2) : url.substring(firstIdx + 2, lastIdx);
        var portIndex = host.indexOf(':');
        host = portIndex === -1 ? host : host.substring(0, portIndex);
        var lastChar = host.charAt(host.length - 1);
        if (lastChar === '.') {
            host = host.slice(0, -1);
        }
        return host;
    }
    /**
     * Removes leading www. from domain
     * @param domain
     */
    var getCroppedDomain = function (domain) {
        if (domain.startsWith('www.')) {
            return domain.substring(4);
        }
        return domain;
    };
    var DOMAIN_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/;
    /**
     * Check if the string could be a domain name
     *
     * @param text
     */
    var isDomainName = function (text) {
        if (text.indexOf('.') < 0 || text.endsWith('.')) {
            return false;
        }
        return DOMAIN_REGEX.test(text);
    };
    /**
     * Extract relative part from hierarchical structured URL
     * @param url
     */
    var getRelativeUrl = function (url) {
        var i = url.indexOf('/', url.indexOf('://') + 3);
        return i !== -1 ? url.substr(i) : null;
    };

    /**
     * Query parameters filtering modifier class
     * Works with '$removeparam' modifier
     */
    var RemoveParamModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         */
        function RemoveParamModifier(value) {
            this.value = value;
            var rawValue = value;
            if (value.startsWith('~')) {
                rawValue = value.substring(1);
            }
            if (rawValue.startsWith('/')) {
                this.valueRegExp = SimpleRegex.patternFromString(rawValue);
            }
            else {
                this.valueRegExp = new RegExp("((^|&)(".concat(SimpleRegex.escapeRegexSpecials(rawValue), ")=[^&#]*)"), 'g');
            }
        }
        /**
         * Modifier value
         */
        RemoveParamModifier.prototype.getValue = function () {
            return this.value;
        };
        /**
         * Removes query parameters from url
         *
         * @param url
         */
        RemoveParamModifier.prototype.removeParameters = function (url) {
            var sepIndex = url.indexOf('?');
            if (sepIndex < 0) {
                return url;
            }
            if (!this.value) {
                return url.substring(0, sepIndex);
            }
            if (sepIndex === url.length - 1) {
                return url;
            }
            if (this.value.startsWith('~')) {
                return cleanUrlParamByRegExp(url, this.valueRegExp, true);
            }
            return cleanUrlParamByRegExp(url, this.valueRegExp);
        };
        return RemoveParamModifier;
    }());

    /**
     * Headers filtering modifier class.
     * Rules with $removeheader modifier are intended to remove headers from HTTP requests and responses.
     */
    var RemoveHeaderModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         * @param isAllowlist
         */
        function RemoveHeaderModifier(value, isAllowlist) {
            this.value = value.toLowerCase();
            if (!isAllowlist && !this.value) {
                throw new SyntaxError('Invalid $removeheader rule, removeheader value must not be empty');
            }
            this.isRequestModifier = this.value.startsWith(RemoveHeaderModifier.REQUEST_PREFIX);
            var headerName = this.isRequestModifier
                ? this.value.substring(RemoveHeaderModifier.REQUEST_PREFIX.length) : this.value;
            this.applicableHeaderName = RemoveHeaderModifier.isAllowedHeader(headerName) ? headerName : null;
        }
        /**
         * Modifier value
         */
        RemoveHeaderModifier.prototype.getValue = function () {
            return this.value;
        };
        /**
         * Returns effective header name to be removed
         *
         * @param isRequestHeaders
         */
        RemoveHeaderModifier.prototype.getApplicableHeaderName = function (isRequestHeaders) {
            if (!this.applicableHeaderName) {
                return null;
            }
            if (isRequestHeaders !== this.isRequestModifier) {
                return null;
            }
            return this.applicableHeaderName;
        };
        /**
         * Some headers are forbidden to remove
         *
         * @param headerName
         */
        RemoveHeaderModifier.isAllowedHeader = function (headerName) {
            return !this.FORBIDDEN_HEADERS.includes(headerName);
        };
        /**
         * List of forbidden headers
         */
        RemoveHeaderModifier.FORBIDDEN_HEADERS = [
            'access-control-allow-origin',
            'access-control-allow-credentials',
            'access-control-allow-headers',
            'access-control-allow-methods',
            'access-control-expose-headers',
            'access-control-max-age',
            'access-control-request-headers',
            'access-control-request-method',
            'origin',
            'timing-allow-origin',
            'allow',
            'cross-origin-embedder-policy',
            'cross-origin-opener-policy',
            'cross-origin-resource-policy',
            'content-security-policy',
            'content-security-policy-report-only',
            'expect-ct',
            'feature-policy',
            'origin-isolation',
            'strict-transport-security',
            'upgrade-insecure-requests',
            'x-content-type-options',
            'x-download-options',
            'x-frame-options',
            'x-permitted-cross-domain-policies',
            'x-powered-by',
            'x-xss-protection',
            'public-key-pins',
            'public-key-pins-report-only',
            'sec-websocket-key',
            'sec-websocket-extensions',
            'sec-websocket-accept',
            'sec-websocket-protocol',
            'sec-websocket-version',
            'p3p',
            'sec-fetch-mode',
            'sec-fetch-dest',
            'sec-fetch-site',
            'sec-fetch-user',
            'referrer-policy',
            'content-type',
            'content-length',
            'accept',
            'accept-encoding',
            'host',
            'connection',
            'transfer-encoding',
            'upgrade',
        ];
        /**
         * Request prefix
         */
        RemoveHeaderModifier.REQUEST_PREFIX = 'request:';
        return RemoveHeaderModifier;
    }());

    /**
     * This is a helper class that is used specifically to work with app restrictions.
     *
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#app
     *
     * Examples:
     * ||baddomain.com^$app=org.example.app
     * ||baddomain.com^$app=org.example.app1|org.example.app2
     */
    var AppModifier = /** @class */ (function () {
        /**
         * Parses the `apps` string
         *
         * @param apps - apps string
         *
         * @throws an error if the app string is empty or invalid
         */
        function AppModifier(apps) {
            /**
             * Separator between apps
             */
            this.APPS_SEPARATOR = '|';
            if (!apps) {
                throw new SyntaxError('$app modifier cannot be empty');
            }
            var permittedApps = [];
            var restrictedApps = [];
            var parts = apps.split(this.APPS_SEPARATOR);
            for (var i = 0; i < parts.length; i += 1) {
                var app = parts[i];
                var restricted = false;
                if (app.startsWith('~')) {
                    restricted = true;
                    app = app.substring(1).trim();
                }
                if (app === '') {
                    throw new SyntaxError("Empty app specified in \"".concat(apps, "\""));
                }
                if (restricted) {
                    restrictedApps.push(app);
                }
                else {
                    permittedApps.push(app);
                }
            }
            this.restrictedApps = restrictedApps.length > 0 ? restrictedApps : null;
            this.permittedApps = permittedApps.length > 0 ? permittedApps : null;
        }
        return AppModifier;
    }());

    var isCidr$1 = {exports: {}};

    var cidrRegex = {exports: {}};

    const word = '[a-fA-F\\d:]';
    const b = options => options && options.includeBoundaries ?
    	`(?:(?<=\\s|^)(?=${word})|(?<=${word})(?=\\s|$))` :
    	'';
    const v4$1 = '(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}';
    const v6seg = '[a-fA-F\\d]{1,4}';
    const v6$1 = `
(?:
(?:${v6seg}:){7}(?:${v6seg}|:)|                                    // 1:2:3:4:5:6:7::  1:2:3:4:5:6:7:8
(?:${v6seg}:){6}(?:${v4$1}|:${v6seg}|:)|                             // 1:2:3:4:5:6::    1:2:3:4:5:6::8   1:2:3:4:5:6::8  1:2:3:4:5:6::1.2.3.4
(?:${v6seg}:){5}(?::${v4$1}|(?::${v6seg}){1,2}|:)|                   // 1:2:3:4:5::      1:2:3:4:5::7:8   1:2:3:4:5::8    1:2:3:4:5::7:1.2.3.4
(?:${v6seg}:){4}(?:(?::${v6seg}){0,1}:${v4$1}|(?::${v6seg}){1,3}|:)| // 1:2:3:4::        1:2:3:4::6:7:8   1:2:3:4::8      1:2:3:4::6:7:1.2.3.4
(?:${v6seg}:){3}(?:(?::${v6seg}){0,2}:${v4$1}|(?::${v6seg}){1,4}|:)| // 1:2:3::          1:2:3::5:6:7:8   1:2:3::8        1:2:3::5:6:7:1.2.3.4
(?:${v6seg}:){2}(?:(?::${v6seg}){0,3}:${v4$1}|(?::${v6seg}){1,5}|:)| // 1:2::            1:2::4:5:6:7:8   1:2::8          1:2::4:5:6:7:1.2.3.4
(?:${v6seg}:){1}(?:(?::${v6seg}){0,4}:${v4$1}|(?::${v6seg}){1,6}|:)| // 1::              1::3:4:5:6:7:8   1::8            1::3:4:5:6:7:1.2.3.4
(?::(?:(?::${v6seg}){0,5}:${v4$1}|(?::${v6seg}){1,7}|:))             // ::2:3:4:5:6:7:8  ::2:3:4:5:6:7:8  ::8             ::1.2.3.4
)(?:%[0-9a-zA-Z]{1,})?                                             // %eth0            %1
`.replace(/\s*\/\/.*$/gm, '').replace(/\n/g, '').trim();
    const v46Exact = new RegExp(`(?:^${v4$1}$)|(?:^${v6$1}$)`);
    const v4exact$1 = new RegExp(`^${v4$1}$`);
    const v6exact$1 = new RegExp(`^${v6$1}$`);
    const ip = options => options && options.exact ?
    	v46Exact :
    	new RegExp(`(?:${b(options)}${v4$1}${b(options)})|(?:${b(options)}${v6$1}${b(options)})`, 'g');
    ip.v4 = options => options && options.exact ? v4exact$1 : new RegExp(`${b(options)}${v4$1}${b(options)}`, 'g');
    ip.v6 = options => options && options.exact ? v6exact$1 : new RegExp(`${b(options)}${v6$1}${b(options)}`, 'g');
    var ipRegex$2 = ip;

    const ipRegex$1 = ipRegex$2;
    const defaultOpts = {exact: false};
    const v4str = `${ipRegex$1.v4().source}\\/(3[0-2]|[12]?[0-9])`;
    const v6str = `${ipRegex$1.v6().source}\\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])`;
    const v4exact = new RegExp(`^${v4str}$`);
    const v6exact = new RegExp(`^${v6str}$`);
    const v46exact = new RegExp(`(?:^${v4str}$)|(?:^${v6str}$)`);
    cidrRegex.exports = ({exact} = defaultOpts) => exact ? v46exact : new RegExp(`(?:${v4str})|(?:${v6str})`, "g");
    cidrRegex.exports.v4 = ({exact} = defaultOpts) => exact ? v4exact : new RegExp(v4str, "g");
    cidrRegex.exports.v6 = ({exact} = defaultOpts) => exact ? v6exact : new RegExp(v6str, "g");

    const {v4, v6} = cidrRegex.exports;
    const re4 = v4({exact: true});
    const re6 = v6({exact: true});
    isCidr$1.exports = str => re4.test(str) ? 4 : (re6.test(str) ? 6 : 0);
    isCidr$1.exports.v4 = str => re4.test(str);
    isCidr$1.exports.v6 = str => re6.test(str);
    var isCidr = isCidr$1.exports;

    const ipRegex = ipRegex$2;
    const isIp = string => ipRegex({exact: true}).test(string);
    isIp.v4 = string => ipRegex.v4({exact: true}).test(string);
    isIp.v6 = string => ipRegex.v6({exact: true}).test(string);
    isIp.version = string => isIp(string) ? (isIp.v4(string) ? 4 : 6) : undefined;
    var isIp_1 = isIp;

    var Netmask_1;
    (function() {
      var Netmask, atob, chr, chr0, chrA, chra, ip2long, long2ip;
      long2ip = function(long) {
        var a, b, c, d;
        a = (long & (0xff << 24)) >>> 24;
        b = (long & (0xff << 16)) >>> 16;
        c = (long & (0xff << 8)) >>> 8;
        d = long & 0xff;
        return [a, b, c, d].join('.');
      };
      ip2long = function(ip) {
        var b, c, i, j, n, ref;
        b = [];
        for (i = j = 0; j <= 3; i = ++j) {
          if (ip.length === 0) {
            break;
          }
          if (i > 0) {
            if (ip[0] !== '.') {
              throw new Error('Invalid IP');
            }
            ip = ip.substring(1);
          }
          ref = atob(ip), n = ref[0], c = ref[1];
          ip = ip.substring(c);
          b.push(n);
        }
        if (ip.length !== 0) {
          throw new Error('Invalid IP');
        }
        switch (b.length) {
          case 1:
            if (b[0] > 0xFFFFFFFF) {
              throw new Error('Invalid IP');
            }
            return b[0] >>> 0;
          case 2:
            if (b[0] > 0xFF || b[1] > 0xFFFFFF) {
              throw new Error('Invalid IP');
            }
            return (b[0] << 24 | b[1]) >>> 0;
          case 3:
            if (b[0] > 0xFF || b[1] > 0xFF || b[2] > 0xFFFF) {
              throw new Error('Invalid IP');
            }
            return (b[0] << 24 | b[1] << 16 | b[2]) >>> 0;
          case 4:
            if (b[0] > 0xFF || b[1] > 0xFF || b[2] > 0xFF || b[3] > 0xFF) {
              throw new Error('Invalid IP');
            }
            return (b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]) >>> 0;
          default:
            throw new Error('Invalid IP');
        }
      };
      chr = function(b) {
        return b.charCodeAt(0);
      };
      chr0 = chr('0');
      chra = chr('a');
      chrA = chr('A');
      atob = function(s) {
        var base, dmax, i, n, start;
        n = 0;
        base = 10;
        dmax = '9';
        i = 0;
        if (s.length > 1 && s[i] === '0') {
          if (s[i + 1] === 'x' || s[i + 1] === 'X') {
            i += 2;
            base = 16;
          } else if ('0' <= s[i + 1] && s[i + 1] <= '9') {
            i++;
            base = 8;
            dmax = '7';
          }
        }
        start = i;
        while (i < s.length) {
          if ('0' <= s[i] && s[i] <= dmax) {
            n = (n * base + (chr(s[i]) - chr0)) >>> 0;
          } else if (base === 16) {
            if ('a' <= s[i] && s[i] <= 'f') {
              n = (n * base + (10 + chr(s[i]) - chra)) >>> 0;
            } else if ('A' <= s[i] && s[i] <= 'F') {
              n = (n * base + (10 + chr(s[i]) - chrA)) >>> 0;
            } else {
              break;
            }
          } else {
            break;
          }
          if (n > 0xFFFFFFFF) {
            throw new Error('too large');
          }
          i++;
        }
        if (i === start) {
          throw new Error('empty octet');
        }
        return [n, i];
      };
      Netmask = (function() {
        function Netmask(net, mask) {
          var i, j, ref;
          if (typeof net !== 'string') {
            throw new Error("Missing `net' parameter");
          }
          if (!mask) {
            ref = net.split('/', 2), net = ref[0], mask = ref[1];
          }
          if (!mask) {
            mask = 32;
          }
          if (typeof mask === 'string' && mask.indexOf('.') > -1) {
            try {
              this.maskLong = ip2long(mask);
            } catch (error1) {
              throw new Error("Invalid mask: " + mask);
            }
            for (i = j = 32; j >= 0; i = --j) {
              if (this.maskLong === (0xffffffff << (32 - i)) >>> 0) {
                this.bitmask = i;
                break;
              }
            }
          } else if (mask || mask === 0) {
            this.bitmask = parseInt(mask, 10);
            this.maskLong = 0;
            if (this.bitmask > 0) {
              this.maskLong = (0xffffffff << (32 - this.bitmask)) >>> 0;
            }
          } else {
            throw new Error("Invalid mask: empty");
          }
          try {
            this.netLong = (ip2long(net) & this.maskLong) >>> 0;
          } catch (error1) {
            throw new Error("Invalid net address: " + net);
          }
          if (!(this.bitmask <= 32)) {
            throw new Error("Invalid mask for ip4: " + mask);
          }
          this.size = Math.pow(2, 32 - this.bitmask);
          this.base = long2ip(this.netLong);
          this.mask = long2ip(this.maskLong);
          this.hostmask = long2ip(~this.maskLong);
          this.first = this.bitmask <= 30 ? long2ip(this.netLong + 1) : this.base;
          this.last = this.bitmask <= 30 ? long2ip(this.netLong + this.size - 2) : long2ip(this.netLong + this.size - 1);
          this.broadcast = this.bitmask <= 30 ? long2ip(this.netLong + this.size - 1) : void 0;
        }
        Netmask.prototype.contains = function(ip) {
          if (typeof ip === 'string' && (ip.indexOf('/') > 0 || ip.split('.').length !== 4)) {
            ip = new Netmask(ip);
          }
          if (ip instanceof Netmask) {
            return this.contains(ip.base) && this.contains(ip.broadcast || ip.last);
          } else {
            return (ip2long(ip) & this.maskLong) >>> 0 === (this.netLong & this.maskLong) >>> 0;
          }
        };
        Netmask.prototype.next = function(count) {
          if (count == null) {
            count = 1;
          }
          return new Netmask(long2ip(this.netLong + (this.size * count)), this.mask);
        };
        Netmask.prototype.forEach = function(fn) {
          var index, lastLong, long;
          long = ip2long(this.first);
          lastLong = ip2long(this.last);
          index = 0;
          while (long <= lastLong) {
            fn(long2ip(long), long, index);
            index++;
            long++;
          }
        };
        Netmask.prototype.toString = function() {
          return this.base + "/" + this.bitmask;
        };
        return Netmask;
      })();
      Netmask_1 = Netmask;
    }).call(commonjsGlobal);

    var global$2 = (typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g :
                typeof self !== "undefined" ? self :
                typeof window !== "undefined" ? window : {});

    var lookup$1 = [];
    var revLookup$1 = [];
    var Arr$1 = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
    var inited$1 = false;
    function init$1 () {
      inited$1 = true;
      var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      for (var i = 0, len = code.length; i < len; ++i) {
        lookup$1[i] = code[i];
        revLookup$1[code.charCodeAt(i)] = i;
      }
      revLookup$1['-'.charCodeAt(0)] = 62;
      revLookup$1['_'.charCodeAt(0)] = 63;
    }
    function toByteArray$1 (b64) {
      if (!inited$1) {
        init$1();
      }
      var i, j, l, tmp, placeHolders, arr;
      var len = b64.length;
      if (len % 4 > 0) {
        throw new Error('Invalid string. Length must be a multiple of 4')
      }
      placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0;
      arr = new Arr$1(len * 3 / 4 - placeHolders);
      l = placeHolders > 0 ? len - 4 : len;
      var L = 0;
      for (i = 0, j = 0; i < l; i += 4, j += 3) {
        tmp = (revLookup$1[b64.charCodeAt(i)] << 18) | (revLookup$1[b64.charCodeAt(i + 1)] << 12) | (revLookup$1[b64.charCodeAt(i + 2)] << 6) | revLookup$1[b64.charCodeAt(i + 3)];
        arr[L++] = (tmp >> 16) & 0xFF;
        arr[L++] = (tmp >> 8) & 0xFF;
        arr[L++] = tmp & 0xFF;
      }
      if (placeHolders === 2) {
        tmp = (revLookup$1[b64.charCodeAt(i)] << 2) | (revLookup$1[b64.charCodeAt(i + 1)] >> 4);
        arr[L++] = tmp & 0xFF;
      } else if (placeHolders === 1) {
        tmp = (revLookup$1[b64.charCodeAt(i)] << 10) | (revLookup$1[b64.charCodeAt(i + 1)] << 4) | (revLookup$1[b64.charCodeAt(i + 2)] >> 2);
        arr[L++] = (tmp >> 8) & 0xFF;
        arr[L++] = tmp & 0xFF;
      }
      return arr
    }
    function tripletToBase64$1 (num) {
      return lookup$1[num >> 18 & 0x3F] + lookup$1[num >> 12 & 0x3F] + lookup$1[num >> 6 & 0x3F] + lookup$1[num & 0x3F]
    }
    function encodeChunk$1 (uint8, start, end) {
      var tmp;
      var output = [];
      for (var i = start; i < end; i += 3) {
        tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
        output.push(tripletToBase64$1(tmp));
      }
      return output.join('')
    }
    function fromByteArray$1 (uint8) {
      if (!inited$1) {
        init$1();
      }
      var tmp;
      var len = uint8.length;
      var extraBytes = len % 3;
      var output = '';
      var parts = [];
      var maxChunkLength = 16383;
      for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
        parts.push(encodeChunk$1(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)));
      }
      if (extraBytes === 1) {
        tmp = uint8[len - 1];
        output += lookup$1[tmp >> 2];
        output += lookup$1[(tmp << 4) & 0x3F];
        output += '==';
      } else if (extraBytes === 2) {
        tmp = (uint8[len - 2] << 8) + (uint8[len - 1]);
        output += lookup$1[tmp >> 10];
        output += lookup$1[(tmp >> 4) & 0x3F];
        output += lookup$1[(tmp << 2) & 0x3F];
        output += '=';
      }
      parts.push(output);
      return parts.join('')
    }

    function read$1 (buffer, offset, isLE, mLen, nBytes) {
      var e, m;
      var eLen = nBytes * 8 - mLen - 1;
      var eMax = (1 << eLen) - 1;
      var eBias = eMax >> 1;
      var nBits = -7;
      var i = isLE ? (nBytes - 1) : 0;
      var d = isLE ? -1 : 1;
      var s = buffer[offset + i];
      i += d;
      e = s & ((1 << (-nBits)) - 1);
      s >>= (-nBits);
      nBits += eLen;
      for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
      m = e & ((1 << (-nBits)) - 1);
      e >>= (-nBits);
      nBits += mLen;
      for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
      if (e === 0) {
        e = 1 - eBias;
      } else if (e === eMax) {
        return m ? NaN : ((s ? -1 : 1) * Infinity)
      } else {
        m = m + Math.pow(2, mLen);
        e = e - eBias;
      }
      return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
    }
    function write$1 (buffer, value, offset, isLE, mLen, nBytes) {
      var e, m, c;
      var eLen = nBytes * 8 - mLen - 1;
      var eMax = (1 << eLen) - 1;
      var eBias = eMax >> 1;
      var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
      var i = isLE ? 0 : (nBytes - 1);
      var d = isLE ? 1 : -1;
      var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
      value = Math.abs(value);
      if (isNaN(value) || value === Infinity) {
        m = isNaN(value) ? 1 : 0;
        e = eMax;
      } else {
        e = Math.floor(Math.log(value) / Math.LN2);
        if (value * (c = Math.pow(2, -e)) < 1) {
          e--;
          c *= 2;
        }
        if (e + eBias >= 1) {
          value += rt / c;
        } else {
          value += rt * Math.pow(2, 1 - eBias);
        }
        if (value * c >= 2) {
          e++;
          c /= 2;
        }
        if (e + eBias >= eMax) {
          m = 0;
          e = eMax;
        } else if (e + eBias >= 1) {
          m = (value * c - 1) * Math.pow(2, mLen);
          e = e + eBias;
        } else {
          m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
          e = 0;
        }
      }
      for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
      e = (e << mLen) | m;
      eLen += mLen;
      for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
      buffer[offset + i - d] |= s * 128;
    }

    var toString$1 = {}.toString;
    var isArray$3 = Array.isArray || function (arr) {
      return toString$1.call(arr) == '[object Array]';
    };

    var INSPECT_MAX_BYTES$1 = 50;
    Buffer$1.TYPED_ARRAY_SUPPORT = global$2.TYPED_ARRAY_SUPPORT !== undefined
      ? global$2.TYPED_ARRAY_SUPPORT
      : true;
    function kMaxLength$1 () {
      return Buffer$1.TYPED_ARRAY_SUPPORT
        ? 0x7fffffff
        : 0x3fffffff
    }
    function createBuffer$1 (that, length) {
      if (kMaxLength$1() < length) {
        throw new RangeError('Invalid typed array length')
      }
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        that = new Uint8Array(length);
        that.__proto__ = Buffer$1.prototype;
      } else {
        if (that === null) {
          that = new Buffer$1(length);
        }
        that.length = length;
      }
      return that
    }
    function Buffer$1 (arg, encodingOrOffset, length) {
      if (!Buffer$1.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer$1)) {
        return new Buffer$1(arg, encodingOrOffset, length)
      }
      if (typeof arg === 'number') {
        if (typeof encodingOrOffset === 'string') {
          throw new Error(
            'If encoding is specified then the first argument must be a string'
          )
        }
        return allocUnsafe$1(this, arg)
      }
      return from$1(this, arg, encodingOrOffset, length)
    }
    Buffer$1.poolSize = 8192;
    Buffer$1._augment = function (arr) {
      arr.__proto__ = Buffer$1.prototype;
      return arr
    };
    function from$1 (that, value, encodingOrOffset, length) {
      if (typeof value === 'number') {
        throw new TypeError('"value" argument must not be a number')
      }
      if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
        return fromArrayBuffer$1(that, value, encodingOrOffset, length)
      }
      if (typeof value === 'string') {
        return fromString$1(that, value, encodingOrOffset)
      }
      return fromObject$1(that, value)
    }
    Buffer$1.from = function (value, encodingOrOffset, length) {
      return from$1(null, value, encodingOrOffset, length)
    };
    if (Buffer$1.TYPED_ARRAY_SUPPORT) {
      Buffer$1.prototype.__proto__ = Uint8Array.prototype;
      Buffer$1.__proto__ = Uint8Array;
    }
    function assertSize$1 (size) {
      if (typeof size !== 'number') {
        throw new TypeError('"size" argument must be a number')
      } else if (size < 0) {
        throw new RangeError('"size" argument must not be negative')
      }
    }
    function alloc$1 (that, size, fill, encoding) {
      assertSize$1(size);
      if (size <= 0) {
        return createBuffer$1(that, size)
      }
      if (fill !== undefined) {
        return typeof encoding === 'string'
          ? createBuffer$1(that, size).fill(fill, encoding)
          : createBuffer$1(that, size).fill(fill)
      }
      return createBuffer$1(that, size)
    }
    Buffer$1.alloc = function (size, fill, encoding) {
      return alloc$1(null, size, fill, encoding)
    };
    function allocUnsafe$1 (that, size) {
      assertSize$1(size);
      that = createBuffer$1(that, size < 0 ? 0 : checked$1(size) | 0);
      if (!Buffer$1.TYPED_ARRAY_SUPPORT) {
        for (var i = 0; i < size; ++i) {
          that[i] = 0;
        }
      }
      return that
    }
    Buffer$1.allocUnsafe = function (size) {
      return allocUnsafe$1(null, size)
    };
    Buffer$1.allocUnsafeSlow = function (size) {
      return allocUnsafe$1(null, size)
    };
    function fromString$1 (that, string, encoding) {
      if (typeof encoding !== 'string' || encoding === '') {
        encoding = 'utf8';
      }
      if (!Buffer$1.isEncoding(encoding)) {
        throw new TypeError('"encoding" must be a valid string encoding')
      }
      var length = byteLength$1(string, encoding) | 0;
      that = createBuffer$1(that, length);
      var actual = that.write(string, encoding);
      if (actual !== length) {
        that = that.slice(0, actual);
      }
      return that
    }
    function fromArrayLike$1 (that, array) {
      var length = array.length < 0 ? 0 : checked$1(array.length) | 0;
      that = createBuffer$1(that, length);
      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255;
      }
      return that
    }
    function fromArrayBuffer$1 (that, array, byteOffset, length) {
      array.byteLength;
      if (byteOffset < 0 || array.byteLength < byteOffset) {
        throw new RangeError('\'offset\' is out of bounds')
      }
      if (array.byteLength < byteOffset + (length || 0)) {
        throw new RangeError('\'length\' is out of bounds')
      }
      if (byteOffset === undefined && length === undefined) {
        array = new Uint8Array(array);
      } else if (length === undefined) {
        array = new Uint8Array(array, byteOffset);
      } else {
        array = new Uint8Array(array, byteOffset, length);
      }
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        that = array;
        that.__proto__ = Buffer$1.prototype;
      } else {
        that = fromArrayLike$1(that, array);
      }
      return that
    }
    function fromObject$1 (that, obj) {
      if (internalIsBuffer$1(obj)) {
        var len = checked$1(obj.length) | 0;
        that = createBuffer$1(that, len);
        if (that.length === 0) {
          return that
        }
        obj.copy(that, 0, 0, len);
        return that
      }
      if (obj) {
        if ((typeof ArrayBuffer !== 'undefined' &&
            obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
          if (typeof obj.length !== 'number' || isnan$1(obj.length)) {
            return createBuffer$1(that, 0)
          }
          return fromArrayLike$1(that, obj)
        }
        if (obj.type === 'Buffer' && isArray$3(obj.data)) {
          return fromArrayLike$1(that, obj.data)
        }
      }
      throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
    }
    function checked$1 (length) {
      if (length >= kMaxLength$1()) {
        throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
                             'size: 0x' + kMaxLength$1().toString(16) + ' bytes')
      }
      return length | 0
    }
    Buffer$1.isBuffer = isBuffer$2;
    function internalIsBuffer$1 (b) {
      return !!(b != null && b._isBuffer)
    }
    Buffer$1.compare = function compare (a, b) {
      if (!internalIsBuffer$1(a) || !internalIsBuffer$1(b)) {
        throw new TypeError('Arguments must be Buffers')
      }
      if (a === b) return 0
      var x = a.length;
      var y = b.length;
      for (var i = 0, len = Math.min(x, y); i < len; ++i) {
        if (a[i] !== b[i]) {
          x = a[i];
          y = b[i];
          break
        }
      }
      if (x < y) return -1
      if (y < x) return 1
      return 0
    };
    Buffer$1.isEncoding = function isEncoding (encoding) {
      switch (String(encoding).toLowerCase()) {
        case 'hex':
        case 'utf8':
        case 'utf-8':
        case 'ascii':
        case 'latin1':
        case 'binary':
        case 'base64':
        case 'ucs2':
        case 'ucs-2':
        case 'utf16le':
        case 'utf-16le':
          return true
        default:
          return false
      }
    };
    Buffer$1.concat = function concat (list, length) {
      if (!isArray$3(list)) {
        throw new TypeError('"list" argument must be an Array of Buffers')
      }
      if (list.length === 0) {
        return Buffer$1.alloc(0)
      }
      var i;
      if (length === undefined) {
        length = 0;
        for (i = 0; i < list.length; ++i) {
          length += list[i].length;
        }
      }
      var buffer = Buffer$1.allocUnsafe(length);
      var pos = 0;
      for (i = 0; i < list.length; ++i) {
        var buf = list[i];
        if (!internalIsBuffer$1(buf)) {
          throw new TypeError('"list" argument must be an Array of Buffers')
        }
        buf.copy(buffer, pos);
        pos += buf.length;
      }
      return buffer
    };
    function byteLength$1 (string, encoding) {
      if (internalIsBuffer$1(string)) {
        return string.length
      }
      if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
          (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
        return string.byteLength
      }
      if (typeof string !== 'string') {
        string = '' + string;
      }
      var len = string.length;
      if (len === 0) return 0
      var loweredCase = false;
      for (;;) {
        switch (encoding) {
          case 'ascii':
          case 'latin1':
          case 'binary':
            return len
          case 'utf8':
          case 'utf-8':
          case undefined:
            return utf8ToBytes$1(string).length
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return len * 2
          case 'hex':
            return len >>> 1
          case 'base64':
            return base64ToBytes$1(string).length
          default:
            if (loweredCase) return utf8ToBytes$1(string).length
            encoding = ('' + encoding).toLowerCase();
            loweredCase = true;
        }
      }
    }
    Buffer$1.byteLength = byteLength$1;
    function slowToString$1 (encoding, start, end) {
      var loweredCase = false;
      if (start === undefined || start < 0) {
        start = 0;
      }
      if (start > this.length) {
        return ''
      }
      if (end === undefined || end > this.length) {
        end = this.length;
      }
      if (end <= 0) {
        return ''
      }
      end >>>= 0;
      start >>>= 0;
      if (end <= start) {
        return ''
      }
      if (!encoding) encoding = 'utf8';
      while (true) {
        switch (encoding) {
          case 'hex':
            return hexSlice$1(this, start, end)
          case 'utf8':
          case 'utf-8':
            return utf8Slice$1(this, start, end)
          case 'ascii':
            return asciiSlice$1(this, start, end)
          case 'latin1':
          case 'binary':
            return latin1Slice$1(this, start, end)
          case 'base64':
            return base64Slice$1(this, start, end)
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return utf16leSlice$1(this, start, end)
          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = (encoding + '').toLowerCase();
            loweredCase = true;
        }
      }
    }
    Buffer$1.prototype._isBuffer = true;
    function swap$1 (b, n, m) {
      var i = b[n];
      b[n] = b[m];
      b[m] = i;
    }
    Buffer$1.prototype.swap16 = function swap16 () {
      var len = this.length;
      if (len % 2 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 16-bits')
      }
      for (var i = 0; i < len; i += 2) {
        swap$1(this, i, i + 1);
      }
      return this
    };
    Buffer$1.prototype.swap32 = function swap32 () {
      var len = this.length;
      if (len % 4 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 32-bits')
      }
      for (var i = 0; i < len; i += 4) {
        swap$1(this, i, i + 3);
        swap$1(this, i + 1, i + 2);
      }
      return this
    };
    Buffer$1.prototype.swap64 = function swap64 () {
      var len = this.length;
      if (len % 8 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 64-bits')
      }
      for (var i = 0; i < len; i += 8) {
        swap$1(this, i, i + 7);
        swap$1(this, i + 1, i + 6);
        swap$1(this, i + 2, i + 5);
        swap$1(this, i + 3, i + 4);
      }
      return this
    };
    Buffer$1.prototype.toString = function toString () {
      var length = this.length | 0;
      if (length === 0) return ''
      if (arguments.length === 0) return utf8Slice$1(this, 0, length)
      return slowToString$1.apply(this, arguments)
    };
    Buffer$1.prototype.equals = function equals (b) {
      if (!internalIsBuffer$1(b)) throw new TypeError('Argument must be a Buffer')
      if (this === b) return true
      return Buffer$1.compare(this, b) === 0
    };
    Buffer$1.prototype.inspect = function inspect () {
      var str = '';
      var max = INSPECT_MAX_BYTES$1;
      if (this.length > 0) {
        str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
        if (this.length > max) str += ' ... ';
      }
      return '<Buffer ' + str + '>'
    };
    Buffer$1.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
      if (!internalIsBuffer$1(target)) {
        throw new TypeError('Argument must be a Buffer')
      }
      if (start === undefined) {
        start = 0;
      }
      if (end === undefined) {
        end = target ? target.length : 0;
      }
      if (thisStart === undefined) {
        thisStart = 0;
      }
      if (thisEnd === undefined) {
        thisEnd = this.length;
      }
      if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
        throw new RangeError('out of range index')
      }
      if (thisStart >= thisEnd && start >= end) {
        return 0
      }
      if (thisStart >= thisEnd) {
        return -1
      }
      if (start >= end) {
        return 1
      }
      start >>>= 0;
      end >>>= 0;
      thisStart >>>= 0;
      thisEnd >>>= 0;
      if (this === target) return 0
      var x = thisEnd - thisStart;
      var y = end - start;
      var len = Math.min(x, y);
      var thisCopy = this.slice(thisStart, thisEnd);
      var targetCopy = target.slice(start, end);
      for (var i = 0; i < len; ++i) {
        if (thisCopy[i] !== targetCopy[i]) {
          x = thisCopy[i];
          y = targetCopy[i];
          break
        }
      }
      if (x < y) return -1
      if (y < x) return 1
      return 0
    };
    function bidirectionalIndexOf$1 (buffer, val, byteOffset, encoding, dir) {
      if (buffer.length === 0) return -1
      if (typeof byteOffset === 'string') {
        encoding = byteOffset;
        byteOffset = 0;
      } else if (byteOffset > 0x7fffffff) {
        byteOffset = 0x7fffffff;
      } else if (byteOffset < -0x80000000) {
        byteOffset = -0x80000000;
      }
      byteOffset = +byteOffset;
      if (isNaN(byteOffset)) {
        byteOffset = dir ? 0 : (buffer.length - 1);
      }
      if (byteOffset < 0) byteOffset = buffer.length + byteOffset;
      if (byteOffset >= buffer.length) {
        if (dir) return -1
        else byteOffset = buffer.length - 1;
      } else if (byteOffset < 0) {
        if (dir) byteOffset = 0;
        else return -1
      }
      if (typeof val === 'string') {
        val = Buffer$1.from(val, encoding);
      }
      if (internalIsBuffer$1(val)) {
        if (val.length === 0) {
          return -1
        }
        return arrayIndexOf$1(buffer, val, byteOffset, encoding, dir)
      } else if (typeof val === 'number') {
        val = val & 0xFF;
        if (Buffer$1.TYPED_ARRAY_SUPPORT &&
            typeof Uint8Array.prototype.indexOf === 'function') {
          if (dir) {
            return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
          } else {
            return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
          }
        }
        return arrayIndexOf$1(buffer, [ val ], byteOffset, encoding, dir)
      }
      throw new TypeError('val must be string, number or Buffer')
    }
    function arrayIndexOf$1 (arr, val, byteOffset, encoding, dir) {
      var indexSize = 1;
      var arrLength = arr.length;
      var valLength = val.length;
      if (encoding !== undefined) {
        encoding = String(encoding).toLowerCase();
        if (encoding === 'ucs2' || encoding === 'ucs-2' ||
            encoding === 'utf16le' || encoding === 'utf-16le') {
          if (arr.length < 2 || val.length < 2) {
            return -1
          }
          indexSize = 2;
          arrLength /= 2;
          valLength /= 2;
          byteOffset /= 2;
        }
      }
      function read (buf, i) {
        if (indexSize === 1) {
          return buf[i]
        } else {
          return buf.readUInt16BE(i * indexSize)
        }
      }
      var i;
      if (dir) {
        var foundIndex = -1;
        for (i = byteOffset; i < arrLength; i++) {
          if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
            if (foundIndex === -1) foundIndex = i;
            if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
          } else {
            if (foundIndex !== -1) i -= i - foundIndex;
            foundIndex = -1;
          }
        }
      } else {
        if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;
        for (i = byteOffset; i >= 0; i--) {
          var found = true;
          for (var j = 0; j < valLength; j++) {
            if (read(arr, i + j) !== read(val, j)) {
              found = false;
              break
            }
          }
          if (found) return i
        }
      }
      return -1
    }
    Buffer$1.prototype.includes = function includes (val, byteOffset, encoding) {
      return this.indexOf(val, byteOffset, encoding) !== -1
    };
    Buffer$1.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf$1(this, val, byteOffset, encoding, true)
    };
    Buffer$1.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf$1(this, val, byteOffset, encoding, false)
    };
    function hexWrite$1 (buf, string, offset, length) {
      offset = Number(offset) || 0;
      var remaining = buf.length - offset;
      if (!length) {
        length = remaining;
      } else {
        length = Number(length);
        if (length > remaining) {
          length = remaining;
        }
      }
      var strLen = string.length;
      if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
      if (length > strLen / 2) {
        length = strLen / 2;
      }
      for (var i = 0; i < length; ++i) {
        var parsed = parseInt(string.substr(i * 2, 2), 16);
        if (isNaN(parsed)) return i
        buf[offset + i] = parsed;
      }
      return i
    }
    function utf8Write$1 (buf, string, offset, length) {
      return blitBuffer$1(utf8ToBytes$1(string, buf.length - offset), buf, offset, length)
    }
    function asciiWrite$1 (buf, string, offset, length) {
      return blitBuffer$1(asciiToBytes$1(string), buf, offset, length)
    }
    function latin1Write$1 (buf, string, offset, length) {
      return asciiWrite$1(buf, string, offset, length)
    }
    function base64Write$1 (buf, string, offset, length) {
      return blitBuffer$1(base64ToBytes$1(string), buf, offset, length)
    }
    function ucs2Write$1 (buf, string, offset, length) {
      return blitBuffer$1(utf16leToBytes$1(string, buf.length - offset), buf, offset, length)
    }
    Buffer$1.prototype.write = function write (string, offset, length, encoding) {
      if (offset === undefined) {
        encoding = 'utf8';
        length = this.length;
        offset = 0;
      } else if (length === undefined && typeof offset === 'string') {
        encoding = offset;
        length = this.length;
        offset = 0;
      } else if (isFinite(offset)) {
        offset = offset | 0;
        if (isFinite(length)) {
          length = length | 0;
          if (encoding === undefined) encoding = 'utf8';
        } else {
          encoding = length;
          length = undefined;
        }
      } else {
        throw new Error(
          'Buffer.write(string, encoding, offset[, length]) is no longer supported'
        )
      }
      var remaining = this.length - offset;
      if (length === undefined || length > remaining) length = remaining;
      if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
        throw new RangeError('Attempt to write outside buffer bounds')
      }
      if (!encoding) encoding = 'utf8';
      var loweredCase = false;
      for (;;) {
        switch (encoding) {
          case 'hex':
            return hexWrite$1(this, string, offset, length)
          case 'utf8':
          case 'utf-8':
            return utf8Write$1(this, string, offset, length)
          case 'ascii':
            return asciiWrite$1(this, string, offset, length)
          case 'latin1':
          case 'binary':
            return latin1Write$1(this, string, offset, length)
          case 'base64':
            return base64Write$1(this, string, offset, length)
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return ucs2Write$1(this, string, offset, length)
          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = ('' + encoding).toLowerCase();
            loweredCase = true;
        }
      }
    };
    Buffer$1.prototype.toJSON = function toJSON () {
      return {
        type: 'Buffer',
        data: Array.prototype.slice.call(this._arr || this, 0)
      }
    };
    function base64Slice$1 (buf, start, end) {
      if (start === 0 && end === buf.length) {
        return fromByteArray$1(buf)
      } else {
        return fromByteArray$1(buf.slice(start, end))
      }
    }
    function utf8Slice$1 (buf, start, end) {
      end = Math.min(buf.length, end);
      var res = [];
      var i = start;
      while (i < end) {
        var firstByte = buf[i];
        var codePoint = null;
        var bytesPerSequence = (firstByte > 0xEF) ? 4
          : (firstByte > 0xDF) ? 3
          : (firstByte > 0xBF) ? 2
          : 1;
        if (i + bytesPerSequence <= end) {
          var secondByte, thirdByte, fourthByte, tempCodePoint;
          switch (bytesPerSequence) {
            case 1:
              if (firstByte < 0x80) {
                codePoint = firstByte;
              }
              break
            case 2:
              secondByte = buf[i + 1];
              if ((secondByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F);
                if (tempCodePoint > 0x7F) {
                  codePoint = tempCodePoint;
                }
              }
              break
            case 3:
              secondByte = buf[i + 1];
              thirdByte = buf[i + 2];
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F);
                if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
                  codePoint = tempCodePoint;
                }
              }
              break
            case 4:
              secondByte = buf[i + 1];
              thirdByte = buf[i + 2];
              fourthByte = buf[i + 3];
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F);
                if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
                  codePoint = tempCodePoint;
                }
              }
          }
        }
        if (codePoint === null) {
          codePoint = 0xFFFD;
          bytesPerSequence = 1;
        } else if (codePoint > 0xFFFF) {
          codePoint -= 0x10000;
          res.push(codePoint >>> 10 & 0x3FF | 0xD800);
          codePoint = 0xDC00 | codePoint & 0x3FF;
        }
        res.push(codePoint);
        i += bytesPerSequence;
      }
      return decodeCodePointsArray$1(res)
    }
    var MAX_ARGUMENTS_LENGTH$1 = 0x1000;
    function decodeCodePointsArray$1 (codePoints) {
      var len = codePoints.length;
      if (len <= MAX_ARGUMENTS_LENGTH$1) {
        return String.fromCharCode.apply(String, codePoints)
      }
      var res = '';
      var i = 0;
      while (i < len) {
        res += String.fromCharCode.apply(
          String,
          codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH$1)
        );
      }
      return res
    }
    function asciiSlice$1 (buf, start, end) {
      var ret = '';
      end = Math.min(buf.length, end);
      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i] & 0x7F);
      }
      return ret
    }
    function latin1Slice$1 (buf, start, end) {
      var ret = '';
      end = Math.min(buf.length, end);
      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i]);
      }
      return ret
    }
    function hexSlice$1 (buf, start, end) {
      var len = buf.length;
      if (!start || start < 0) start = 0;
      if (!end || end < 0 || end > len) end = len;
      var out = '';
      for (var i = start; i < end; ++i) {
        out += toHex$1(buf[i]);
      }
      return out
    }
    function utf16leSlice$1 (buf, start, end) {
      var bytes = buf.slice(start, end);
      var res = '';
      for (var i = 0; i < bytes.length; i += 2) {
        res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);
      }
      return res
    }
    Buffer$1.prototype.slice = function slice (start, end) {
      var len = this.length;
      start = ~~start;
      end = end === undefined ? len : ~~end;
      if (start < 0) {
        start += len;
        if (start < 0) start = 0;
      } else if (start > len) {
        start = len;
      }
      if (end < 0) {
        end += len;
        if (end < 0) end = 0;
      } else if (end > len) {
        end = len;
      }
      if (end < start) end = start;
      var newBuf;
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        newBuf = this.subarray(start, end);
        newBuf.__proto__ = Buffer$1.prototype;
      } else {
        var sliceLen = end - start;
        newBuf = new Buffer$1(sliceLen, undefined);
        for (var i = 0; i < sliceLen; ++i) {
          newBuf[i] = this[i + start];
        }
      }
      return newBuf
    };
    function checkOffset$1 (offset, ext, length) {
      if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
      if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
    }
    Buffer$1.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset$1(offset, byteLength, this.length);
      var val = this[offset];
      var mul = 1;
      var i = 0;
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul;
      }
      return val
    };
    Buffer$1.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        checkOffset$1(offset, byteLength, this.length);
      }
      var val = this[offset + --byteLength];
      var mul = 1;
      while (byteLength > 0 && (mul *= 0x100)) {
        val += this[offset + --byteLength] * mul;
      }
      return val
    };
    Buffer$1.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 1, this.length);
      return this[offset]
    };
    Buffer$1.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 2, this.length);
      return this[offset] | (this[offset + 1] << 8)
    };
    Buffer$1.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 2, this.length);
      return (this[offset] << 8) | this[offset + 1]
    };
    Buffer$1.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return ((this[offset]) |
          (this[offset + 1] << 8) |
          (this[offset + 2] << 16)) +
          (this[offset + 3] * 0x1000000)
    };
    Buffer$1.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return (this[offset] * 0x1000000) +
        ((this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        this[offset + 3])
    };
    Buffer$1.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset$1(offset, byteLength, this.length);
      var val = this[offset];
      var mul = 1;
      var i = 0;
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul;
      }
      mul *= 0x80;
      if (val >= mul) val -= Math.pow(2, 8 * byteLength);
      return val
    };
    Buffer$1.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset$1(offset, byteLength, this.length);
      var i = byteLength;
      var mul = 1;
      var val = this[offset + --i];
      while (i > 0 && (mul *= 0x100)) {
        val += this[offset + --i] * mul;
      }
      mul *= 0x80;
      if (val >= mul) val -= Math.pow(2, 8 * byteLength);
      return val
    };
    Buffer$1.prototype.readInt8 = function readInt8 (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 1, this.length);
      if (!(this[offset] & 0x80)) return (this[offset])
      return ((0xff - this[offset] + 1) * -1)
    };
    Buffer$1.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 2, this.length);
      var val = this[offset] | (this[offset + 1] << 8);
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    };
    Buffer$1.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 2, this.length);
      var val = this[offset + 1] | (this[offset] << 8);
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    };
    Buffer$1.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return (this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16) |
        (this[offset + 3] << 24)
    };
    Buffer$1.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return (this[offset] << 24) |
        (this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        (this[offset + 3])
    };
    Buffer$1.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return read$1(this, offset, true, 23, 4)
    };
    Buffer$1.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 4, this.length);
      return read$1(this, offset, false, 23, 4)
    };
    Buffer$1.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 8, this.length);
      return read$1(this, offset, true, 52, 8)
    };
    Buffer$1.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
      if (!noAssert) checkOffset$1(offset, 8, this.length);
      return read$1(this, offset, false, 52, 8)
    };
    function checkInt$1 (buf, value, offset, ext, max, min) {
      if (!internalIsBuffer$1(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
      if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
    }
    Buffer$1.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1;
        checkInt$1(this, value, offset, byteLength, maxBytes, 0);
      }
      var mul = 1;
      var i = 0;
      this[offset] = value & 0xFF;
      while (++i < byteLength && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF;
      }
      return offset + byteLength
    };
    Buffer$1.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1;
        checkInt$1(this, value, offset, byteLength, maxBytes, 0);
      }
      var i = byteLength - 1;
      var mul = 1;
      this[offset + i] = value & 0xFF;
      while (--i >= 0 && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF;
      }
      return offset + byteLength
    };
    Buffer$1.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 1, 0xff, 0);
      if (!Buffer$1.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
      this[offset] = (value & 0xff);
      return offset + 1
    };
    function objectWriteUInt16$1 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffff + value + 1;
      for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
        buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
          (littleEndian ? i : 1 - i) * 8;
      }
    }
    Buffer$1.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 2, 0xffff, 0);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
      } else {
        objectWriteUInt16$1(this, value, offset, true);
      }
      return offset + 2
    };
    Buffer$1.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 2, 0xffff, 0);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8);
        this[offset + 1] = (value & 0xff);
      } else {
        objectWriteUInt16$1(this, value, offset, false);
      }
      return offset + 2
    };
    function objectWriteUInt32$1 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffffffff + value + 1;
      for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
        buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff;
      }
    }
    Buffer$1.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 4, 0xffffffff, 0);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset + 3] = (value >>> 24);
        this[offset + 2] = (value >>> 16);
        this[offset + 1] = (value >>> 8);
        this[offset] = (value & 0xff);
      } else {
        objectWriteUInt32$1(this, value, offset, true);
      }
      return offset + 4
    };
    Buffer$1.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 4, 0xffffffff, 0);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24);
        this[offset + 1] = (value >>> 16);
        this[offset + 2] = (value >>> 8);
        this[offset + 3] = (value & 0xff);
      } else {
        objectWriteUInt32$1(this, value, offset, false);
      }
      return offset + 4
    };
    Buffer$1.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1);
        checkInt$1(this, value, offset, byteLength, limit - 1, -limit);
      }
      var i = 0;
      var mul = 1;
      var sub = 0;
      this[offset] = value & 0xFF;
      while (++i < byteLength && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
          sub = 1;
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
      }
      return offset + byteLength
    };
    Buffer$1.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1);
        checkInt$1(this, value, offset, byteLength, limit - 1, -limit);
      }
      var i = byteLength - 1;
      var mul = 1;
      var sub = 0;
      this[offset + i] = value & 0xFF;
      while (--i >= 0 && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
          sub = 1;
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
      }
      return offset + byteLength
    };
    Buffer$1.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 1, 0x7f, -0x80);
      if (!Buffer$1.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
      if (value < 0) value = 0xff + value + 1;
      this[offset] = (value & 0xff);
      return offset + 1
    };
    Buffer$1.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 2, 0x7fff, -0x8000);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
      } else {
        objectWriteUInt16$1(this, value, offset, true);
      }
      return offset + 2
    };
    Buffer$1.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 2, 0x7fff, -0x8000);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8);
        this[offset + 1] = (value & 0xff);
      } else {
        objectWriteUInt16$1(this, value, offset, false);
      }
      return offset + 2
    };
    Buffer$1.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 4, 0x7fffffff, -0x80000000);
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
        this[offset + 2] = (value >>> 16);
        this[offset + 3] = (value >>> 24);
      } else {
        objectWriteUInt32$1(this, value, offset, true);
      }
      return offset + 4
    };
    Buffer$1.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt$1(this, value, offset, 4, 0x7fffffff, -0x80000000);
      if (value < 0) value = 0xffffffff + value + 1;
      if (Buffer$1.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24);
        this[offset + 1] = (value >>> 16);
        this[offset + 2] = (value >>> 8);
        this[offset + 3] = (value & 0xff);
      } else {
        objectWriteUInt32$1(this, value, offset, false);
      }
      return offset + 4
    };
    function checkIEEE754$1 (buf, value, offset, ext, max, min) {
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
      if (offset < 0) throw new RangeError('Index out of range')
    }
    function writeFloat$1 (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754$1(buf, value, offset, 4);
      }
      write$1(buf, value, offset, littleEndian, 23, 4);
      return offset + 4
    }
    Buffer$1.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
      return writeFloat$1(this, value, offset, true, noAssert)
    };
    Buffer$1.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
      return writeFloat$1(this, value, offset, false, noAssert)
    };
    function writeDouble$1 (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754$1(buf, value, offset, 8);
      }
      write$1(buf, value, offset, littleEndian, 52, 8);
      return offset + 8
    }
    Buffer$1.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
      return writeDouble$1(this, value, offset, true, noAssert)
    };
    Buffer$1.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
      return writeDouble$1(this, value, offset, false, noAssert)
    };
    Buffer$1.prototype.copy = function copy (target, targetStart, start, end) {
      if (!start) start = 0;
      if (!end && end !== 0) end = this.length;
      if (targetStart >= target.length) targetStart = target.length;
      if (!targetStart) targetStart = 0;
      if (end > 0 && end < start) end = start;
      if (end === start) return 0
      if (target.length === 0 || this.length === 0) return 0
      if (targetStart < 0) {
        throw new RangeError('targetStart out of bounds')
      }
      if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
      if (end < 0) throw new RangeError('sourceEnd out of bounds')
      if (end > this.length) end = this.length;
      if (target.length - targetStart < end - start) {
        end = target.length - targetStart + start;
      }
      var len = end - start;
      var i;
      if (this === target && start < targetStart && targetStart < end) {
        for (i = len - 1; i >= 0; --i) {
          target[i + targetStart] = this[i + start];
        }
      } else if (len < 1000 || !Buffer$1.TYPED_ARRAY_SUPPORT) {
        for (i = 0; i < len; ++i) {
          target[i + targetStart] = this[i + start];
        }
      } else {
        Uint8Array.prototype.set.call(
          target,
          this.subarray(start, start + len),
          targetStart
        );
      }
      return len
    };
    Buffer$1.prototype.fill = function fill (val, start, end, encoding) {
      if (typeof val === 'string') {
        if (typeof start === 'string') {
          encoding = start;
          start = 0;
          end = this.length;
        } else if (typeof end === 'string') {
          encoding = end;
          end = this.length;
        }
        if (val.length === 1) {
          var code = val.charCodeAt(0);
          if (code < 256) {
            val = code;
          }
        }
        if (encoding !== undefined && typeof encoding !== 'string') {
          throw new TypeError('encoding must be a string')
        }
        if (typeof encoding === 'string' && !Buffer$1.isEncoding(encoding)) {
          throw new TypeError('Unknown encoding: ' + encoding)
        }
      } else if (typeof val === 'number') {
        val = val & 255;
      }
      if (start < 0 || this.length < start || this.length < end) {
        throw new RangeError('Out of range index')
      }
      if (end <= start) {
        return this
      }
      start = start >>> 0;
      end = end === undefined ? this.length : end >>> 0;
      if (!val) val = 0;
      var i;
      if (typeof val === 'number') {
        for (i = start; i < end; ++i) {
          this[i] = val;
        }
      } else {
        var bytes = internalIsBuffer$1(val)
          ? val
          : utf8ToBytes$1(new Buffer$1(val, encoding).toString());
        var len = bytes.length;
        for (i = 0; i < end - start; ++i) {
          this[i + start] = bytes[i % len];
        }
      }
      return this
    };
    var INVALID_BASE64_RE$1 = /[^+\/0-9A-Za-z-_]/g;
    function base64clean$1 (str) {
      str = stringtrim$1(str).replace(INVALID_BASE64_RE$1, '');
      if (str.length < 2) return ''
      while (str.length % 4 !== 0) {
        str = str + '=';
      }
      return str
    }
    function stringtrim$1 (str) {
      if (str.trim) return str.trim()
      return str.replace(/^\s+|\s+$/g, '')
    }
    function toHex$1 (n) {
      if (n < 16) return '0' + n.toString(16)
      return n.toString(16)
    }
    function utf8ToBytes$1 (string, units) {
      units = units || Infinity;
      var codePoint;
      var length = string.length;
      var leadSurrogate = null;
      var bytes = [];
      for (var i = 0; i < length; ++i) {
        codePoint = string.charCodeAt(i);
        if (codePoint > 0xD7FF && codePoint < 0xE000) {
          if (!leadSurrogate) {
            if (codePoint > 0xDBFF) {
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
              continue
            } else if (i + 1 === length) {
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
              continue
            }
            leadSurrogate = codePoint;
            continue
          }
          if (codePoint < 0xDC00) {
            if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
            leadSurrogate = codePoint;
            continue
          }
          codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;
        } else if (leadSurrogate) {
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
        }
        leadSurrogate = null;
        if (codePoint < 0x80) {
          if ((units -= 1) < 0) break
          bytes.push(codePoint);
        } else if (codePoint < 0x800) {
          if ((units -= 2) < 0) break
          bytes.push(
            codePoint >> 0x6 | 0xC0,
            codePoint & 0x3F | 0x80
          );
        } else if (codePoint < 0x10000) {
          if ((units -= 3) < 0) break
          bytes.push(
            codePoint >> 0xC | 0xE0,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          );
        } else if (codePoint < 0x110000) {
          if ((units -= 4) < 0) break
          bytes.push(
            codePoint >> 0x12 | 0xF0,
            codePoint >> 0xC & 0x3F | 0x80,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          );
        } else {
          throw new Error('Invalid code point')
        }
      }
      return bytes
    }
    function asciiToBytes$1 (str) {
      var byteArray = [];
      for (var i = 0; i < str.length; ++i) {
        byteArray.push(str.charCodeAt(i) & 0xFF);
      }
      return byteArray
    }
    function utf16leToBytes$1 (str, units) {
      var c, hi, lo;
      var byteArray = [];
      for (var i = 0; i < str.length; ++i) {
        if ((units -= 2) < 0) break
        c = str.charCodeAt(i);
        hi = c >> 8;
        lo = c % 256;
        byteArray.push(lo);
        byteArray.push(hi);
      }
      return byteArray
    }
    function base64ToBytes$1 (str) {
      return toByteArray$1(base64clean$1(str))
    }
    function blitBuffer$1 (src, dst, offset, length) {
      for (var i = 0; i < length; ++i) {
        if ((i + offset >= dst.length) || (i >= src.length)) break
        dst[i + offset] = src[i];
      }
      return i
    }
    function isnan$1 (val) {
      return val !== val
    }
    function isBuffer$2(obj) {
      return obj != null && (!!obj._isBuffer || isFastBuffer$1(obj) || isSlowBuffer$1(obj))
    }
    function isFastBuffer$1 (obj) {
      return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
    }
    function isSlowBuffer$1 (obj) {
      return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer$1(obj.slice(0, 0))
    }

    function defaultSetTimout$1() {
        throw new Error('setTimeout has not been defined');
    }
    function defaultClearTimeout$1 () {
        throw new Error('clearTimeout has not been defined');
    }
    var cachedSetTimeout$1 = defaultSetTimout$1;
    var cachedClearTimeout$1 = defaultClearTimeout$1;
    if (typeof global$2.setTimeout === 'function') {
        cachedSetTimeout$1 = setTimeout;
    }
    if (typeof global$2.clearTimeout === 'function') {
        cachedClearTimeout$1 = clearTimeout;
    }
    function runTimeout$1(fun) {
        if (cachedSetTimeout$1 === setTimeout) {
            return setTimeout(fun, 0);
        }
        if ((cachedSetTimeout$1 === defaultSetTimout$1 || !cachedSetTimeout$1) && setTimeout) {
            cachedSetTimeout$1 = setTimeout;
            return setTimeout(fun, 0);
        }
        try {
            return cachedSetTimeout$1(fun, 0);
        } catch(e){
            try {
                return cachedSetTimeout$1.call(null, fun, 0);
            } catch(e){
                return cachedSetTimeout$1.call(this, fun, 0);
            }
        }
    }
    function runClearTimeout$1(marker) {
        if (cachedClearTimeout$1 === clearTimeout) {
            return clearTimeout(marker);
        }
        if ((cachedClearTimeout$1 === defaultClearTimeout$1 || !cachedClearTimeout$1) && clearTimeout) {
            cachedClearTimeout$1 = clearTimeout;
            return clearTimeout(marker);
        }
        try {
            return cachedClearTimeout$1(marker);
        } catch (e){
            try {
                return cachedClearTimeout$1.call(null, marker);
            } catch (e){
                return cachedClearTimeout$1.call(this, marker);
            }
        }
    }
    var queue$1 = [];
    var draining$1 = false;
    var currentQueue$1;
    var queueIndex$1 = -1;
    function cleanUpNextTick$1() {
        if (!draining$1 || !currentQueue$1) {
            return;
        }
        draining$1 = false;
        if (currentQueue$1.length) {
            queue$1 = currentQueue$1.concat(queue$1);
        } else {
            queueIndex$1 = -1;
        }
        if (queue$1.length) {
            drainQueue$1();
        }
    }
    function drainQueue$1() {
        if (draining$1) {
            return;
        }
        var timeout = runTimeout$1(cleanUpNextTick$1);
        draining$1 = true;
        var len = queue$1.length;
        while(len) {
            currentQueue$1 = queue$1;
            queue$1 = [];
            while (++queueIndex$1 < len) {
                if (currentQueue$1) {
                    currentQueue$1[queueIndex$1].run();
                }
            }
            queueIndex$1 = -1;
            len = queue$1.length;
        }
        currentQueue$1 = null;
        draining$1 = false;
        runClearTimeout$1(timeout);
    }
    function nextTick$1(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$1.push(new Item$1(fun, args));
        if (queue$1.length === 1 && !draining$1) {
            runTimeout$1(drainQueue$1);
        }
    }
    function Item$1(fun, array) {
        this.fun = fun;
        this.array = array;
    }
    Item$1.prototype.run = function () {
        this.fun.apply(null, this.array);
    };
    var title$1 = 'browser';
    var platform$1 = 'browser';
    var browser$3 = true;
    var env$1 = {};
    var argv$1 = [];
    var version$2 = '';
    var versions$1 = {};
    var release$1 = {};
    var config$1 = {};
    function noop$2() {}
    var on$1 = noop$2;
    var addListener$1 = noop$2;
    var once$1 = noop$2;
    var off$1 = noop$2;
    var removeListener$1 = noop$2;
    var removeAllListeners$1 = noop$2;
    var emit$1 = noop$2;
    function binding$1(name) {
        throw new Error('process.binding is not supported');
    }
    function cwd$1 () { return '/' }
    function chdir$1 (dir) {
        throw new Error('process.chdir is not supported');
    }function umask$1() { return 0; }
    var performance$1 = global$2.performance || {};
    var performanceNow$1 =
      performance$1.now        ||
      performance$1.mozNow     ||
      performance$1.msNow      ||
      performance$1.oNow       ||
      performance$1.webkitNow  ||
      function(){ return (new Date()).getTime() };
    function hrtime$1(previousTimestamp){
      var clocktime = performanceNow$1.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$1 = new Date();
    function uptime$1() {
      var currentTime = new Date();
      var dif = currentTime - startTime$1;
      return dif / 1000;
    }
    var process$1 = {
      nextTick: nextTick$1,
      title: title$1,
      browser: browser$3,
      env: env$1,
      argv: argv$1,
      version: version$2,
      versions: versions$1,
      on: on$1,
      addListener: addListener$1,
      once: once$1,
      off: off$1,
      removeListener: removeListener$1,
      removeAllListeners: removeAllListeners$1,
      emit: emit$1,
      binding: binding$1,
      cwd: cwd$1,
      chdir: chdir$1,
      umask: umask$1,
      hrtime: hrtime$1,
      platform: platform$1,
      release: release$1,
      config: config$1,
      uptime: uptime$1
    };

    var global$1 = (typeof global$1 !== "undefined" ? global$1 :
      typeof self !== "undefined" ? self :
      typeof window !== "undefined" ? window : {});

    var lookup = [];
    var revLookup = [];
    var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
    var inited = false;
    function init () {
      inited = true;
      var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
      for (var i = 0, len = code.length; i < len; ++i) {
        lookup[i] = code[i];
        revLookup[code.charCodeAt(i)] = i;
      }

      revLookup['-'.charCodeAt(0)] = 62;
      revLookup['_'.charCodeAt(0)] = 63;
    }

    function toByteArray (b64) {
      if (!inited) {
        init();
      }
      var i, j, l, tmp, placeHolders, arr;
      var len = b64.length;

      if (len % 4 > 0) {
        throw new Error('Invalid string. Length must be a multiple of 4')
      }

      // the number of equal signs (place holders)
      // if there are two placeholders, than the two characters before it
      // represent one byte
      // if there is only one, then the three characters before it represent 2 bytes
      // this is just a cheap hack to not do indexOf twice
      placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0;

      // base64 is 4/3 + up to two characters of the original data
      arr = new Arr(len * 3 / 4 - placeHolders);

      // if there are placeholders, only get up to the last complete 4 chars
      l = placeHolders > 0 ? len - 4 : len;

      var L = 0;

      for (i = 0, j = 0; i < l; i += 4, j += 3) {
        tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)];
        arr[L++] = (tmp >> 16) & 0xFF;
        arr[L++] = (tmp >> 8) & 0xFF;
        arr[L++] = tmp & 0xFF;
      }

      if (placeHolders === 2) {
        tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4);
        arr[L++] = tmp & 0xFF;
      } else if (placeHolders === 1) {
        tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2);
        arr[L++] = (tmp >> 8) & 0xFF;
        arr[L++] = tmp & 0xFF;
      }

      return arr
    }

    function tripletToBase64 (num) {
      return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
    }

    function encodeChunk (uint8, start, end) {
      var tmp;
      var output = [];
      for (var i = start; i < end; i += 3) {
        tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);
        output.push(tripletToBase64(tmp));
      }
      return output.join('')
    }

    function fromByteArray (uint8) {
      if (!inited) {
        init();
      }
      var tmp;
      var len = uint8.length;
      var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
      var output = '';
      var parts = [];
      var maxChunkLength = 16383; // must be multiple of 3

      // go through the array every three bytes, we'll deal with trailing stuff later
      for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
        parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)));
      }

      // pad the end with zeros, but make sure to not forget the extra bytes
      if (extraBytes === 1) {
        tmp = uint8[len - 1];
        output += lookup[tmp >> 2];
        output += lookup[(tmp << 4) & 0x3F];
        output += '==';
      } else if (extraBytes === 2) {
        tmp = (uint8[len - 2] << 8) + (uint8[len - 1]);
        output += lookup[tmp >> 10];
        output += lookup[(tmp >> 4) & 0x3F];
        output += lookup[(tmp << 2) & 0x3F];
        output += '=';
      }

      parts.push(output);

      return parts.join('')
    }

    function read (buffer, offset, isLE, mLen, nBytes) {
      var e, m;
      var eLen = nBytes * 8 - mLen - 1;
      var eMax = (1 << eLen) - 1;
      var eBias = eMax >> 1;
      var nBits = -7;
      var i = isLE ? (nBytes - 1) : 0;
      var d = isLE ? -1 : 1;
      var s = buffer[offset + i];

      i += d;

      e = s & ((1 << (-nBits)) - 1);
      s >>= (-nBits);
      nBits += eLen;
      for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}

      m = e & ((1 << (-nBits)) - 1);
      e >>= (-nBits);
      nBits += mLen;
      for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}

      if (e === 0) {
        e = 1 - eBias;
      } else if (e === eMax) {
        return m ? NaN : ((s ? -1 : 1) * Infinity)
      } else {
        m = m + Math.pow(2, mLen);
        e = e - eBias;
      }
      return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
    }

    function write (buffer, value, offset, isLE, mLen, nBytes) {
      var e, m, c;
      var eLen = nBytes * 8 - mLen - 1;
      var eMax = (1 << eLen) - 1;
      var eBias = eMax >> 1;
      var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
      var i = isLE ? 0 : (nBytes - 1);
      var d = isLE ? 1 : -1;
      var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;

      value = Math.abs(value);

      if (isNaN(value) || value === Infinity) {
        m = isNaN(value) ? 1 : 0;
        e = eMax;
      } else {
        e = Math.floor(Math.log(value) / Math.LN2);
        if (value * (c = Math.pow(2, -e)) < 1) {
          e--;
          c *= 2;
        }
        if (e + eBias >= 1) {
          value += rt / c;
        } else {
          value += rt * Math.pow(2, 1 - eBias);
        }
        if (value * c >= 2) {
          e++;
          c /= 2;
        }

        if (e + eBias >= eMax) {
          m = 0;
          e = eMax;
        } else if (e + eBias >= 1) {
          m = (value * c - 1) * Math.pow(2, mLen);
          e = e + eBias;
        } else {
          m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
          e = 0;
        }
      }

      for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}

      e = (e << mLen) | m;
      eLen += mLen;
      for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}

      buffer[offset + i - d] |= s * 128;
    }

    var toString = {}.toString;

    var isArray$2 = Array.isArray || function (arr) {
      return toString.call(arr) == '[object Array]';
    };

    /*!
     * The buffer module from node.js, for the browser.
     *
     * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
     * @license  MIT
     */

    var INSPECT_MAX_BYTES = 50;

    /**
     * If `Buffer.TYPED_ARRAY_SUPPORT`:
     *   === true    Use Uint8Array implementation (fastest)
     *   === false   Use Object implementation (most compatible, even IE6)
     *
     * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
     * Opera 11.6+, iOS 4.2+.
     *
     * Due to various browser bugs, sometimes the Object implementation will be used even
     * when the browser supports typed arrays.
     *
     * Note:
     *
     *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
     *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
     *
     *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
     *
     *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
     *     incorrect length in some situations.

     * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
     * get the Object implementation, which is slower but behaves correctly.
     */
    Buffer.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined
      ? global$1.TYPED_ARRAY_SUPPORT
      : true;

    function kMaxLength () {
      return Buffer.TYPED_ARRAY_SUPPORT
        ? 0x7fffffff
        : 0x3fffffff
    }

    function createBuffer (that, length) {
      if (kMaxLength() < length) {
        throw new RangeError('Invalid typed array length')
      }
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        // Return an augmented `Uint8Array` instance, for best performance
        that = new Uint8Array(length);
        that.__proto__ = Buffer.prototype;
      } else {
        // Fallback: Return an object instance of the Buffer class
        if (that === null) {
          that = new Buffer(length);
        }
        that.length = length;
      }

      return that
    }

    /**
     * The Buffer constructor returns instances of `Uint8Array` that have their
     * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
     * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
     * and the `Uint8Array` methods. Square bracket notation works as expected -- it
     * returns a single octet.
     *
     * The `Uint8Array` prototype remains unmodified.
     */

    function Buffer (arg, encodingOrOffset, length) {
      if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
        return new Buffer(arg, encodingOrOffset, length)
      }

      // Common case.
      if (typeof arg === 'number') {
        if (typeof encodingOrOffset === 'string') {
          throw new Error(
            'If encoding is specified then the first argument must be a string'
          )
        }
        return allocUnsafe(this, arg)
      }
      return from(this, arg, encodingOrOffset, length)
    }

    Buffer.poolSize = 8192; // not used by this implementation

    // TODO: Legacy, not needed anymore. Remove in next major version.
    Buffer._augment = function (arr) {
      arr.__proto__ = Buffer.prototype;
      return arr
    };

    function from (that, value, encodingOrOffset, length) {
      if (typeof value === 'number') {
        throw new TypeError('"value" argument must not be a number')
      }

      if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
        return fromArrayBuffer(that, value, encodingOrOffset, length)
      }

      if (typeof value === 'string') {
        return fromString(that, value, encodingOrOffset)
      }

      return fromObject(that, value)
    }

    /**
     * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
     * if value is a number.
     * Buffer.from(str[, encoding])
     * Buffer.from(array)
     * Buffer.from(buffer)
     * Buffer.from(arrayBuffer[, byteOffset[, length]])
     **/
    Buffer.from = function (value, encodingOrOffset, length) {
      return from(null, value, encodingOrOffset, length)
    };

    if (Buffer.TYPED_ARRAY_SUPPORT) {
      Buffer.prototype.__proto__ = Uint8Array.prototype;
      Buffer.__proto__ = Uint8Array;
    }

    function assertSize (size) {
      if (typeof size !== 'number') {
        throw new TypeError('"size" argument must be a number')
      } else if (size < 0) {
        throw new RangeError('"size" argument must not be negative')
      }
    }

    function alloc (that, size, fill, encoding) {
      assertSize(size);
      if (size <= 0) {
        return createBuffer(that, size)
      }
      if (fill !== undefined) {
        // Only pay attention to encoding if it's a string. This
        // prevents accidentally sending in a number that would
        // be interpretted as a start offset.
        return typeof encoding === 'string'
          ? createBuffer(that, size).fill(fill, encoding)
          : createBuffer(that, size).fill(fill)
      }
      return createBuffer(that, size)
    }

    /**
     * Creates a new filled Buffer instance.
     * alloc(size[, fill[, encoding]])
     **/
    Buffer.alloc = function (size, fill, encoding) {
      return alloc(null, size, fill, encoding)
    };

    function allocUnsafe (that, size) {
      assertSize(size);
      that = createBuffer(that, size < 0 ? 0 : checked(size) | 0);
      if (!Buffer.TYPED_ARRAY_SUPPORT) {
        for (var i = 0; i < size; ++i) {
          that[i] = 0;
        }
      }
      return that
    }

    /**
     * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
     * */
    Buffer.allocUnsafe = function (size) {
      return allocUnsafe(null, size)
    };
    /**
     * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
     */
    Buffer.allocUnsafeSlow = function (size) {
      return allocUnsafe(null, size)
    };

    function fromString (that, string, encoding) {
      if (typeof encoding !== 'string' || encoding === '') {
        encoding = 'utf8';
      }

      if (!Buffer.isEncoding(encoding)) {
        throw new TypeError('"encoding" must be a valid string encoding')
      }

      var length = byteLength(string, encoding) | 0;
      that = createBuffer(that, length);

      var actual = that.write(string, encoding);

      if (actual !== length) {
        // Writing a hex string, for example, that contains invalid characters will
        // cause everything after the first invalid character to be ignored. (e.g.
        // 'abxxcd' will be treated as 'ab')
        that = that.slice(0, actual);
      }

      return that
    }

    function fromArrayLike (that, array) {
      var length = array.length < 0 ? 0 : checked(array.length) | 0;
      that = createBuffer(that, length);
      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255;
      }
      return that
    }

    function fromArrayBuffer (that, array, byteOffset, length) {
      array.byteLength; // this throws if `array` is not a valid ArrayBuffer

      if (byteOffset < 0 || array.byteLength < byteOffset) {
        throw new RangeError('\'offset\' is out of bounds')
      }

      if (array.byteLength < byteOffset + (length || 0)) {
        throw new RangeError('\'length\' is out of bounds')
      }

      if (byteOffset === undefined && length === undefined) {
        array = new Uint8Array(array);
      } else if (length === undefined) {
        array = new Uint8Array(array, byteOffset);
      } else {
        array = new Uint8Array(array, byteOffset, length);
      }

      if (Buffer.TYPED_ARRAY_SUPPORT) {
        // Return an augmented `Uint8Array` instance, for best performance
        that = array;
        that.__proto__ = Buffer.prototype;
      } else {
        // Fallback: Return an object instance of the Buffer class
        that = fromArrayLike(that, array);
      }
      return that
    }

    function fromObject (that, obj) {
      if (internalIsBuffer(obj)) {
        var len = checked(obj.length) | 0;
        that = createBuffer(that, len);

        if (that.length === 0) {
          return that
        }

        obj.copy(that, 0, 0, len);
        return that
      }

      if (obj) {
        if ((typeof ArrayBuffer !== 'undefined' &&
            obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
          if (typeof obj.length !== 'number' || isnan(obj.length)) {
            return createBuffer(that, 0)
          }
          return fromArrayLike(that, obj)
        }

        if (obj.type === 'Buffer' && isArray$2(obj.data)) {
          return fromArrayLike(that, obj.data)
        }
      }

      throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
    }

    function checked (length) {
      // Note: cannot use `length < kMaxLength()` here because that fails when
      // length is NaN (which is otherwise coerced to zero.)
      if (length >= kMaxLength()) {
        throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
                             'size: 0x' + kMaxLength().toString(16) + ' bytes')
      }
      return length | 0
    }
    Buffer.isBuffer = isBuffer$1;
    function internalIsBuffer (b) {
      return !!(b != null && b._isBuffer)
    }

    Buffer.compare = function compare (a, b) {
      if (!internalIsBuffer(a) || !internalIsBuffer(b)) {
        throw new TypeError('Arguments must be Buffers')
      }

      if (a === b) return 0

      var x = a.length;
      var y = b.length;

      for (var i = 0, len = Math.min(x, y); i < len; ++i) {
        if (a[i] !== b[i]) {
          x = a[i];
          y = b[i];
          break
        }
      }

      if (x < y) return -1
      if (y < x) return 1
      return 0
    };

    Buffer.isEncoding = function isEncoding (encoding) {
      switch (String(encoding).toLowerCase()) {
        case 'hex':
        case 'utf8':
        case 'utf-8':
        case 'ascii':
        case 'latin1':
        case 'binary':
        case 'base64':
        case 'ucs2':
        case 'ucs-2':
        case 'utf16le':
        case 'utf-16le':
          return true
        default:
          return false
      }
    };

    Buffer.concat = function concat (list, length) {
      if (!isArray$2(list)) {
        throw new TypeError('"list" argument must be an Array of Buffers')
      }

      if (list.length === 0) {
        return Buffer.alloc(0)
      }

      var i;
      if (length === undefined) {
        length = 0;
        for (i = 0; i < list.length; ++i) {
          length += list[i].length;
        }
      }

      var buffer = Buffer.allocUnsafe(length);
      var pos = 0;
      for (i = 0; i < list.length; ++i) {
        var buf = list[i];
        if (!internalIsBuffer(buf)) {
          throw new TypeError('"list" argument must be an Array of Buffers')
        }
        buf.copy(buffer, pos);
        pos += buf.length;
      }
      return buffer
    };

    function byteLength (string, encoding) {
      if (internalIsBuffer(string)) {
        return string.length
      }
      if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
          (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
        return string.byteLength
      }
      if (typeof string !== 'string') {
        string = '' + string;
      }

      var len = string.length;
      if (len === 0) return 0

      // Use a for loop to avoid recursion
      var loweredCase = false;
      for (;;) {
        switch (encoding) {
          case 'ascii':
          case 'latin1':
          case 'binary':
            return len
          case 'utf8':
          case 'utf-8':
          case undefined:
            return utf8ToBytes(string).length
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return len * 2
          case 'hex':
            return len >>> 1
          case 'base64':
            return base64ToBytes(string).length
          default:
            if (loweredCase) return utf8ToBytes(string).length // assume utf8
            encoding = ('' + encoding).toLowerCase();
            loweredCase = true;
        }
      }
    }
    Buffer.byteLength = byteLength;

    function slowToString (encoding, start, end) {
      var loweredCase = false;

      // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
      // property of a typed array.

      // This behaves neither like String nor Uint8Array in that we set start/end
      // to their upper/lower bounds if the value passed is out of range.
      // undefined is handled specially as per ECMA-262 6th Edition,
      // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
      if (start === undefined || start < 0) {
        start = 0;
      }
      // Return early if start > this.length. Done here to prevent potential uint32
      // coercion fail below.
      if (start > this.length) {
        return ''
      }

      if (end === undefined || end > this.length) {
        end = this.length;
      }

      if (end <= 0) {
        return ''
      }

      // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
      end >>>= 0;
      start >>>= 0;

      if (end <= start) {
        return ''
      }

      if (!encoding) encoding = 'utf8';

      while (true) {
        switch (encoding) {
          case 'hex':
            return hexSlice(this, start, end)

          case 'utf8':
          case 'utf-8':
            return utf8Slice(this, start, end)

          case 'ascii':
            return asciiSlice(this, start, end)

          case 'latin1':
          case 'binary':
            return latin1Slice(this, start, end)

          case 'base64':
            return base64Slice(this, start, end)

          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return utf16leSlice(this, start, end)

          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = (encoding + '').toLowerCase();
            loweredCase = true;
        }
      }
    }

    // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
    // Buffer instances.
    Buffer.prototype._isBuffer = true;

    function swap (b, n, m) {
      var i = b[n];
      b[n] = b[m];
      b[m] = i;
    }

    Buffer.prototype.swap16 = function swap16 () {
      var len = this.length;
      if (len % 2 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 16-bits')
      }
      for (var i = 0; i < len; i += 2) {
        swap(this, i, i + 1);
      }
      return this
    };

    Buffer.prototype.swap32 = function swap32 () {
      var len = this.length;
      if (len % 4 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 32-bits')
      }
      for (var i = 0; i < len; i += 4) {
        swap(this, i, i + 3);
        swap(this, i + 1, i + 2);
      }
      return this
    };

    Buffer.prototype.swap64 = function swap64 () {
      var len = this.length;
      if (len % 8 !== 0) {
        throw new RangeError('Buffer size must be a multiple of 64-bits')
      }
      for (var i = 0; i < len; i += 8) {
        swap(this, i, i + 7);
        swap(this, i + 1, i + 6);
        swap(this, i + 2, i + 5);
        swap(this, i + 3, i + 4);
      }
      return this
    };

    Buffer.prototype.toString = function toString () {
      var length = this.length | 0;
      if (length === 0) return ''
      if (arguments.length === 0) return utf8Slice(this, 0, length)
      return slowToString.apply(this, arguments)
    };

    Buffer.prototype.equals = function equals (b) {
      if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer')
      if (this === b) return true
      return Buffer.compare(this, b) === 0
    };

    Buffer.prototype.inspect = function inspect () {
      var str = '';
      var max = INSPECT_MAX_BYTES;
      if (this.length > 0) {
        str = this.toString('hex', 0, max).match(/.{2}/g).join(' ');
        if (this.length > max) str += ' ... ';
      }
      return '<Buffer ' + str + '>'
    };

    Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
      if (!internalIsBuffer(target)) {
        throw new TypeError('Argument must be a Buffer')
      }

      if (start === undefined) {
        start = 0;
      }
      if (end === undefined) {
        end = target ? target.length : 0;
      }
      if (thisStart === undefined) {
        thisStart = 0;
      }
      if (thisEnd === undefined) {
        thisEnd = this.length;
      }

      if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
        throw new RangeError('out of range index')
      }

      if (thisStart >= thisEnd && start >= end) {
        return 0
      }
      if (thisStart >= thisEnd) {
        return -1
      }
      if (start >= end) {
        return 1
      }

      start >>>= 0;
      end >>>= 0;
      thisStart >>>= 0;
      thisEnd >>>= 0;

      if (this === target) return 0

      var x = thisEnd - thisStart;
      var y = end - start;
      var len = Math.min(x, y);

      var thisCopy = this.slice(thisStart, thisEnd);
      var targetCopy = target.slice(start, end);

      for (var i = 0; i < len; ++i) {
        if (thisCopy[i] !== targetCopy[i]) {
          x = thisCopy[i];
          y = targetCopy[i];
          break
        }
      }

      if (x < y) return -1
      if (y < x) return 1
      return 0
    };

    // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
    // OR the last index of `val` in `buffer` at offset <= `byteOffset`.
    //
    // Arguments:
    // - buffer - a Buffer to search
    // - val - a string, Buffer, or number
    // - byteOffset - an index into `buffer`; will be clamped to an int32
    // - encoding - an optional encoding, relevant is val is a string
    // - dir - true for indexOf, false for lastIndexOf
    function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
      // Empty buffer means no match
      if (buffer.length === 0) return -1

      // Normalize byteOffset
      if (typeof byteOffset === 'string') {
        encoding = byteOffset;
        byteOffset = 0;
      } else if (byteOffset > 0x7fffffff) {
        byteOffset = 0x7fffffff;
      } else if (byteOffset < -0x80000000) {
        byteOffset = -0x80000000;
      }
      byteOffset = +byteOffset;  // Coerce to Number.
      if (isNaN(byteOffset)) {
        // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
        byteOffset = dir ? 0 : (buffer.length - 1);
      }

      // Normalize byteOffset: negative offsets start from the end of the buffer
      if (byteOffset < 0) byteOffset = buffer.length + byteOffset;
      if (byteOffset >= buffer.length) {
        if (dir) return -1
        else byteOffset = buffer.length - 1;
      } else if (byteOffset < 0) {
        if (dir) byteOffset = 0;
        else return -1
      }

      // Normalize val
      if (typeof val === 'string') {
        val = Buffer.from(val, encoding);
      }

      // Finally, search either indexOf (if dir is true) or lastIndexOf
      if (internalIsBuffer(val)) {
        // Special case: looking for empty string/buffer always fails
        if (val.length === 0) {
          return -1
        }
        return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
      } else if (typeof val === 'number') {
        val = val & 0xFF; // Search for a byte value [0-255]
        if (Buffer.TYPED_ARRAY_SUPPORT &&
            typeof Uint8Array.prototype.indexOf === 'function') {
          if (dir) {
            return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
          } else {
            return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
          }
        }
        return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
      }

      throw new TypeError('val must be string, number or Buffer')
    }

    function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
      var indexSize = 1;
      var arrLength = arr.length;
      var valLength = val.length;

      if (encoding !== undefined) {
        encoding = String(encoding).toLowerCase();
        if (encoding === 'ucs2' || encoding === 'ucs-2' ||
            encoding === 'utf16le' || encoding === 'utf-16le') {
          if (arr.length < 2 || val.length < 2) {
            return -1
          }
          indexSize = 2;
          arrLength /= 2;
          valLength /= 2;
          byteOffset /= 2;
        }
      }

      function read (buf, i) {
        if (indexSize === 1) {
          return buf[i]
        } else {
          return buf.readUInt16BE(i * indexSize)
        }
      }

      var i;
      if (dir) {
        var foundIndex = -1;
        for (i = byteOffset; i < arrLength; i++) {
          if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
            if (foundIndex === -1) foundIndex = i;
            if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
          } else {
            if (foundIndex !== -1) i -= i - foundIndex;
            foundIndex = -1;
          }
        }
      } else {
        if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength;
        for (i = byteOffset; i >= 0; i--) {
          var found = true;
          for (var j = 0; j < valLength; j++) {
            if (read(arr, i + j) !== read(val, j)) {
              found = false;
              break
            }
          }
          if (found) return i
        }
      }

      return -1
    }

    Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
      return this.indexOf(val, byteOffset, encoding) !== -1
    };

    Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
    };

    Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
      return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
    };

    function hexWrite (buf, string, offset, length) {
      offset = Number(offset) || 0;
      var remaining = buf.length - offset;
      if (!length) {
        length = remaining;
      } else {
        length = Number(length);
        if (length > remaining) {
          length = remaining;
        }
      }

      // must be an even number of digits
      var strLen = string.length;
      if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')

      if (length > strLen / 2) {
        length = strLen / 2;
      }
      for (var i = 0; i < length; ++i) {
        var parsed = parseInt(string.substr(i * 2, 2), 16);
        if (isNaN(parsed)) return i
        buf[offset + i] = parsed;
      }
      return i
    }

    function utf8Write (buf, string, offset, length) {
      return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
    }

    function asciiWrite (buf, string, offset, length) {
      return blitBuffer(asciiToBytes(string), buf, offset, length)
    }

    function latin1Write (buf, string, offset, length) {
      return asciiWrite(buf, string, offset, length)
    }

    function base64Write (buf, string, offset, length) {
      return blitBuffer(base64ToBytes(string), buf, offset, length)
    }

    function ucs2Write (buf, string, offset, length) {
      return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
    }

    Buffer.prototype.write = function write (string, offset, length, encoding) {
      // Buffer#write(string)
      if (offset === undefined) {
        encoding = 'utf8';
        length = this.length;
        offset = 0;
      // Buffer#write(string, encoding)
      } else if (length === undefined && typeof offset === 'string') {
        encoding = offset;
        length = this.length;
        offset = 0;
      // Buffer#write(string, offset[, length][, encoding])
      } else if (isFinite(offset)) {
        offset = offset | 0;
        if (isFinite(length)) {
          length = length | 0;
          if (encoding === undefined) encoding = 'utf8';
        } else {
          encoding = length;
          length = undefined;
        }
      // legacy write(string, encoding, offset, length) - remove in v0.13
      } else {
        throw new Error(
          'Buffer.write(string, encoding, offset[, length]) is no longer supported'
        )
      }

      var remaining = this.length - offset;
      if (length === undefined || length > remaining) length = remaining;

      if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
        throw new RangeError('Attempt to write outside buffer bounds')
      }

      if (!encoding) encoding = 'utf8';

      var loweredCase = false;
      for (;;) {
        switch (encoding) {
          case 'hex':
            return hexWrite(this, string, offset, length)

          case 'utf8':
          case 'utf-8':
            return utf8Write(this, string, offset, length)

          case 'ascii':
            return asciiWrite(this, string, offset, length)

          case 'latin1':
          case 'binary':
            return latin1Write(this, string, offset, length)

          case 'base64':
            // Warning: maxLength not taken into account in base64Write
            return base64Write(this, string, offset, length)

          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return ucs2Write(this, string, offset, length)

          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = ('' + encoding).toLowerCase();
            loweredCase = true;
        }
      }
    };

    Buffer.prototype.toJSON = function toJSON () {
      return {
        type: 'Buffer',
        data: Array.prototype.slice.call(this._arr || this, 0)
      }
    };

    function base64Slice (buf, start, end) {
      if (start === 0 && end === buf.length) {
        return fromByteArray(buf)
      } else {
        return fromByteArray(buf.slice(start, end))
      }
    }

    function utf8Slice (buf, start, end) {
      end = Math.min(buf.length, end);
      var res = [];

      var i = start;
      while (i < end) {
        var firstByte = buf[i];
        var codePoint = null;
        var bytesPerSequence = (firstByte > 0xEF) ? 4
          : (firstByte > 0xDF) ? 3
          : (firstByte > 0xBF) ? 2
          : 1;

        if (i + bytesPerSequence <= end) {
          var secondByte, thirdByte, fourthByte, tempCodePoint;

          switch (bytesPerSequence) {
            case 1:
              if (firstByte < 0x80) {
                codePoint = firstByte;
              }
              break
            case 2:
              secondByte = buf[i + 1];
              if ((secondByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F);
                if (tempCodePoint > 0x7F) {
                  codePoint = tempCodePoint;
                }
              }
              break
            case 3:
              secondByte = buf[i + 1];
              thirdByte = buf[i + 2];
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F);
                if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
                  codePoint = tempCodePoint;
                }
              }
              break
            case 4:
              secondByte = buf[i + 1];
              thirdByte = buf[i + 2];
              fourthByte = buf[i + 3];
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F);
                if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
                  codePoint = tempCodePoint;
                }
              }
          }
        }

        if (codePoint === null) {
          // we did not generate a valid codePoint so insert a
          // replacement char (U+FFFD) and advance only 1 byte
          codePoint = 0xFFFD;
          bytesPerSequence = 1;
        } else if (codePoint > 0xFFFF) {
          // encode to utf16 (surrogate pair dance)
          codePoint -= 0x10000;
          res.push(codePoint >>> 10 & 0x3FF | 0xD800);
          codePoint = 0xDC00 | codePoint & 0x3FF;
        }

        res.push(codePoint);
        i += bytesPerSequence;
      }

      return decodeCodePointsArray(res)
    }

    // Based on http://stackoverflow.com/a/22747272/680742, the browser with
    // the lowest limit is Chrome, with 0x10000 args.
    // We go 1 magnitude less, for safety
    var MAX_ARGUMENTS_LENGTH = 0x1000;

    function decodeCodePointsArray (codePoints) {
      var len = codePoints.length;
      if (len <= MAX_ARGUMENTS_LENGTH) {
        return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
      }

      // Decode in chunks to avoid "call stack size exceeded".
      var res = '';
      var i = 0;
      while (i < len) {
        res += String.fromCharCode.apply(
          String,
          codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
        );
      }
      return res
    }

    function asciiSlice (buf, start, end) {
      var ret = '';
      end = Math.min(buf.length, end);

      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i] & 0x7F);
      }
      return ret
    }

    function latin1Slice (buf, start, end) {
      var ret = '';
      end = Math.min(buf.length, end);

      for (var i = start; i < end; ++i) {
        ret += String.fromCharCode(buf[i]);
      }
      return ret
    }

    function hexSlice (buf, start, end) {
      var len = buf.length;

      if (!start || start < 0) start = 0;
      if (!end || end < 0 || end > len) end = len;

      var out = '';
      for (var i = start; i < end; ++i) {
        out += toHex(buf[i]);
      }
      return out
    }

    function utf16leSlice (buf, start, end) {
      var bytes = buf.slice(start, end);
      var res = '';
      for (var i = 0; i < bytes.length; i += 2) {
        res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256);
      }
      return res
    }

    Buffer.prototype.slice = function slice (start, end) {
      var len = this.length;
      start = ~~start;
      end = end === undefined ? len : ~~end;

      if (start < 0) {
        start += len;
        if (start < 0) start = 0;
      } else if (start > len) {
        start = len;
      }

      if (end < 0) {
        end += len;
        if (end < 0) end = 0;
      } else if (end > len) {
        end = len;
      }

      if (end < start) end = start;

      var newBuf;
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        newBuf = this.subarray(start, end);
        newBuf.__proto__ = Buffer.prototype;
      } else {
        var sliceLen = end - start;
        newBuf = new Buffer(sliceLen, undefined);
        for (var i = 0; i < sliceLen; ++i) {
          newBuf[i] = this[i + start];
        }
      }

      return newBuf
    };

    /*
     * Need to make sure that buffer isn't trying to write out of bounds.
     */
    function checkOffset (offset, ext, length) {
      if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
      if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
    }

    Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset(offset, byteLength, this.length);

      var val = this[offset];
      var mul = 1;
      var i = 0;
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul;
      }

      return val
    };

    Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        checkOffset(offset, byteLength, this.length);
      }

      var val = this[offset + --byteLength];
      var mul = 1;
      while (byteLength > 0 && (mul *= 0x100)) {
        val += this[offset + --byteLength] * mul;
      }

      return val
    };

    Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 1, this.length);
      return this[offset]
    };

    Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length);
      return this[offset] | (this[offset + 1] << 8)
    };

    Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length);
      return (this[offset] << 8) | this[offset + 1]
    };

    Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);

      return ((this[offset]) |
          (this[offset + 1] << 8) |
          (this[offset + 2] << 16)) +
          (this[offset + 3] * 0x1000000)
    };

    Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);

      return (this[offset] * 0x1000000) +
        ((this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        this[offset + 3])
    };

    Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset(offset, byteLength, this.length);

      var val = this[offset];
      var mul = 1;
      var i = 0;
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul;
      }
      mul *= 0x80;

      if (val >= mul) val -= Math.pow(2, 8 * byteLength);

      return val
    };

    Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) checkOffset(offset, byteLength, this.length);

      var i = byteLength;
      var mul = 1;
      var val = this[offset + --i];
      while (i > 0 && (mul *= 0x100)) {
        val += this[offset + --i] * mul;
      }
      mul *= 0x80;

      if (val >= mul) val -= Math.pow(2, 8 * byteLength);

      return val
    };

    Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 1, this.length);
      if (!(this[offset] & 0x80)) return (this[offset])
      return ((0xff - this[offset] + 1) * -1)
    };

    Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length);
      var val = this[offset] | (this[offset + 1] << 8);
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    };

    Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length);
      var val = this[offset + 1] | (this[offset] << 8);
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    };

    Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);

      return (this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16) |
        (this[offset + 3] << 24)
    };

    Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);

      return (this[offset] << 24) |
        (this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        (this[offset + 3])
    };

    Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);
      return read(this, offset, true, 23, 4)
    };

    Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length);
      return read(this, offset, false, 23, 4)
    };

    Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 8, this.length);
      return read(this, offset, true, 52, 8)
    };

    Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 8, this.length);
      return read(this, offset, false, 52, 8)
    };

    function checkInt (buf, value, offset, ext, max, min) {
      if (!internalIsBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
      if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
    }

    Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1;
        checkInt(this, value, offset, byteLength, maxBytes, 0);
      }

      var mul = 1;
      var i = 0;
      this[offset] = value & 0xFF;
      while (++i < byteLength && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF;
      }

      return offset + byteLength
    };

    Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      byteLength = byteLength | 0;
      if (!noAssert) {
        var maxBytes = Math.pow(2, 8 * byteLength) - 1;
        checkInt(this, value, offset, byteLength, maxBytes, 0);
      }

      var i = byteLength - 1;
      var mul = 1;
      this[offset + i] = value & 0xFF;
      while (--i >= 0 && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF;
      }

      return offset + byteLength
    };

    Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0);
      if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
      this[offset] = (value & 0xff);
      return offset + 1
    };

    function objectWriteUInt16 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffff + value + 1;
      for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
        buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
          (littleEndian ? i : 1 - i) * 8;
      }
    }

    Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
      } else {
        objectWriteUInt16(this, value, offset, true);
      }
      return offset + 2
    };

    Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8);
        this[offset + 1] = (value & 0xff);
      } else {
        objectWriteUInt16(this, value, offset, false);
      }
      return offset + 2
    };

    function objectWriteUInt32 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffffffff + value + 1;
      for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
        buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff;
      }
    }

    Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset + 3] = (value >>> 24);
        this[offset + 2] = (value >>> 16);
        this[offset + 1] = (value >>> 8);
        this[offset] = (value & 0xff);
      } else {
        objectWriteUInt32(this, value, offset, true);
      }
      return offset + 4
    };

    Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24);
        this[offset + 1] = (value >>> 16);
        this[offset + 2] = (value >>> 8);
        this[offset + 3] = (value & 0xff);
      } else {
        objectWriteUInt32(this, value, offset, false);
      }
      return offset + 4
    };

    Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1);

        checkInt(this, value, offset, byteLength, limit - 1, -limit);
      }

      var i = 0;
      var mul = 1;
      var sub = 0;
      this[offset] = value & 0xFF;
      while (++i < byteLength && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
          sub = 1;
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
      }

      return offset + byteLength
    };

    Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1);

        checkInt(this, value, offset, byteLength, limit - 1, -limit);
      }

      var i = byteLength - 1;
      var mul = 1;
      var sub = 0;
      this[offset + i] = value & 0xFF;
      while (--i >= 0 && (mul *= 0x100)) {
        if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
          sub = 1;
        }
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF;
      }

      return offset + byteLength
    };

    Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80);
      if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value);
      if (value < 0) value = 0xff + value + 1;
      this[offset] = (value & 0xff);
      return offset + 1
    };

    Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
      } else {
        objectWriteUInt16(this, value, offset, true);
      }
      return offset + 2
    };

    Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8);
        this[offset + 1] = (value & 0xff);
      } else {
        objectWriteUInt16(this, value, offset, false);
      }
      return offset + 2
    };

    Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff);
        this[offset + 1] = (value >>> 8);
        this[offset + 2] = (value >>> 16);
        this[offset + 3] = (value >>> 24);
      } else {
        objectWriteUInt32(this, value, offset, true);
      }
      return offset + 4
    };

    Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
      value = +value;
      offset = offset | 0;
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000);
      if (value < 0) value = 0xffffffff + value + 1;
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24);
        this[offset + 1] = (value >>> 16);
        this[offset + 2] = (value >>> 8);
        this[offset + 3] = (value & 0xff);
      } else {
        objectWriteUInt32(this, value, offset, false);
      }
      return offset + 4
    };

    function checkIEEE754 (buf, value, offset, ext, max, min) {
      if (offset + ext > buf.length) throw new RangeError('Index out of range')
      if (offset < 0) throw new RangeError('Index out of range')
    }

    function writeFloat (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 4);
      }
      write(buf, value, offset, littleEndian, 23, 4);
      return offset + 4
    }

    Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
      return writeFloat(this, value, offset, true, noAssert)
    };

    Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
      return writeFloat(this, value, offset, false, noAssert)
    };

    function writeDouble (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 8);
      }
      write(buf, value, offset, littleEndian, 52, 8);
      return offset + 8
    }

    Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
      return writeDouble(this, value, offset, true, noAssert)
    };

    Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
      return writeDouble(this, value, offset, false, noAssert)
    };

    // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
    Buffer.prototype.copy = function copy (target, targetStart, start, end) {
      if (!start) start = 0;
      if (!end && end !== 0) end = this.length;
      if (targetStart >= target.length) targetStart = target.length;
      if (!targetStart) targetStart = 0;
      if (end > 0 && end < start) end = start;

      // Copy 0 bytes; we're done
      if (end === start) return 0
      if (target.length === 0 || this.length === 0) return 0

      // Fatal error conditions
      if (targetStart < 0) {
        throw new RangeError('targetStart out of bounds')
      }
      if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
      if (end < 0) throw new RangeError('sourceEnd out of bounds')

      // Are we oob?
      if (end > this.length) end = this.length;
      if (target.length - targetStart < end - start) {
        end = target.length - targetStart + start;
      }

      var len = end - start;
      var i;

      if (this === target && start < targetStart && targetStart < end) {
        // descending copy from end
        for (i = len - 1; i >= 0; --i) {
          target[i + targetStart] = this[i + start];
        }
      } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
        // ascending copy from start
        for (i = 0; i < len; ++i) {
          target[i + targetStart] = this[i + start];
        }
      } else {
        Uint8Array.prototype.set.call(
          target,
          this.subarray(start, start + len),
          targetStart
        );
      }

      return len
    };

    // Usage:
    //    buffer.fill(number[, offset[, end]])
    //    buffer.fill(buffer[, offset[, end]])
    //    buffer.fill(string[, offset[, end]][, encoding])
    Buffer.prototype.fill = function fill (val, start, end, encoding) {
      // Handle string cases:
      if (typeof val === 'string') {
        if (typeof start === 'string') {
          encoding = start;
          start = 0;
          end = this.length;
        } else if (typeof end === 'string') {
          encoding = end;
          end = this.length;
        }
        if (val.length === 1) {
          var code = val.charCodeAt(0);
          if (code < 256) {
            val = code;
          }
        }
        if (encoding !== undefined && typeof encoding !== 'string') {
          throw new TypeError('encoding must be a string')
        }
        if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
          throw new TypeError('Unknown encoding: ' + encoding)
        }
      } else if (typeof val === 'number') {
        val = val & 255;
      }

      // Invalid ranges are not set to a default, so can range check early.
      if (start < 0 || this.length < start || this.length < end) {
        throw new RangeError('Out of range index')
      }

      if (end <= start) {
        return this
      }

      start = start >>> 0;
      end = end === undefined ? this.length : end >>> 0;

      if (!val) val = 0;

      var i;
      if (typeof val === 'number') {
        for (i = start; i < end; ++i) {
          this[i] = val;
        }
      } else {
        var bytes = internalIsBuffer(val)
          ? val
          : utf8ToBytes(new Buffer(val, encoding).toString());
        var len = bytes.length;
        for (i = 0; i < end - start; ++i) {
          this[i + start] = bytes[i % len];
        }
      }

      return this
    };

    // HELPER FUNCTIONS
    // ================

    var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g;

    function base64clean (str) {
      // Node strips out invalid characters like \n and \t from the string, base64-js does not
      str = stringtrim(str).replace(INVALID_BASE64_RE, '');
      // Node converts strings with length < 2 to ''
      if (str.length < 2) return ''
      // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
      while (str.length % 4 !== 0) {
        str = str + '=';
      }
      return str
    }

    function stringtrim (str) {
      if (str.trim) return str.trim()
      return str.replace(/^\s+|\s+$/g, '')
    }

    function toHex (n) {
      if (n < 16) return '0' + n.toString(16)
      return n.toString(16)
    }

    function utf8ToBytes (string, units) {
      units = units || Infinity;
      var codePoint;
      var length = string.length;
      var leadSurrogate = null;
      var bytes = [];

      for (var i = 0; i < length; ++i) {
        codePoint = string.charCodeAt(i);

        // is surrogate component
        if (codePoint > 0xD7FF && codePoint < 0xE000) {
          // last char was a lead
          if (!leadSurrogate) {
            // no lead yet
            if (codePoint > 0xDBFF) {
              // unexpected trail
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
              continue
            } else if (i + 1 === length) {
              // unpaired lead
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
              continue
            }

            // valid lead
            leadSurrogate = codePoint;

            continue
          }

          // 2 leads in a row
          if (codePoint < 0xDC00) {
            if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
            leadSurrogate = codePoint;
            continue
          }

          // valid surrogate pair
          codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000;
        } else if (leadSurrogate) {
          // valid bmp char, but last char was a lead
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD);
        }

        leadSurrogate = null;

        // encode utf8
        if (codePoint < 0x80) {
          if ((units -= 1) < 0) break
          bytes.push(codePoint);
        } else if (codePoint < 0x800) {
          if ((units -= 2) < 0) break
          bytes.push(
            codePoint >> 0x6 | 0xC0,
            codePoint & 0x3F | 0x80
          );
        } else if (codePoint < 0x10000) {
          if ((units -= 3) < 0) break
          bytes.push(
            codePoint >> 0xC | 0xE0,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          );
        } else if (codePoint < 0x110000) {
          if ((units -= 4) < 0) break
          bytes.push(
            codePoint >> 0x12 | 0xF0,
            codePoint >> 0xC & 0x3F | 0x80,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          );
        } else {
          throw new Error('Invalid code point')
        }
      }

      return bytes
    }

    function asciiToBytes (str) {
      var byteArray = [];
      for (var i = 0; i < str.length; ++i) {
        // Node's code seems to be doing this and not & 0x7F..
        byteArray.push(str.charCodeAt(i) & 0xFF);
      }
      return byteArray
    }

    function utf16leToBytes (str, units) {
      var c, hi, lo;
      var byteArray = [];
      for (var i = 0; i < str.length; ++i) {
        if ((units -= 2) < 0) break

        c = str.charCodeAt(i);
        hi = c >> 8;
        lo = c % 256;
        byteArray.push(lo);
        byteArray.push(hi);
      }

      return byteArray
    }


    function base64ToBytes (str) {
      return toByteArray(base64clean(str))
    }

    function blitBuffer (src, dst, offset, length) {
      for (var i = 0; i < length; ++i) {
        if ((i + offset >= dst.length) || (i >= src.length)) break
        dst[i + offset] = src[i];
      }
      return i
    }

    function isnan (val) {
      return val !== val // eslint-disable-line no-self-compare
    }


    // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence
    // The _isBuffer check is for Safari 5-7 support, because it's missing
    // Object.prototype.constructor. Remove this eventually
    function isBuffer$1(obj) {
      return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj))
    }

    function isFastBuffer (obj) {
      return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
    }

    // For Node v0.10 support. Remove this eventually.
    function isSlowBuffer (obj) {
      return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0))
    }

    // 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$1.setTimeout === 'function') {
        cachedSetTimeout = setTimeout;
    }
    if (typeof global$1.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$2 = true;
    var env = {};
    var argv = [];
    var version$1 = ''; // empty string to avoid regexp issues
    var versions = {};
    var release = {};
    var config = {};

    function noop$1() {}

    var on = noop$1;
    var addListener = noop$1;
    var once = noop$1;
    var off = noop$1;
    var removeListener = noop$1;
    var removeAllListeners = noop$1;
    var emit = noop$1;

    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 = global$1.performance || {};
    var performanceNow =
      performance.now        ||
      performance.mozNow     ||
      performance.msNow      ||
      performance.oNow       ||
      performance.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)*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$2,
      env: env,
      argv: argv,
      version: version$1,
      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 process = browser$1$1;

    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;

    var formatRegExp = /%[sdj%]/g;
    function format(f) {
      if (!isString$1(f)) {
        var objects = [];
        for (var i = 0; i < arguments.length; i++) {
          objects.push(inspect$1(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$1(x) || !isObject$1(x)) {
          str += ' ' + x;
        } else {
          str += ' ' + inspect$1(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$1(global$1.process)) {
        return function() {
          return deprecate(fn, msg).apply(this, arguments);
        };
      }

      if (process.noDeprecation === true) {
        return fn;
      }

      var warned = false;
      function deprecated() {
        if (!warned) {
          if (process.throwDeprecation) {
            throw new Error(msg);
          } else if (process.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$1(debugEnviron))
        debugEnviron = process.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$1(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$1(ctx.showHidden)) ctx.showHidden = false;
      if (isUndefined$1(ctx.depth)) ctx.depth = 2;
      if (isUndefined$1(ctx.colors)) ctx.colors = false;
      if (isUndefined$1(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$1.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$1.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$1.styles[styleType];

      if (style) {
        return '\u001b[' + inspect$1.colors[style][0] + 'm' + str +
               '\u001b[' + inspect$1.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$1 &&
          // 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$1(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$1(value)) {
          return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
        }
        if (isDate$1(value)) {
          return ctx.stylize(Date.prototype.toString.call(value), 'date');
        }
        if (isError$1(value)) {
          return formatError(value);
        }
      }

      var base = '', array = false, braces = ['{', '}'];

      // Make Array say that they are Array
      if (isArray$1(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$1(value)) {
        base = ' ' + RegExp.prototype.toString.call(value);
      }

      // Make dates with properties first say the date
      if (isDate$1(value)) {
        base = ' ' + Date.prototype.toUTCString.call(value);
      }

      // Make error with message first say the error
      if (isError$1(value)) {
        base = ' ' + formatError(value);
      }

      if (keys.length === 0 && (!array || value.length == 0)) {
        return braces[0] + base + braces[1];
      }

      if (recurseTimes < 0) {
        if (isRegExp$1(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$1(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$1(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$1(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$1(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$1(ar) {
      return Array.isArray(ar);
    }

    function isBoolean$1(arg) {
      return typeof arg === 'boolean';
    }

    function isNull$1(arg) {
      return arg === null;
    }

    function isNullOrUndefined$1(arg) {
      return arg == null;
    }

    function isNumber$1(arg) {
      return typeof arg === 'number';
    }

    function isString$1(arg) {
      return typeof arg === 'string';
    }

    function isSymbol$1(arg) {
      return typeof arg === 'symbol';
    }

    function isUndefined$1(arg) {
      return arg === void 0;
    }

    function isRegExp$1(re) {
      return isObject$1(re) && objectToString$1(re) === '[object RegExp]';
    }

    function isObject$1(arg) {
      return typeof arg === 'object' && arg !== null;
    }

    function isDate$1(d) {
      return isObject$1(d) && objectToString$1(d) === '[object Date]';
    }

    function isError$1(e) {
      return isObject$1(e) &&
          (objectToString$1(e) === '[object Error]' || e instanceof Error);
    }

    function isFunction$1(arg) {
      return typeof arg === 'function';
    }

    function isPrimitive$1(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$1(o) {
      return Object.prototype.toString.call(o);
    }


    function pad(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(d.getHours()),
                  pad(d.getMinutes()),
                  pad(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() {
      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$1(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 _polyfillNode_util = {
      inherits: inherits$1,
      _extend: _extend,
      log: log,
      isBuffer: isBuffer,
      isPrimitive: isPrimitive$1,
      isFunction: isFunction$1,
      isError: isError$1,
      isDate: isDate$1,
      isObject: isObject$1,
      isRegExp: isRegExp$1,
      isUndefined: isUndefined$1,
      isSymbol: isSymbol$1,
      isString: isString$1,
      isNumber: isNumber$1,
      isNullOrUndefined: isNullOrUndefined$1,
      isNull: isNull$1,
      isBoolean: isBoolean$1,
      isArray: isArray$1,
      inspect: inspect$1,
      deprecate: deprecate,
      format: format,
      debuglog: debuglog
    };

    var _polyfillNode_util$1 = /*#__PURE__*/Object.freeze({
        __proto__: null,
        format: format,
        deprecate: deprecate,
        debuglog: debuglog,
        inspect: inspect$1,
        isArray: isArray$1,
        isBoolean: isBoolean$1,
        isNull: isNull$1,
        isNullOrUndefined: isNullOrUndefined$1,
        isNumber: isNumber$1,
        isString: isString$1,
        isSymbol: isSymbol$1,
        isUndefined: isUndefined$1,
        isRegExp: isRegExp$1,
        isObject: isObject$1,
        isDate: isDate$1,
        isError: isError$1,
        isFunction: isFunction$1,
        isPrimitive: isPrimitive$1,
        isBuffer: isBuffer,
        log: log,
        inherits: inherits$1,
        _extend: _extend,
        'default': _polyfillNode_util
    });

    function compare(a, b) {
      if (a === b) {
        return 0;
      }

      var x = a.length;
      var y = b.length;

      for (var i = 0, len = Math.min(x, y); i < len; ++i) {
        if (a[i] !== b[i]) {
          x = a[i];
          y = b[i];
          break;
        }
      }

      if (x < y) {
        return -1;
      }
      if (y < x) {
        return 1;
      }
      return 0;
    }
    var hasOwn = Object.prototype.hasOwnProperty;

    var objectKeys = Object.keys || function (obj) {
      var keys = [];
      for (var key in obj) {
        if (hasOwn.call(obj, key)) keys.push(key);
      }
      return keys;
    };
    var pSlice = Array.prototype.slice;
    var _functionsHaveNames;
    function functionsHaveNames() {
      if (typeof _functionsHaveNames !== 'undefined') {
        return _functionsHaveNames;
      }
      return _functionsHaveNames = (function () {
        return function foo() {}.name === 'foo';
      }());
    }
    function pToString (obj) {
      return Object.prototype.toString.call(obj);
    }
    function isView(arrbuf) {
      if (isBuffer$1(arrbuf)) {
        return false;
      }
      if (typeof global$1.ArrayBuffer !== 'function') {
        return false;
      }
      if (typeof ArrayBuffer.isView === 'function') {
        return ArrayBuffer.isView(arrbuf);
      }
      if (!arrbuf) {
        return false;
      }
      if (arrbuf instanceof DataView) {
        return true;
      }
      if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
        return true;
      }
      return false;
    }
    // 1. The assert module provides functions that throw
    // AssertionError's when particular conditions are not met. The
    // assert module must conform to the following interface.

    function assert$2(value, message) {
      if (!value) fail(value, true, message, '==', ok);
    }

    // 2. The AssertionError is defined in assert.
    // new assert.AssertionError({ message: message,
    //                             actual: actual,
    //                             expected: expected })

    var regex = /\s*function\s+([^\(\s]*)\s*/;
    // based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
    function getName(func) {
      if (!isFunction$1(func)) {
        return;
      }
      if (functionsHaveNames()) {
        return func.name;
      }
      var str = func.toString();
      var match = str.match(regex);
      return match && match[1];
    }
    assert$2.AssertionError = AssertionError;
    function AssertionError(options) {
      this.name = 'AssertionError';
      this.actual = options.actual;
      this.expected = options.expected;
      this.operator = options.operator;
      if (options.message) {
        this.message = options.message;
        this.generatedMessage = false;
      } else {
        this.message = getMessage(this);
        this.generatedMessage = true;
      }
      var stackStartFunction = options.stackStartFunction || fail;
      if (Error.captureStackTrace) {
        Error.captureStackTrace(this, stackStartFunction);
      } else {
        // non v8 browsers so we can have a stacktrace
        var err = new Error();
        if (err.stack) {
          var out = err.stack;

          // try to strip useless frames
          var fn_name = getName(stackStartFunction);
          var idx = out.indexOf('\n' + fn_name);
          if (idx >= 0) {
            // once we have located the function frame
            // we need to strip out everything before it (and its line)
            var next_line = out.indexOf('\n', idx + 1);
            out = out.substring(next_line + 1);
          }

          this.stack = out;
        }
      }
    }

    // assert.AssertionError instanceof Error
    inherits$1(AssertionError, Error);

    function truncate(s, n) {
      if (typeof s === 'string') {
        return s.length < n ? s : s.slice(0, n);
      } else {
        return s;
      }
    }
    function inspect(something) {
      if (functionsHaveNames() || !isFunction$1(something)) {
        return inspect$1(something);
      }
      var rawname = getName(something);
      var name = rawname ? ': ' + rawname : '';
      return '[Function' +  name + ']';
    }
    function getMessage(self) {
      return truncate(inspect(self.actual), 128) + ' ' +
             self.operator + ' ' +
             truncate(inspect(self.expected), 128);
    }

    // At present only the three keys mentioned above are used and
    // understood by the spec. Implementations or sub modules can pass
    // other keys to the AssertionError's constructor - they will be
    // ignored.

    // 3. All of the following functions must throw an AssertionError
    // when a corresponding condition is not met, with a message that
    // may be undefined if not provided.  All assertion methods provide
    // both the actual and expected values to the assertion error for
    // display purposes.

    function fail(actual, expected, message, operator, stackStartFunction) {
      throw new AssertionError({
        message: message,
        actual: actual,
        expected: expected,
        operator: operator,
        stackStartFunction: stackStartFunction
      });
    }

    // EXTENSION! allows for well behaved errors defined elsewhere.
    assert$2.fail = fail;

    // 4. Pure assertion tests whether a value is truthy, as determined
    // by !!guard.
    // assert.ok(guard, message_opt);
    // This statement is equivalent to assert.equal(true, !!guard,
    // message_opt);. To test strictly for the value true, use
    // assert.strictEqual(true, guard, message_opt);.

    function ok(value, message) {
      if (!value) fail(value, true, message, '==', ok);
    }
    assert$2.ok = ok;

    // 5. The equality assertion tests shallow, coercive equality with
    // ==.
    // assert.equal(actual, expected, message_opt);
    assert$2.equal = equal;
    function equal(actual, expected, message) {
      if (actual != expected) fail(actual, expected, message, '==', equal);
    }

    // 6. The non-equality assertion tests for whether two objects are not equal
    // with != assert.notEqual(actual, expected, message_opt);
    assert$2.notEqual = notEqual;
    function notEqual(actual, expected, message) {
      if (actual == expected) {
        fail(actual, expected, message, '!=', notEqual);
      }
    }

    // 7. The equivalence assertion tests a deep equality relation.
    // assert.deepEqual(actual, expected, message_opt);
    assert$2.deepEqual = deepEqual$1;
    function deepEqual$1(actual, expected, message) {
      if (!_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'deepEqual', deepEqual$1);
      }
    }
    assert$2.deepStrictEqual = deepStrictEqual;
    function deepStrictEqual(actual, expected, message) {
      if (!_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'deepStrictEqual', deepStrictEqual);
      }
    }

    function _deepEqual(actual, expected, strict, memos) {
      // 7.1. All identical values are equivalent, as determined by ===.
      if (actual === expected) {
        return true;
      } else if (isBuffer$1(actual) && isBuffer$1(expected)) {
        return compare(actual, expected) === 0;

      // 7.2. If the expected value is a Date object, the actual value is
      // equivalent if it is also a Date object that refers to the same time.
      } else if (isDate$1(actual) && isDate$1(expected)) {
        return actual.getTime() === expected.getTime();

      // 7.3 If the expected value is a RegExp object, the actual value is
      // equivalent if it is also a RegExp object with the same source and
      // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
      } else if (isRegExp$1(actual) && isRegExp$1(expected)) {
        return actual.source === expected.source &&
               actual.global === expected.global &&
               actual.multiline === expected.multiline &&
               actual.lastIndex === expected.lastIndex &&
               actual.ignoreCase === expected.ignoreCase;

      // 7.4. Other pairs that do not both pass typeof value == 'object',
      // equivalence is determined by ==.
      } else if ((actual === null || typeof actual !== 'object') &&
                 (expected === null || typeof expected !== 'object')) {
        return strict ? actual === expected : actual == expected;

      // If both values are instances of typed arrays, wrap their underlying
      // ArrayBuffers in a Buffer each to increase performance
      // This optimization requires the arrays to have the same type as checked by
      // Object.prototype.toString (aka pToString). Never perform binary
      // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
      // bit patterns are not identical.
      } else if (isView(actual) && isView(expected) &&
                 pToString(actual) === pToString(expected) &&
                 !(actual instanceof Float32Array ||
                   actual instanceof Float64Array)) {
        return compare(new Uint8Array(actual.buffer),
                       new Uint8Array(expected.buffer)) === 0;

      // 7.5 For all other Object pairs, including Array objects, equivalence is
      // determined by having the same number of owned properties (as verified
      // with Object.prototype.hasOwnProperty.call), the same set of keys
      // (although not necessarily the same order), equivalent values for every
      // corresponding key, and an identical 'prototype' property. Note: this
      // accounts for both named and indexed properties on Arrays.
      } else if (isBuffer$1(actual) !== isBuffer$1(expected)) {
        return false;
      } else {
        memos = memos || {actual: [], expected: []};

        var actualIndex = memos.actual.indexOf(actual);
        if (actualIndex !== -1) {
          if (actualIndex === memos.expected.indexOf(expected)) {
            return true;
          }
        }

        memos.actual.push(actual);
        memos.expected.push(expected);

        return objEquiv(actual, expected, strict, memos);
      }
    }

    function isArguments(object) {
      return Object.prototype.toString.call(object) == '[object Arguments]';
    }

    function objEquiv(a, b, strict, actualVisitedObjects) {
      if (a === null || a === undefined || b === null || b === undefined)
        return false;
      // if one is a primitive, the other must be same
      if (isPrimitive$1(a) || isPrimitive$1(b))
        return a === b;
      if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
        return false;
      var aIsArgs = isArguments(a);
      var bIsArgs = isArguments(b);
      if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
        return false;
      if (aIsArgs) {
        a = pSlice.call(a);
        b = pSlice.call(b);
        return _deepEqual(a, b, strict);
      }
      var ka = objectKeys(a);
      var kb = objectKeys(b);
      var key, i;
      // having the same number of owned properties (keys incorporates
      // hasOwnProperty)
      if (ka.length !== kb.length)
        return false;
      //the same set of keys (although not necessarily the same order),
      ka.sort();
      kb.sort();
      //~~~cheap key test
      for (i = ka.length - 1; i >= 0; i--) {
        if (ka[i] !== kb[i])
          return false;
      }
      //equivalent values for every corresponding key, and
      //~~~possibly expensive deep test
      for (i = ka.length - 1; i >= 0; i--) {
        key = ka[i];
        if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
          return false;
      }
      return true;
    }

    // 8. The non-equivalence assertion tests for any deep inequality.
    // assert.notDeepEqual(actual, expected, message_opt);
    assert$2.notDeepEqual = notDeepEqual;
    function notDeepEqual(actual, expected, message) {
      if (_deepEqual(actual, expected, false)) {
        fail(actual, expected, message, 'notDeepEqual', notDeepEqual);
      }
    }

    assert$2.notDeepStrictEqual = notDeepStrictEqual;
    function notDeepStrictEqual(actual, expected, message) {
      if (_deepEqual(actual, expected, true)) {
        fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
      }
    }


    // 9. The strict equality assertion tests strict equality, as determined by ===.
    // assert.strictEqual(actual, expected, message_opt);
    assert$2.strictEqual = strictEqual;
    function strictEqual(actual, expected, message) {
      if (actual !== expected) {
        fail(actual, expected, message, '===', strictEqual);
      }
    }

    // 10. The strict non-equality assertion tests for strict inequality, as
    // determined by !==.  assert.notStrictEqual(actual, expected, message_opt);
    assert$2.notStrictEqual = notStrictEqual;
    function notStrictEqual(actual, expected, message) {
      if (actual === expected) {
        fail(actual, expected, message, '!==', notStrictEqual);
      }
    }

    function expectedException(actual, expected) {
      if (!actual || !expected) {
        return false;
      }

      if (Object.prototype.toString.call(expected) == '[object RegExp]') {
        return expected.test(actual);
      }

      try {
        if (actual instanceof expected) {
          return true;
        }
      } catch (e) {
        // Ignore.  The instanceof check doesn't work for arrow functions.
      }

      if (Error.isPrototypeOf(expected)) {
        return false;
      }

      return expected.call({}, actual) === true;
    }

    function _tryBlock(block) {
      var error;
      try {
        block();
      } catch (e) {
        error = e;
      }
      return error;
    }

    function _throws(shouldThrow, block, expected, message) {
      var actual;

      if (typeof block !== 'function') {
        throw new TypeError('"block" argument must be a function');
      }

      if (typeof expected === 'string') {
        message = expected;
        expected = null;
      }

      actual = _tryBlock(block);

      message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
                (message ? ' ' + message : '.');

      if (shouldThrow && !actual) {
        fail(actual, expected, 'Missing expected exception' + message);
      }

      var userProvidedMessage = typeof message === 'string';
      var isUnwantedException = !shouldThrow && isError$1(actual);
      var isUnexpectedException = !shouldThrow && actual && !expected;

      if ((isUnwantedException &&
          userProvidedMessage &&
          expectedException(actual, expected)) ||
          isUnexpectedException) {
        fail(actual, expected, 'Got unwanted exception' + message);
      }

      if ((shouldThrow && actual && expected &&
          !expectedException(actual, expected)) || (!shouldThrow && actual)) {
        throw actual;
      }
    }

    // 11. Expected to throw an error:
    // assert.throws(block, Error_opt, message_opt);
    assert$2.throws = throws;
    function throws(block, /*optional*/error, /*optional*/message) {
      _throws(true, block, error, message);
    }

    // EXTENSION! This is annoying to write outside this module.
    assert$2.doesNotThrow = doesNotThrow;
    function doesNotThrow(block, /*optional*/error, /*optional*/message) {
      _throws(false, block, error, message);
    }

    assert$2.ifError = ifError;
    function ifError(err) {
      if (err) throw err;
    }

    var _polyfillNode_assert = /*#__PURE__*/Object.freeze({
        __proto__: null,
        'default': assert$2,
        AssertionError: AssertionError,
        fail: fail,
        ok: ok,
        assert: ok,
        equal: equal,
        notEqual: notEqual,
        deepEqual: deepEqual$1,
        deepStrictEqual: deepStrictEqual,
        notDeepEqual: notDeepEqual,
        notDeepStrictEqual: notDeepStrictEqual,
        strictEqual: strictEqual,
        notStrictEqual: notStrictEqual,
        throws: throws,
        doesNotThrow: doesNotThrow,
        ifError: ifError
    });

    var require$$0 = /*@__PURE__*/getAugmentedNamespace(_polyfillNode_assert);

    var domain;

    // This constructor is used to store event handlers. Instantiating this is
    // faster than explicitly calling `Object.create(null)` to get a "clean" empty
    // object (tested with v8 v4.9).
    function EventHandlers() {}
    EventHandlers.prototype = Object.create(null);

    function EventEmitter() {
      EventEmitter.init.call(this);
    }

    // nodejs oddity
    // require('events') === require('events').EventEmitter
    EventEmitter.EventEmitter = EventEmitter;

    EventEmitter.usingDomains = false;

    EventEmitter.prototype.domain = undefined;
    EventEmitter.prototype._events = undefined;
    EventEmitter.prototype._maxListeners = undefined;

    // By default EventEmitters will print a warning if more than 10 listeners are
    // added to it. This is a useful default which helps finding memory leaks.
    EventEmitter.defaultMaxListeners = 10;

    EventEmitter.init = function() {
      this.domain = null;
      if (EventEmitter.usingDomains) {
        // if there is an active domain, then attach to it.
        if (domain.active ) ;
      }

      if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
        this._events = new EventHandlers();
        this._eventsCount = 0;
      }

      this._maxListeners = this._maxListeners || undefined;
    };

    // Obviously not all Emitters should be limited to 10. This function allows
    // that to be increased. Set to zero for unlimited.
    EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
      if (typeof n !== 'number' || n < 0 || isNaN(n))
        throw new TypeError('"n" argument must be a positive number');
      this._maxListeners = n;
      return this;
    };

    function $getMaxListeners(that) {
      if (that._maxListeners === undefined)
        return EventEmitter.defaultMaxListeners;
      return that._maxListeners;
    }

    EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
      return $getMaxListeners(this);
    };

    // These standalone emit* functions are used to optimize calling of event
    // handlers for fast cases because emit() itself often has a variable number of
    // arguments and can be deoptimized because of that. These functions always have
    // the same number of arguments and thus do not get deoptimized, so the code
    // inside them can execute faster.
    function emitNone(handler, isFn, self) {
      if (isFn)
        handler.call(self);
      else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          listeners[i].call(self);
      }
    }
    function emitOne(handler, isFn, self, arg1) {
      if (isFn)
        handler.call(self, arg1);
      else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          listeners[i].call(self, arg1);
      }
    }
    function emitTwo(handler, isFn, self, arg1, arg2) {
      if (isFn)
        handler.call(self, arg1, arg2);
      else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          listeners[i].call(self, arg1, arg2);
      }
    }
    function emitThree(handler, isFn, self, arg1, arg2, arg3) {
      if (isFn)
        handler.call(self, arg1, arg2, arg3);
      else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          listeners[i].call(self, arg1, arg2, arg3);
      }
    }

    function emitMany(handler, isFn, self, args) {
      if (isFn)
        handler.apply(self, args);
      else {
        var len = handler.length;
        var listeners = arrayClone(handler, len);
        for (var i = 0; i < len; ++i)
          listeners[i].apply(self, args);
      }
    }

    EventEmitter.prototype.emit = function emit(type) {
      var er, handler, len, args, i, events, domain;
      var doError = (type === 'error');

      events = this._events;
      if (events)
        doError = (doError && events.error == null);
      else if (!doError)
        return false;

      domain = this.domain;

      // If there is no 'error' event listener then throw.
      if (doError) {
        er = arguments[1];
        if (domain) {
          if (!er)
            er = new Error('Uncaught, unspecified "error" event');
          er.domainEmitter = this;
          er.domain = domain;
          er.domainThrown = false;
          domain.emit('error', er);
        } else if (er instanceof Error) {
          throw er; // Unhandled 'error' event
        } else {
          // At least give some kind of context to the user
          var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
          err.context = er;
          throw err;
        }
        return false;
      }

      handler = events[type];

      if (!handler)
        return false;

      var isFn = typeof handler === 'function';
      len = arguments.length;
      switch (len) {
        // fast cases
        case 1:
          emitNone(handler, isFn, this);
          break;
        case 2:
          emitOne(handler, isFn, this, arguments[1]);
          break;
        case 3:
          emitTwo(handler, isFn, this, arguments[1], arguments[2]);
          break;
        case 4:
          emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
          break;
        // slower
        default:
          args = new Array(len - 1);
          for (i = 1; i < len; i++)
            args[i - 1] = arguments[i];
          emitMany(handler, isFn, this, args);
      }

      return true;
    };

    function _addListener(target, type, listener, prepend) {
      var m;
      var events;
      var existing;

      if (typeof listener !== 'function')
        throw new TypeError('"listener" argument must be a function');

      events = target._events;
      if (!events) {
        events = target._events = new EventHandlers();
        target._eventsCount = 0;
      } else {
        // To avoid recursion in the case that type === "newListener"! Before
        // adding it to the listeners, first emit "newListener".
        if (events.newListener) {
          target.emit('newListener', type,
                      listener.listener ? listener.listener : listener);

          // Re-assign `events` because a newListener handler could have caused the
          // this._events to be assigned to a new object
          events = target._events;
        }
        existing = events[type];
      }

      if (!existing) {
        // Optimize the case of one listener. Don't need the extra array object.
        existing = events[type] = listener;
        ++target._eventsCount;
      } else {
        if (typeof existing === 'function') {
          // Adding the second element, need to change to array.
          existing = events[type] = prepend ? [listener, existing] :
                                              [existing, listener];
        } else {
          // If we've already got an array, just append.
          if (prepend) {
            existing.unshift(listener);
          } else {
            existing.push(listener);
          }
        }

        // Check for listener leak
        if (!existing.warned) {
          m = $getMaxListeners(target);
          if (m && m > 0 && existing.length > m) {
            existing.warned = true;
            var w = new Error('Possible EventEmitter memory leak detected. ' +
                                existing.length + ' ' + type + ' listeners added. ' +
                                'Use emitter.setMaxListeners() to increase limit');
            w.name = 'MaxListenersExceededWarning';
            w.emitter = target;
            w.type = type;
            w.count = existing.length;
            emitWarning(w);
          }
        }
      }

      return target;
    }
    function emitWarning(e) {
      typeof console.warn === 'function' ? console.warn(e) : console.log(e);
    }
    EventEmitter.prototype.addListener = function addListener(type, listener) {
      return _addListener(this, type, listener, false);
    };

    EventEmitter.prototype.on = EventEmitter.prototype.addListener;

    EventEmitter.prototype.prependListener =
        function prependListener(type, listener) {
          return _addListener(this, type, listener, true);
        };

    function _onceWrap(target, type, listener) {
      var fired = false;
      function g() {
        target.removeListener(type, g);
        if (!fired) {
          fired = true;
          listener.apply(target, arguments);
        }
      }
      g.listener = listener;
      return g;
    }

    EventEmitter.prototype.once = function once(type, listener) {
      if (typeof listener !== 'function')
        throw new TypeError('"listener" argument must be a function');
      this.on(type, _onceWrap(this, type, listener));
      return this;
    };

    EventEmitter.prototype.prependOnceListener =
        function prependOnceListener(type, listener) {
          if (typeof listener !== 'function')
            throw new TypeError('"listener" argument must be a function');
          this.prependListener(type, _onceWrap(this, type, listener));
          return this;
        };

    // emits a 'removeListener' event iff the listener was removed
    EventEmitter.prototype.removeListener =
        function removeListener(type, listener) {
          var list, events, position, i, originalListener;

          if (typeof listener !== 'function')
            throw new TypeError('"listener" argument must be a function');

          events = this._events;
          if (!events)
            return this;

          list = events[type];
          if (!list)
            return this;

          if (list === listener || (list.listener && list.listener === listener)) {
            if (--this._eventsCount === 0)
              this._events = new EventHandlers();
            else {
              delete events[type];
              if (events.removeListener)
                this.emit('removeListener', type, list.listener || listener);
            }
          } else if (typeof list !== 'function') {
            position = -1;

            for (i = list.length; i-- > 0;) {
              if (list[i] === listener ||
                  (list[i].listener && list[i].listener === listener)) {
                originalListener = list[i].listener;
                position = i;
                break;
              }
            }

            if (position < 0)
              return this;

            if (list.length === 1) {
              list[0] = undefined;
              if (--this._eventsCount === 0) {
                this._events = new EventHandlers();
                return this;
              } else {
                delete events[type];
              }
            } else {
              spliceOne(list, position);
            }

            if (events.removeListener)
              this.emit('removeListener', type, originalListener || listener);
          }

          return this;
        };
        
    // Alias for removeListener added in NodeJS 10.0
    // https://nodejs.org/api/events.html#events_emitter_off_eventname_listener
    EventEmitter.prototype.off = function(type, listener){
        return this.removeListener(type, listener);
    };

    EventEmitter.prototype.removeAllListeners =
        function removeAllListeners(type) {
          var listeners, events;

          events = this._events;
          if (!events)
            return this;

          // not listening for removeListener, no need to emit
          if (!events.removeListener) {
            if (arguments.length === 0) {
              this._events = new EventHandlers();
              this._eventsCount = 0;
            } else if (events[type]) {
              if (--this._eventsCount === 0)
                this._events = new EventHandlers();
              else
                delete events[type];
            }
            return this;
          }

          // emit removeListener for all listeners on all events
          if (arguments.length === 0) {
            var keys = Object.keys(events);
            for (var i = 0, key; i < keys.length; ++i) {
              key = keys[i];
              if (key === 'removeListener') continue;
              this.removeAllListeners(key);
            }
            this.removeAllListeners('removeListener');
            this._events = new EventHandlers();
            this._eventsCount = 0;
            return this;
          }

          listeners = events[type];

          if (typeof listeners === 'function') {
            this.removeListener(type, listeners);
          } else if (listeners) {
            // LIFO order
            do {
              this.removeListener(type, listeners[listeners.length - 1]);
            } while (listeners[0]);
          }

          return this;
        };

    EventEmitter.prototype.listeners = function listeners(type) {
      var evlistener;
      var ret;
      var events = this._events;

      if (!events)
        ret = [];
      else {
        evlistener = events[type];
        if (!evlistener)
          ret = [];
        else if (typeof evlistener === 'function')
          ret = [evlistener.listener || evlistener];
        else
          ret = unwrapListeners(evlistener);
      }

      return ret;
    };

    EventEmitter.listenerCount = function(emitter, type) {
      if (typeof emitter.listenerCount === 'function') {
        return emitter.listenerCount(type);
      } else {
        return listenerCount$1.call(emitter, type);
      }
    };

    EventEmitter.prototype.listenerCount = listenerCount$1;
    function listenerCount$1(type) {
      var events = this._events;

      if (events) {
        var evlistener = events[type];

        if (typeof evlistener === 'function') {
          return 1;
        } else if (evlistener) {
          return evlistener.length;
        }
      }

      return 0;
    }

    EventEmitter.prototype.eventNames = function eventNames() {
      return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
    };

    // About 1.5x faster than the two-arg version of Array#splice().
    function spliceOne(list, index) {
      for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
        list[i] = list[k];
      list.pop();
    }

    function arrayClone(arr, i) {
      var copy = new Array(i);
      while (i--)
        copy[i] = arr[i];
      return copy;
    }

    function unwrapListeners(arr) {
      var ret = new Array(arr.length);
      for (var i = 0; i < ret.length; ++i) {
        ret[i] = arr[i].listener || arr[i];
      }
      return ret;
    }

    function BufferList() {
      this.head = null;
      this.tail = null;
      this.length = 0;
    }

    BufferList.prototype.push = function (v) {
      var entry = { data: v, next: null };
      if (this.length > 0) this.tail.next = entry;else this.head = entry;
      this.tail = entry;
      ++this.length;
    };

    BufferList.prototype.unshift = function (v) {
      var entry = { data: v, next: this.head };
      if (this.length === 0) this.tail = entry;
      this.head = entry;
      ++this.length;
    };

    BufferList.prototype.shift = function () {
      if (this.length === 0) return;
      var ret = this.head.data;
      if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next;
      --this.length;
      return ret;
    };

    BufferList.prototype.clear = function () {
      this.head = this.tail = null;
      this.length = 0;
    };

    BufferList.prototype.join = function (s) {
      if (this.length === 0) return '';
      var p = this.head;
      var ret = '' + p.data;
      while (p = p.next) {
        ret += s + p.data;
      }return ret;
    };

    BufferList.prototype.concat = function (n) {
      if (this.length === 0) return Buffer.alloc(0);
      if (this.length === 1) return this.head.data;
      var ret = Buffer.allocUnsafe(n >>> 0);
      var p = this.head;
      var i = 0;
      while (p) {
        p.data.copy(ret, i);
        i += p.data.length;
        p = p.next;
      }
      return ret;
    };

    // Copyright Joyent, Inc. and other Node contributors.
    var isBufferEncoding = Buffer.isEncoding
      || function(encoding) {
           switch (encoding && encoding.toLowerCase()) {
             case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true;
             default: return false;
           }
         };


    function assertEncoding(encoding) {
      if (encoding && !isBufferEncoding(encoding)) {
        throw new Error('Unknown encoding: ' + encoding);
      }
    }

    // StringDecoder provides an interface for efficiently splitting a series of
    // buffers into a series of JS strings without breaking apart multi-byte
    // characters. CESU-8 is handled as part of the UTF-8 encoding.
    //
    // @TODO Handling all encodings inside a single object makes it very difficult
    // to reason about this code, so it should be split up in the future.
    // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code
    // points as used by CESU-8.
    function StringDecoder(encoding) {
      this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
      assertEncoding(encoding);
      switch (this.encoding) {
        case 'utf8':
          // CESU-8 represents each of Surrogate Pair by 3-bytes
          this.surrogateSize = 3;
          break;
        case 'ucs2':
        case 'utf16le':
          // UTF-16 represents each of Surrogate Pair by 2-bytes
          this.surrogateSize = 2;
          this.detectIncompleteChar = utf16DetectIncompleteChar;
          break;
        case 'base64':
          // Base-64 stores 3 bytes in 4 chars, and pads the remainder.
          this.surrogateSize = 3;
          this.detectIncompleteChar = base64DetectIncompleteChar;
          break;
        default:
          this.write = passThroughWrite;
          return;
      }

      // Enough space to store all bytes of a single character. UTF-8 needs 4
      // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate).
      this.charBuffer = new Buffer(6);
      // Number of bytes received for the current incomplete multi-byte character.
      this.charReceived = 0;
      // Number of bytes expected for the current incomplete multi-byte character.
      this.charLength = 0;
    }

    // write decodes the given buffer and returns it as JS string that is
    // guaranteed to not contain any partial multi-byte characters. Any partial
    // character found at the end of the buffer is buffered up, and will be
    // returned when calling write again with the remaining bytes.
    //
    // Note: Converting a Buffer containing an orphan surrogate to a String
    // currently works, but converting a String to a Buffer (via `new Buffer`, or
    // Buffer#write) will replace incomplete surrogates with the unicode
    // replacement character. See https://codereview.chromium.org/121173009/ .
    StringDecoder.prototype.write = function(buffer) {
      var charStr = '';
      // if our last write ended with an incomplete multibyte character
      while (this.charLength) {
        // determine how many remaining bytes this buffer has to offer for this char
        var available = (buffer.length >= this.charLength - this.charReceived) ?
            this.charLength - this.charReceived :
            buffer.length;

        // add the new bytes to the char buffer
        buffer.copy(this.charBuffer, this.charReceived, 0, available);
        this.charReceived += available;

        if (this.charReceived < this.charLength) {
          // still not enough chars in this buffer? wait for more ...
          return '';
        }

        // remove bytes belonging to the current character from the buffer
        buffer = buffer.slice(available, buffer.length);

        // get the character that was split
        charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);

        // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
        var charCode = charStr.charCodeAt(charStr.length - 1);
        if (charCode >= 0xD800 && charCode <= 0xDBFF) {
          this.charLength += this.surrogateSize;
          charStr = '';
          continue;
        }
        this.charReceived = this.charLength = 0;

        // if there are no more bytes in this buffer, just emit our char
        if (buffer.length === 0) {
          return charStr;
        }
        break;
      }

      // determine and set charLength / charReceived
      this.detectIncompleteChar(buffer);

      var end = buffer.length;
      if (this.charLength) {
        // buffer the incomplete character bytes we got
        buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end);
        end -= this.charReceived;
      }

      charStr += buffer.toString(this.encoding, 0, end);

      var end = charStr.length - 1;
      var charCode = charStr.charCodeAt(end);
      // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character
      if (charCode >= 0xD800 && charCode <= 0xDBFF) {
        var size = this.surrogateSize;
        this.charLength += size;
        this.charReceived += size;
        this.charBuffer.copy(this.charBuffer, size, 0, size);
        buffer.copy(this.charBuffer, 0, 0, size);
        return charStr.substring(0, end);
      }

      // or just emit the charStr
      return charStr;
    };

    // detectIncompleteChar determines if there is an incomplete UTF-8 character at
    // the end of the given buffer. If so, it sets this.charLength to the byte
    // length that character, and sets this.charReceived to the number of bytes
    // that are available for this character.
    StringDecoder.prototype.detectIncompleteChar = function(buffer) {
      // determine how many bytes we have to check at the end of this buffer
      var i = (buffer.length >= 3) ? 3 : buffer.length;

      // Figure out if one of the last i bytes of our buffer announces an
      // incomplete char.
      for (; i > 0; i--) {
        var c = buffer[buffer.length - i];

        // See http://en.wikipedia.org/wiki/UTF-8#Description

        // 110XXXXX
        if (i == 1 && c >> 5 == 0x06) {
          this.charLength = 2;
          break;
        }

        // 1110XXXX
        if (i <= 2 && c >> 4 == 0x0E) {
          this.charLength = 3;
          break;
        }

        // 11110XXX
        if (i <= 3 && c >> 3 == 0x1E) {
          this.charLength = 4;
          break;
        }
      }
      this.charReceived = i;
    };

    StringDecoder.prototype.end = function(buffer) {
      var res = '';
      if (buffer && buffer.length)
        res = this.write(buffer);

      if (this.charReceived) {
        var cr = this.charReceived;
        var buf = this.charBuffer;
        var enc = this.encoding;
        res += buf.slice(0, cr).toString(enc);
      }

      return res;
    };

    function passThroughWrite(buffer) {
      return buffer.toString(this.encoding);
    }

    function utf16DetectIncompleteChar(buffer) {
      this.charReceived = buffer.length % 2;
      this.charLength = this.charReceived ? 2 : 0;
    }

    function base64DetectIncompleteChar(buffer) {
      this.charReceived = buffer.length % 3;
      this.charLength = this.charReceived ? 3 : 0;
    }

    Readable.ReadableState = ReadableState;

    var debug = debuglog('stream');
    inherits$1(Readable, EventEmitter);

    function prependListener(emitter, event, fn) {
      // Sadly this is not cacheable as some libraries bundle their own
      // event emitter implementation with them.
      if (typeof emitter.prependListener === 'function') {
        return emitter.prependListener(event, fn);
      } else {
        // This is a hack to make sure that our error handler is attached before any
        // userland ones.  NEVER DO THIS. This is here only because this code needs
        // to continue to work with older versions of Node.js that do not include
        // the prependListener() method. The goal is to eventually remove this hack.
        if (!emitter._events || !emitter._events[event])
          emitter.on(event, fn);
        else if (Array.isArray(emitter._events[event]))
          emitter._events[event].unshift(fn);
        else
          emitter._events[event] = [fn, emitter._events[event]];
      }
    }
    function listenerCount (emitter, type) {
      return emitter.listeners(type).length;
    }
    function ReadableState(options, stream) {

      options = options || {};

      // object stream flag. Used to make read(n) ignore n and to
      // make all the buffer merging and length checks go away
      this.objectMode = !!options.objectMode;

      if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode;

      // the point at which it stops calling _read() to fill the buffer
      // Note: 0 is a valid value, means "don't call _read preemptively ever"
      var hwm = options.highWaterMark;
      var defaultHwm = this.objectMode ? 16 : 16 * 1024;
      this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;

      // cast to ints.
      this.highWaterMark = ~ ~this.highWaterMark;

      // A linked list is used to store data chunks instead of an array because the
      // linked list can remove elements from the beginning faster than
      // array.shift()
      this.buffer = new BufferList();
      this.length = 0;
      this.pipes = null;
      this.pipesCount = 0;
      this.flowing = null;
      this.ended = false;
      this.endEmitted = false;
      this.reading = false;

      // a flag to be able to tell if the onwrite cb is called immediately,
      // or on a later tick.  We set this to true at first, because any
      // actions that shouldn't happen until "later" should generally also
      // not happen before the first write call.
      this.sync = true;

      // whenever we return null, then we set a flag to say
      // that we're awaiting a 'readable' event emission.
      this.needReadable = false;
      this.emittedReadable = false;
      this.readableListening = false;
      this.resumeScheduled = false;

      // Crypto is kind of old and crusty.  Historically, its default string
      // encoding is 'binary' so we have to make this configurable.
      // Everything else in the universe uses 'utf8', though.
      this.defaultEncoding = options.defaultEncoding || 'utf8';

      // when piping, we only care about 'readable' events that happen
      // after read()ing all the bytes and not getting any pushback.
      this.ranOut = false;

      // the number of writers that are awaiting a drain event in .pipe()s
      this.awaitDrain = 0;

      // if true, a maybeReadMore has been scheduled
      this.readingMore = false;

      this.decoder = null;
      this.encoding = null;
      if (options.encoding) {
        this.decoder = new StringDecoder(options.encoding);
        this.encoding = options.encoding;
      }
    }
    function Readable(options) {

      if (!(this instanceof Readable)) return new Readable(options);

      this._readableState = new ReadableState(options, this);

      // legacy
      this.readable = true;

      if (options && typeof options.read === 'function') this._read = options.read;

      EventEmitter.call(this);
    }

    // Manually shove something into the read() buffer.
    // This returns true if the highWaterMark has not been hit yet,
    // similar to how Writable.write() returns true if you should
    // write() some more.
    Readable.prototype.push = function (chunk, encoding) {
      var state = this._readableState;

      if (!state.objectMode && typeof chunk === 'string') {
        encoding = encoding || state.defaultEncoding;
        if (encoding !== state.encoding) {
          chunk = Buffer.from(chunk, encoding);
          encoding = '';
        }
      }

      return readableAddChunk(this, state, chunk, encoding, false);
    };

    // Unshift should *always* be something directly out of read()
    Readable.prototype.unshift = function (chunk) {
      var state = this._readableState;
      return readableAddChunk(this, state, chunk, '', true);
    };

    Readable.prototype.isPaused = function () {
      return this._readableState.flowing === false;
    };

    function readableAddChunk(stream, state, chunk, encoding, addToFront) {
      var er = chunkInvalid(state, chunk);
      if (er) {
        stream.emit('error', er);
      } else if (chunk === null) {
        state.reading = false;
        onEofChunk(stream, state);
      } else if (state.objectMode || chunk && chunk.length > 0) {
        if (state.ended && !addToFront) {
          var e = new Error('stream.push() after EOF');
          stream.emit('error', e);
        } else if (state.endEmitted && addToFront) {
          var _e = new Error('stream.unshift() after end event');
          stream.emit('error', _e);
        } else {
          var skipAdd;
          if (state.decoder && !addToFront && !encoding) {
            chunk = state.decoder.write(chunk);
            skipAdd = !state.objectMode && chunk.length === 0;
          }

          if (!addToFront) state.reading = false;

          // Don't add to the buffer if we've decoded to an empty string chunk and
          // we're not in object mode
          if (!skipAdd) {
            // if we want the data now, just emit it.
            if (state.flowing && state.length === 0 && !state.sync) {
              stream.emit('data', chunk);
              stream.read(0);
            } else {
              // update the buffer info.
              state.length += state.objectMode ? 1 : chunk.length;
              if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);

              if (state.needReadable) emitReadable(stream);
            }
          }

          maybeReadMore(stream, state);
        }
      } else if (!addToFront) {
        state.reading = false;
      }

      return needMoreData(state);
    }

    // if it's past the high water mark, we can push in some more.
    // Also, if we have no data yet, we can stand some
    // more bytes.  This is to work around cases where hwm=0,
    // such as the repl.  Also, if the push() triggered a
    // readable event, and the user called read(largeNumber) such that
    // needReadable was set, then we ought to push more, so that another
    // 'readable' event will be triggered.
    function needMoreData(state) {
      return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);
    }

    // backwards compatibility.
    Readable.prototype.setEncoding = function (enc) {
      this._readableState.decoder = new StringDecoder(enc);
      this._readableState.encoding = enc;
      return this;
    };

    // Don't raise the hwm > 8MB
    var MAX_HWM = 0x800000;
    function computeNewHighWaterMark(n) {
      if (n >= MAX_HWM) {
        n = MAX_HWM;
      } else {
        // Get the next highest power of 2 to prevent increasing hwm excessively in
        // tiny amounts
        n--;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        n++;
      }
      return n;
    }

    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function howMuchToRead(n, state) {
      if (n <= 0 || state.length === 0 && state.ended) return 0;
      if (state.objectMode) return 1;
      if (n !== n) {
        // Only flow one buffer at a time
        if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;
      }
      // If we're asking for more than the current hwm, then raise the hwm.
      if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);
      if (n <= state.length) return n;
      // Don't have enough
      if (!state.ended) {
        state.needReadable = true;
        return 0;
      }
      return state.length;
    }

    // you can override either this method, or the async _read(n) below.
    Readable.prototype.read = function (n) {
      debug('read', n);
      n = parseInt(n, 10);
      var state = this._readableState;
      var nOrig = n;

      if (n !== 0) state.emittedReadable = false;

      // if we're doing read(0) to trigger a readable event, but we
      // already have a bunch of data in the buffer, then just trigger
      // the 'readable' event and move on.
      if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {
        debug('read: emitReadable', state.length, state.ended);
        if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);
        return null;
      }

      n = howMuchToRead(n, state);

      // if we've ended, and we're now clear, then finish it up.
      if (n === 0 && state.ended) {
        if (state.length === 0) endReadable(this);
        return null;
      }

      // All the actual chunk generation logic needs to be
      // *below* the call to _read.  The reason is that in certain
      // synthetic stream cases, such as passthrough streams, _read
      // may be a completely synchronous operation which may change
      // the state of the read buffer, providing enough data when
      // before there was *not* enough.
      //
      // So, the steps are:
      // 1. Figure out what the state of things will be after we do
      // a read from the buffer.
      //
      // 2. If that resulting state will trigger a _read, then call _read.
      // Note that this may be asynchronous, or synchronous.  Yes, it is
      // deeply ugly to write APIs this way, but that still doesn't mean
      // that the Readable class should behave improperly, as streams are
      // designed to be sync/async agnostic.
      // Take note if the _read call is sync or async (ie, if the read call
      // has returned yet), so that we know whether or not it's safe to emit
      // 'readable' etc.
      //
      // 3. Actually pull the requested chunks out of the buffer and return.

      // if we need a readable event, then we need to do some reading.
      var doRead = state.needReadable;
      debug('need readable', doRead);

      // if we currently have less than the highWaterMark, then also read some
      if (state.length === 0 || state.length - n < state.highWaterMark) {
        doRead = true;
        debug('length less than watermark', doRead);
      }

      // however, if we've ended, then there's no point, and if we're already
      // reading, then it's unnecessary.
      if (state.ended || state.reading) {
        doRead = false;
        debug('reading or ended', doRead);
      } else if (doRead) {
        debug('do read');
        state.reading = true;
        state.sync = true;
        // if the length is currently zero, then we *need* a readable event.
        if (state.length === 0) state.needReadable = true;
        // call internal read method
        this._read(state.highWaterMark);
        state.sync = false;
        // If _read pushed data synchronously, then `reading` will be false,
        // and we need to re-evaluate how much data we can return to the user.
        if (!state.reading) n = howMuchToRead(nOrig, state);
      }

      var ret;
      if (n > 0) ret = fromList(n, state);else ret = null;

      if (ret === null) {
        state.needReadable = true;
        n = 0;
      } else {
        state.length -= n;
      }

      if (state.length === 0) {
        // If we have nothing in the buffer, then we want to know
        // as soon as we *do* get something into the buffer.
        if (!state.ended) state.needReadable = true;

        // If we tried to read() past the EOF, then emit end on the next tick.
        if (nOrig !== n && state.ended) endReadable(this);
      }

      if (ret !== null) this.emit('data', ret);

      return ret;
    };

    function chunkInvalid(state, chunk) {
      var er = null;
      if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== null && chunk !== undefined && !state.objectMode) {
        er = new TypeError('Invalid non-string/buffer chunk');
      }
      return er;
    }

    function onEofChunk(stream, state) {
      if (state.ended) return;
      if (state.decoder) {
        var chunk = state.decoder.end();
        if (chunk && chunk.length) {
          state.buffer.push(chunk);
          state.length += state.objectMode ? 1 : chunk.length;
        }
      }
      state.ended = true;

      // emit 'readable' now to make sure it gets picked up.
      emitReadable(stream);
    }

    // Don't emit readable right away in sync mode, because this can trigger
    // another read() call => stack overflow.  This way, it might trigger
    // a nextTick recursion warning, but that's not so bad.
    function emitReadable(stream) {
      var state = stream._readableState;
      state.needReadable = false;
      if (!state.emittedReadable) {
        debug('emitReadable', state.flowing);
        state.emittedReadable = true;
        if (state.sync) nextTick(emitReadable_, stream);else emitReadable_(stream);
      }
    }

    function emitReadable_(stream) {
      debug('emit readable');
      stream.emit('readable');
      flow(stream);
    }

    // at this point, the user has presumably seen the 'readable' event,
    // and called read() to consume some data.  that may have triggered
    // in turn another _read(n) call, in which case reading = true if
    // it's in progress.
    // However, if we're not ended, or reading, and the length < hwm,
    // then go ahead and try to read some more preemptively.
    function maybeReadMore(stream, state) {
      if (!state.readingMore) {
        state.readingMore = true;
        nextTick(maybeReadMore_, stream, state);
      }
    }

    function maybeReadMore_(stream, state) {
      var len = state.length;
      while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {
        debug('maybeReadMore read 0');
        stream.read(0);
        if (len === state.length)
          // didn't get any data, stop spinning.
          break;else len = state.length;
      }
      state.readingMore = false;
    }

    // abstract method.  to be overridden in specific implementation classes.
    // call cb(er, data) where data is <= n in length.
    // for virtual (non-string, non-buffer) streams, "length" is somewhat
    // arbitrary, and perhaps not very meaningful.
    Readable.prototype._read = function (n) {
      this.emit('error', new Error('not implemented'));
    };

    Readable.prototype.pipe = function (dest, pipeOpts) {
      var src = this;
      var state = this._readableState;

      switch (state.pipesCount) {
        case 0:
          state.pipes = dest;
          break;
        case 1:
          state.pipes = [state.pipes, dest];
          break;
        default:
          state.pipes.push(dest);
          break;
      }
      state.pipesCount += 1;
      debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);

      var doEnd = (!pipeOpts || pipeOpts.end !== false);

      var endFn = doEnd ? onend : cleanup;
      if (state.endEmitted) nextTick(endFn);else src.once('end', endFn);

      dest.on('unpipe', onunpipe);
      function onunpipe(readable) {
        debug('onunpipe');
        if (readable === src) {
          cleanup();
        }
      }

      function onend() {
        debug('onend');
        dest.end();
      }

      // when the dest drains, it reduces the awaitDrain counter
      // on the source.  This would be more elegant with a .once()
      // handler in flow(), but adding and removing repeatedly is
      // too slow.
      var ondrain = pipeOnDrain(src);
      dest.on('drain', ondrain);

      var cleanedUp = false;
      function cleanup() {
        debug('cleanup');
        // cleanup event handlers once the pipe is broken
        dest.removeListener('close', onclose);
        dest.removeListener('finish', onfinish);
        dest.removeListener('drain', ondrain);
        dest.removeListener('error', onerror);
        dest.removeListener('unpipe', onunpipe);
        src.removeListener('end', onend);
        src.removeListener('end', cleanup);
        src.removeListener('data', ondata);

        cleanedUp = true;

        // if the reader is waiting for a drain event from this
        // specific writer, then it would cause it to never start
        // flowing again.
        // So, if this is awaiting a drain, then we just call it now.
        // If we don't know, then assume that we are waiting for one.
        if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();
      }

      // If the user pushes more data while we're writing to dest then we'll end up
      // in ondata again. However, we only want to increase awaitDrain once because
      // dest will only emit one 'drain' event for the multiple writes.
      // => Introduce a guard on increasing awaitDrain.
      var increasedAwaitDrain = false;
      src.on('data', ondata);
      function ondata(chunk) {
        debug('ondata');
        increasedAwaitDrain = false;
        var ret = dest.write(chunk);
        if (false === ret && !increasedAwaitDrain) {
          // If the user unpiped during `dest.write()`, it is possible
          // to get stuck in a permanently paused state if that write
          // also returned false.
          // => Check whether `dest` is still a piping destination.
          if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {
            debug('false write response, pause', src._readableState.awaitDrain);
            src._readableState.awaitDrain++;
            increasedAwaitDrain = true;
          }
          src.pause();
        }
      }

      // if the dest has an error, then stop piping into it.
      // however, don't suppress the throwing behavior for this.
      function onerror(er) {
        debug('onerror', er);
        unpipe();
        dest.removeListener('error', onerror);
        if (listenerCount(dest, 'error') === 0) dest.emit('error', er);
      }

      // Make sure our error handler is attached before userland ones.
      prependListener(dest, 'error', onerror);

      // Both close and finish should trigger unpipe, but only once.
      function onclose() {
        dest.removeListener('finish', onfinish);
        unpipe();
      }
      dest.once('close', onclose);
      function onfinish() {
        debug('onfinish');
        dest.removeListener('close', onclose);
        unpipe();
      }
      dest.once('finish', onfinish);

      function unpipe() {
        debug('unpipe');
        src.unpipe(dest);
      }

      // tell the dest that it's being piped to
      dest.emit('pipe', src);

      // start the flow if it hasn't been started already.
      if (!state.flowing) {
        debug('pipe resume');
        src.resume();
      }

      return dest;
    };

    function pipeOnDrain(src) {
      return function () {
        var state = src._readableState;
        debug('pipeOnDrain', state.awaitDrain);
        if (state.awaitDrain) state.awaitDrain--;
        if (state.awaitDrain === 0 && src.listeners('data').length) {
          state.flowing = true;
          flow(src);
        }
      };
    }

    Readable.prototype.unpipe = function (dest) {
      var state = this._readableState;

      // if we're not piping anywhere, then do nothing.
      if (state.pipesCount === 0) return this;

      // just one destination.  most common case.
      if (state.pipesCount === 1) {
        // passed in one, but it's not the right one.
        if (dest && dest !== state.pipes) return this;

        if (!dest) dest = state.pipes;

        // got a match.
        state.pipes = null;
        state.pipesCount = 0;
        state.flowing = false;
        if (dest) dest.emit('unpipe', this);
        return this;
      }

      // slow case. multiple pipe destinations.

      if (!dest) {
        // remove all.
        var dests = state.pipes;
        var len = state.pipesCount;
        state.pipes = null;
        state.pipesCount = 0;
        state.flowing = false;

        for (var _i = 0; _i < len; _i++) {
          dests[_i].emit('unpipe', this);
        }return this;
      }

      // try to find the right one.
      var i = indexOf(state.pipes, dest);
      if (i === -1) return this;

      state.pipes.splice(i, 1);
      state.pipesCount -= 1;
      if (state.pipesCount === 1) state.pipes = state.pipes[0];

      dest.emit('unpipe', this);

      return this;
    };

    // set up data events if they are asked for
    // Ensure readable listeners eventually get something
    Readable.prototype.on = function (ev, fn) {
      var res = EventEmitter.prototype.on.call(this, ev, fn);

      if (ev === 'data') {
        // Start flowing on next tick if stream isn't explicitly paused
        if (this._readableState.flowing !== false) this.resume();
      } else if (ev === 'readable') {
        var state = this._readableState;
        if (!state.endEmitted && !state.readableListening) {
          state.readableListening = state.needReadable = true;
          state.emittedReadable = false;
          if (!state.reading) {
            nextTick(nReadingNextTick, this);
          } else if (state.length) {
            emitReadable(this);
          }
        }
      }

      return res;
    };
    Readable.prototype.addListener = Readable.prototype.on;

    function nReadingNextTick(self) {
      debug('readable nexttick read 0');
      self.read(0);
    }

    // pause() and resume() are remnants of the legacy readable stream API
    // If the user uses them, then switch into old mode.
    Readable.prototype.resume = function () {
      var state = this._readableState;
      if (!state.flowing) {
        debug('resume');
        state.flowing = true;
        resume(this, state);
      }
      return this;
    };

    function resume(stream, state) {
      if (!state.resumeScheduled) {
        state.resumeScheduled = true;
        nextTick(resume_, stream, state);
      }
    }

    function resume_(stream, state) {
      if (!state.reading) {
        debug('resume read 0');
        stream.read(0);
      }

      state.resumeScheduled = false;
      state.awaitDrain = 0;
      stream.emit('resume');
      flow(stream);
      if (state.flowing && !state.reading) stream.read(0);
    }

    Readable.prototype.pause = function () {
      debug('call pause flowing=%j', this._readableState.flowing);
      if (false !== this._readableState.flowing) {
        debug('pause');
        this._readableState.flowing = false;
        this.emit('pause');
      }
      return this;
    };

    function flow(stream) {
      var state = stream._readableState;
      debug('flow', state.flowing);
      while (state.flowing && stream.read() !== null) {}
    }

    // wrap an old-style stream as the async data source.
    // This is *not* part of the readable stream interface.
    // It is an ugly unfortunate mess of history.
    Readable.prototype.wrap = function (stream) {
      var state = this._readableState;
      var paused = false;

      var self = this;
      stream.on('end', function () {
        debug('wrapped end');
        if (state.decoder && !state.ended) {
          var chunk = state.decoder.end();
          if (chunk && chunk.length) self.push(chunk);
        }

        self.push(null);
      });

      stream.on('data', function (chunk) {
        debug('wrapped data');
        if (state.decoder) chunk = state.decoder.write(chunk);

        // don't skip over falsy values in objectMode
        if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;

        var ret = self.push(chunk);
        if (!ret) {
          paused = true;
          stream.pause();
        }
      });

      // proxy all the other methods.
      // important when wrapping filters and duplexes.
      for (var i in stream) {
        if (this[i] === undefined && typeof stream[i] === 'function') {
          this[i] = function (method) {
            return function () {
              return stream[method].apply(stream, arguments);
            };
          }(i);
        }
      }

      // proxy certain important events.
      var events = ['error', 'close', 'destroy', 'pause', 'resume'];
      forEach(events, function (ev) {
        stream.on(ev, self.emit.bind(self, ev));
      });

      // when we try to consume some more bytes, simply unpause the
      // underlying stream.
      self._read = function (n) {
        debug('wrapped _read', n);
        if (paused) {
          paused = false;
          stream.resume();
        }
      };

      return self;
    };

    // exposed for testing purposes only.
    Readable._fromList = fromList;

    // Pluck off n bytes from an array of buffers.
    // Length is the combined lengths of all the buffers in the list.
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function fromList(n, state) {
      // nothing buffered
      if (state.length === 0) return null;

      var ret;
      if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {
        // read it all, truncate the list
        if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);
        state.buffer.clear();
      } else {
        // read part of list
        ret = fromListPartial(n, state.buffer, state.decoder);
      }

      return ret;
    }

    // Extracts only enough buffered data to satisfy the amount requested.
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function fromListPartial(n, list, hasStrings) {
      var ret;
      if (n < list.head.data.length) {
        // slice is the same for buffers and strings
        ret = list.head.data.slice(0, n);
        list.head.data = list.head.data.slice(n);
      } else if (n === list.head.data.length) {
        // first chunk is a perfect match
        ret = list.shift();
      } else {
        // result spans more than one buffer
        ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);
      }
      return ret;
    }

    // Copies a specified amount of characters from the list of buffered data
    // chunks.
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function copyFromBufferString(n, list) {
      var p = list.head;
      var c = 1;
      var ret = p.data;
      n -= ret.length;
      while (p = p.next) {
        var str = p.data;
        var nb = n > str.length ? str.length : n;
        if (nb === str.length) ret += str;else ret += str.slice(0, n);
        n -= nb;
        if (n === 0) {
          if (nb === str.length) {
            ++c;
            if (p.next) list.head = p.next;else list.head = list.tail = null;
          } else {
            list.head = p;
            p.data = str.slice(nb);
          }
          break;
        }
        ++c;
      }
      list.length -= c;
      return ret;
    }

    // Copies a specified amount of bytes from the list of buffered data chunks.
    // This function is designed to be inlinable, so please take care when making
    // changes to the function body.
    function copyFromBuffer(n, list) {
      var ret = Buffer.allocUnsafe(n);
      var p = list.head;
      var c = 1;
      p.data.copy(ret);
      n -= p.data.length;
      while (p = p.next) {
        var buf = p.data;
        var nb = n > buf.length ? buf.length : n;
        buf.copy(ret, ret.length - n, 0, nb);
        n -= nb;
        if (n === 0) {
          if (nb === buf.length) {
            ++c;
            if (p.next) list.head = p.next;else list.head = list.tail = null;
          } else {
            list.head = p;
            p.data = buf.slice(nb);
          }
          break;
        }
        ++c;
      }
      list.length -= c;
      return ret;
    }

    function endReadable(stream) {
      var state = stream._readableState;

      // If we get here before consuming all the bytes, then that is a
      // bug in node.  Should never happen.
      if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream');

      if (!state.endEmitted) {
        state.ended = true;
        nextTick(endReadableNT, state, stream);
      }
    }

    function endReadableNT(state, stream) {
      // Check that we didn't get one last unshift.
      if (!state.endEmitted && state.length === 0) {
        state.endEmitted = true;
        stream.readable = false;
        stream.emit('end');
      }
    }

    function forEach(xs, f) {
      for (var i = 0, l = xs.length; i < l; i++) {
        f(xs[i], i);
      }
    }

    function indexOf(xs, x) {
      for (var i = 0, l = xs.length; i < l; i++) {
        if (xs[i] === x) return i;
      }
      return -1;
    }

    // A bit simpler than readable streams.
    Writable.WritableState = WritableState;
    inherits$1(Writable, EventEmitter);

    function nop() {}

    function WriteReq(chunk, encoding, cb) {
      this.chunk = chunk;
      this.encoding = encoding;
      this.callback = cb;
      this.next = null;
    }

    function WritableState(options, stream) {
      Object.defineProperty(this, 'buffer', {
        get: deprecate(function () {
          return this.getBuffer();
        }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.')
      });
      options = options || {};

      // object stream flag to indicate whether or not this stream
      // contains buffers or objects.
      this.objectMode = !!options.objectMode;

      if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode;

      // the point at which write() starts returning false
      // Note: 0 is a valid value, means that we always return false if
      // the entire buffer is not flushed immediately on write()
      var hwm = options.highWaterMark;
      var defaultHwm = this.objectMode ? 16 : 16 * 1024;
      this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm;

      // cast to ints.
      this.highWaterMark = ~ ~this.highWaterMark;

      this.needDrain = false;
      // at the start of calling end()
      this.ending = false;
      // when end() has been called, and returned
      this.ended = false;
      // when 'finish' is emitted
      this.finished = false;

      // should we decode strings into buffers before passing to _write?
      // this is here so that some node-core streams can optimize string
      // handling at a lower level.
      var noDecode = options.decodeStrings === false;
      this.decodeStrings = !noDecode;

      // Crypto is kind of old and crusty.  Historically, its default string
      // encoding is 'binary' so we have to make this configurable.
      // Everything else in the universe uses 'utf8', though.
      this.defaultEncoding = options.defaultEncoding || 'utf8';

      // not an actual buffer we keep track of, but a measurement
      // of how much we're waiting to get pushed to some underlying
      // socket or file.
      this.length = 0;

      // a flag to see when we're in the middle of a write.
      this.writing = false;

      // when true all writes will be buffered until .uncork() call
      this.corked = 0;

      // a flag to be able to tell if the onwrite cb is called immediately,
      // or on a later tick.  We set this to true at first, because any
      // actions that shouldn't happen until "later" should generally also
      // not happen before the first write call.
      this.sync = true;

      // a flag to know if we're processing previously buffered items, which
      // may call the _write() callback in the same tick, so that we don't
      // end up in an overlapped onwrite situation.
      this.bufferProcessing = false;

      // the callback that's passed to _write(chunk,cb)
      this.onwrite = function (er) {
        onwrite(stream, er);
      };

      // the callback that the user supplies to write(chunk,encoding,cb)
      this.writecb = null;

      // the amount that is being written when _write is called.
      this.writelen = 0;

      this.bufferedRequest = null;
      this.lastBufferedRequest = null;

      // number of pending user-supplied write callbacks
      // this must be 0 before 'finish' can be emitted
      this.pendingcb = 0;

      // emit prefinish if the only thing we're waiting for is _write cbs
      // This is relevant for synchronous Transform streams
      this.prefinished = false;

      // True if the error was already emitted and should not be thrown again
      this.errorEmitted = false;

      // count buffered requests
      this.bufferedRequestCount = 0;

      // allocate the first CorkedRequest, there is always
      // one allocated and free to use, and we maintain at most two
      this.corkedRequestsFree = new CorkedRequest(this);
    }

    WritableState.prototype.getBuffer = function writableStateGetBuffer() {
      var current = this.bufferedRequest;
      var out = [];
      while (current) {
        out.push(current);
        current = current.next;
      }
      return out;
    };
    function Writable(options) {

      // Writable ctor is applied to Duplexes, though they're not
      // instanceof Writable, they're instanceof Readable.
      if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options);

      this._writableState = new WritableState(options, this);

      // legacy.
      this.writable = true;

      if (options) {
        if (typeof options.write === 'function') this._write = options.write;

        if (typeof options.writev === 'function') this._writev = options.writev;
      }

      EventEmitter.call(this);
    }

    // Otherwise people can pipe Writable streams, which is just wrong.
    Writable.prototype.pipe = function () {
      this.emit('error', new Error('Cannot pipe, not readable'));
    };

    function writeAfterEnd(stream, cb) {
      var er = new Error('write after end');
      // TODO: defer error events consistently everywhere, not just the cb
      stream.emit('error', er);
      nextTick(cb, er);
    }

    // If we get something that is not a buffer, string, null, or undefined,
    // and we're not in objectMode, then that's an error.
    // Otherwise stream chunks are all considered to be of length=1, and the
    // watermarks determine how many objects to keep in the buffer, rather than
    // how many bytes or characters.
    function validChunk(stream, state, chunk, cb) {
      var valid = true;
      var er = false;
      // Always throw error if a null is written
      // if we are not in object mode then throw
      // if it is not a buffer, string, or undefined.
      if (chunk === null) {
        er = new TypeError('May not write null values to stream');
      } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {
        er = new TypeError('Invalid non-string/buffer chunk');
      }
      if (er) {
        stream.emit('error', er);
        nextTick(cb, er);
        valid = false;
      }
      return valid;
    }

    Writable.prototype.write = function (chunk, encoding, cb) {
      var state = this._writableState;
      var ret = false;

      if (typeof encoding === 'function') {
        cb = encoding;
        encoding = null;
      }

      if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;

      if (typeof cb !== 'function') cb = nop;

      if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) {
        state.pendingcb++;
        ret = writeOrBuffer(this, state, chunk, encoding, cb);
      }

      return ret;
    };

    Writable.prototype.cork = function () {
      var state = this._writableState;

      state.corked++;
    };

    Writable.prototype.uncork = function () {
      var state = this._writableState;

      if (state.corked) {
        state.corked--;

        if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
      }
    };

    Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
      // node::ParseEncoding() requires lower case.
      if (typeof encoding === 'string') encoding = encoding.toLowerCase();
      if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);
      this._writableState.defaultEncoding = encoding;
      return this;
    };

    function decodeChunk(state, chunk, encoding) {
      if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {
        chunk = Buffer.from(chunk, encoding);
      }
      return chunk;
    }

    // if we're already writing something, then just put this
    // in the queue, and wait our turn.  Otherwise, call _write
    // If we return false, then we need a drain event, so set that flag.
    function writeOrBuffer(stream, state, chunk, encoding, cb) {
      chunk = decodeChunk(state, chunk, encoding);

      if (Buffer.isBuffer(chunk)) encoding = 'buffer';
      var len = state.objectMode ? 1 : chunk.length;

      state.length += len;

      var ret = state.length < state.highWaterMark;
      // we must ensure that previous needDrain will not be reset to false.
      if (!ret) state.needDrain = true;

      if (state.writing || state.corked) {
        var last = state.lastBufferedRequest;
        state.lastBufferedRequest = new WriteReq(chunk, encoding, cb);
        if (last) {
          last.next = state.lastBufferedRequest;
        } else {
          state.bufferedRequest = state.lastBufferedRequest;
        }
        state.bufferedRequestCount += 1;
      } else {
        doWrite(stream, state, false, len, chunk, encoding, cb);
      }

      return ret;
    }

    function doWrite(stream, state, writev, len, chunk, encoding, cb) {
      state.writelen = len;
      state.writecb = cb;
      state.writing = true;
      state.sync = true;
      if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);
      state.sync = false;
    }

    function onwriteError(stream, state, sync, er, cb) {
      --state.pendingcb;
      if (sync) nextTick(cb, er);else cb(er);

      stream._writableState.errorEmitted = true;
      stream.emit('error', er);
    }

    function onwriteStateUpdate(state) {
      state.writing = false;
      state.writecb = null;
      state.length -= state.writelen;
      state.writelen = 0;
    }

    function onwrite(stream, er) {
      var state = stream._writableState;
      var sync = state.sync;
      var cb = state.writecb;

      onwriteStateUpdate(state);

      if (er) onwriteError(stream, state, sync, er, cb);else {
        // Check if we're actually ready to finish, but don't emit yet
        var finished = needFinish(state);

        if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {
          clearBuffer(stream, state);
        }

        if (sync) {
          /*<replacement>*/
            nextTick(afterWrite, stream, state, finished, cb);
          /*</replacement>*/
        } else {
            afterWrite(stream, state, finished, cb);
          }
      }
    }

    function afterWrite(stream, state, finished, cb) {
      if (!finished) onwriteDrain(stream, state);
      state.pendingcb--;
      cb();
      finishMaybe(stream, state);
    }

    // Must force callback to be called on nextTick, so that we don't
    // emit 'drain' before the write() consumer gets the 'false' return
    // value, and has a chance to attach a 'drain' listener.
    function onwriteDrain(stream, state) {
      if (state.length === 0 && state.needDrain) {
        state.needDrain = false;
        stream.emit('drain');
      }
    }

    // if there's something in the buffer waiting, then process it
    function clearBuffer(stream, state) {
      state.bufferProcessing = true;
      var entry = state.bufferedRequest;

      if (stream._writev && entry && entry.next) {
        // Fast case, write everything using _writev()
        var l = state.bufferedRequestCount;
        var buffer = new Array(l);
        var holder = state.corkedRequestsFree;
        holder.entry = entry;

        var count = 0;
        while (entry) {
          buffer[count] = entry;
          entry = entry.next;
          count += 1;
        }

        doWrite(stream, state, true, state.length, buffer, '', holder.finish);

        // doWrite is almost always async, defer these to save a bit of time
        // as the hot path ends with doWrite
        state.pendingcb++;
        state.lastBufferedRequest = null;
        if (holder.next) {
          state.corkedRequestsFree = holder.next;
          holder.next = null;
        } else {
          state.corkedRequestsFree = new CorkedRequest(state);
        }
      } else {
        // Slow case, write chunks one-by-one
        while (entry) {
          var chunk = entry.chunk;
          var encoding = entry.encoding;
          var cb = entry.callback;
          var len = state.objectMode ? 1 : chunk.length;

          doWrite(stream, state, false, len, chunk, encoding, cb);
          entry = entry.next;
          // if we didn't call the onwrite immediately, then
          // it means that we need to wait until it does.
          // also, that means that the chunk and cb are currently
          // being processed, so move the buffer counter past them.
          if (state.writing) {
            break;
          }
        }

        if (entry === null) state.lastBufferedRequest = null;
      }

      state.bufferedRequestCount = 0;
      state.bufferedRequest = entry;
      state.bufferProcessing = false;
    }

    Writable.prototype._write = function (chunk, encoding, cb) {
      cb(new Error('not implemented'));
    };

    Writable.prototype._writev = null;

    Writable.prototype.end = function (chunk, encoding, cb) {
      var state = this._writableState;

      if (typeof chunk === 'function') {
        cb = chunk;
        chunk = null;
        encoding = null;
      } else if (typeof encoding === 'function') {
        cb = encoding;
        encoding = null;
      }

      if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);

      // .end() fully uncorks
      if (state.corked) {
        state.corked = 1;
        this.uncork();
      }

      // ignore unnecessary end() calls.
      if (!state.ending && !state.finished) endWritable(this, state, cb);
    };

    function needFinish(state) {
      return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;
    }

    function prefinish(stream, state) {
      if (!state.prefinished) {
        state.prefinished = true;
        stream.emit('prefinish');
      }
    }

    function finishMaybe(stream, state) {
      var need = needFinish(state);
      if (need) {
        if (state.pendingcb === 0) {
          prefinish(stream, state);
          state.finished = true;
          stream.emit('finish');
        } else {
          prefinish(stream, state);
        }
      }
      return need;
    }

    function endWritable(stream, state, cb) {
      state.ending = true;
      finishMaybe(stream, state);
      if (cb) {
        if (state.finished) nextTick(cb);else stream.once('finish', cb);
      }
      state.ended = true;
      stream.writable = false;
    }

    // It seems a linked list but it is not
    // there will be only 2 of these for each stream
    function CorkedRequest(state) {
      var _this = this;

      this.next = null;
      this.entry = null;

      this.finish = function (err) {
        var entry = _this.entry;
        _this.entry = null;
        while (entry) {
          var cb = entry.callback;
          state.pendingcb--;
          cb(err);
          entry = entry.next;
        }
        if (state.corkedRequestsFree) {
          state.corkedRequestsFree.next = _this;
        } else {
          state.corkedRequestsFree = _this;
        }
      };
    }

    inherits$1(Duplex, Readable);

    var keys = Object.keys(Writable.prototype);
    for (var v = 0; v < keys.length; v++) {
      var method = keys[v];
      if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
    }
    function Duplex(options) {
      if (!(this instanceof Duplex)) return new Duplex(options);

      Readable.call(this, options);
      Writable.call(this, options);

      if (options && options.readable === false) this.readable = false;

      if (options && options.writable === false) this.writable = false;

      this.allowHalfOpen = true;
      if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;

      this.once('end', onend);
    }

    // the no-half-open enforcer
    function onend() {
      // if we allow half-open state, or if the writable side ended,
      // then we're ok.
      if (this.allowHalfOpen || this._writableState.ended) return;

      // no more data can be written.
      // But allow more writes to happen in this tick.
      nextTick(onEndNT, this);
    }

    function onEndNT(self) {
      self.end();
    }

    // a transform stream is a readable/writable stream where you do
    inherits$1(Transform, Duplex);

    function TransformState(stream) {
      this.afterTransform = function (er, data) {
        return afterTransform(stream, er, data);
      };

      this.needTransform = false;
      this.transforming = false;
      this.writecb = null;
      this.writechunk = null;
      this.writeencoding = null;
    }

    function afterTransform(stream, er, data) {
      var ts = stream._transformState;
      ts.transforming = false;

      var cb = ts.writecb;

      if (!cb) return stream.emit('error', new Error('no writecb in Transform class'));

      ts.writechunk = null;
      ts.writecb = null;

      if (data !== null && data !== undefined) stream.push(data);

      cb(er);

      var rs = stream._readableState;
      rs.reading = false;
      if (rs.needReadable || rs.length < rs.highWaterMark) {
        stream._read(rs.highWaterMark);
      }
    }
    function Transform(options) {
      if (!(this instanceof Transform)) return new Transform(options);

      Duplex.call(this, options);

      this._transformState = new TransformState(this);

      // when the writable side finishes, then flush out anything remaining.
      var stream = this;

      // start out asking for a readable event once data is transformed.
      this._readableState.needReadable = true;

      // we have implemented the _read method, and done the other things
      // that Readable wants before the first _read call, so unset the
      // sync guard flag.
      this._readableState.sync = false;

      if (options) {
        if (typeof options.transform === 'function') this._transform = options.transform;

        if (typeof options.flush === 'function') this._flush = options.flush;
      }

      this.once('prefinish', function () {
        if (typeof this._flush === 'function') this._flush(function (er) {
          done(stream, er);
        });else done(stream);
      });
    }

    Transform.prototype.push = function (chunk, encoding) {
      this._transformState.needTransform = false;
      return Duplex.prototype.push.call(this, chunk, encoding);
    };

    // This is the part where you do stuff!
    // override this function in implementation classes.
    // 'chunk' is an input chunk.
    //
    // Call `push(newChunk)` to pass along transformed output
    // to the readable side.  You may call 'push' zero or more times.
    //
    // Call `cb(err)` when you are done with this chunk.  If you pass
    // an error, then that'll put the hurt on the whole operation.  If you
    // never call cb(), then you'll never get another chunk.
    Transform.prototype._transform = function (chunk, encoding, cb) {
      throw new Error('Not implemented');
    };

    Transform.prototype._write = function (chunk, encoding, cb) {
      var ts = this._transformState;
      ts.writecb = cb;
      ts.writechunk = chunk;
      ts.writeencoding = encoding;
      if (!ts.transforming) {
        var rs = this._readableState;
        if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);
      }
    };

    // Doesn't matter what the args are here.
    // _transform does all the work.
    // That we got here means that the readable side wants more data.
    Transform.prototype._read = function (n) {
      var ts = this._transformState;

      if (ts.writechunk !== null && ts.writecb && !ts.transforming) {
        ts.transforming = true;
        this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
      } else {
        // mark that we need a transform, so that any data that comes in
        // will get processed, now that we've asked for it.
        ts.needTransform = true;
      }
    };

    function done(stream, er) {
      if (er) return stream.emit('error', er);

      // if there's nothing in the write buffer, then that means
      // that nothing more will ever be provided
      var ws = stream._writableState;
      var ts = stream._transformState;

      if (ws.length) throw new Error('Calling transform done when ws.length != 0');

      if (ts.transforming) throw new Error('Calling transform done when still transforming');

      return stream.push(null);
    }

    inherits$1(PassThrough, Transform);
    function PassThrough(options) {
      if (!(this instanceof PassThrough)) return new PassThrough(options);

      Transform.call(this, options);
    }

    PassThrough.prototype._transform = function (chunk, encoding, cb) {
      cb(null, chunk);
    };

    inherits$1(Stream$1, EventEmitter);
    Stream$1.Readable = Readable;
    Stream$1.Writable = Writable;
    Stream$1.Duplex = Duplex;
    Stream$1.Transform = Transform;
    Stream$1.PassThrough = PassThrough;

    // Backwards-compat with node 0.4.x
    Stream$1.Stream = Stream$1;

    // old-style streams.  Note that the pipe method (the only relevant
    // part of this class) is overridden in the Readable class.

    function Stream$1() {
      EventEmitter.call(this);
    }

    Stream$1.prototype.pipe = function(dest, options) {
      var source = this;

      function ondata(chunk) {
        if (dest.writable) {
          if (false === dest.write(chunk) && source.pause) {
            source.pause();
          }
        }
      }

      source.on('data', ondata);

      function ondrain() {
        if (source.readable && source.resume) {
          source.resume();
        }
      }

      dest.on('drain', ondrain);

      // If the 'end' option is not supplied, dest.end() will be called when
      // source gets the 'end' or 'close' events.  Only dest.end() once.
      if (!dest._isStdio && (!options || options.end !== false)) {
        source.on('end', onend);
        source.on('close', onclose);
      }

      var didOnEnd = false;
      function onend() {
        if (didOnEnd) return;
        didOnEnd = true;

        dest.end();
      }


      function onclose() {
        if (didOnEnd) return;
        didOnEnd = true;

        if (typeof dest.destroy === 'function') dest.destroy();
      }

      // don't leave dangling pipes when there are errors.
      function onerror(er) {
        cleanup();
        if (EventEmitter.listenerCount(this, 'error') === 0) {
          throw er; // Unhandled stream error in pipe.
        }
      }

      source.on('error', onerror);
      dest.on('error', onerror);

      // remove all the event listeners that were added.
      function cleanup() {
        source.removeListener('data', ondata);
        dest.removeListener('drain', ondrain);

        source.removeListener('end', onend);
        source.removeListener('close', onclose);

        source.removeListener('error', onerror);
        dest.removeListener('error', onerror);

        source.removeListener('end', cleanup);
        source.removeListener('close', cleanup);

        dest.removeListener('close', cleanup);
      }

      source.on('end', cleanup);
      source.on('close', cleanup);

      dest.on('close', cleanup);

      dest.emit('pipe', source);

      // Allow for unix-like usage: A.pipe(B).pipe(C)
      return dest;
    };

    var _polyfillNode_stream = /*#__PURE__*/Object.freeze({
        __proto__: null,
        'default': Stream$1,
        Readable: Readable,
        Writable: Writable,
        Duplex: Duplex,
        Transform: Transform,
        PassThrough: PassThrough,
        Stream: Stream$1
    });

    var require$$1 = /*@__PURE__*/getAugmentedNamespace(_polyfillNode_stream);

    var require$$2 = /*@__PURE__*/getAugmentedNamespace(_polyfillNode_util$1);

    var assert$1 = require$$0;
    var Stream = require$$1.Stream;
    var util$2 = require$$2;
    var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
    function _capitalize(str) {
        return (str.charAt(0).toUpperCase() + str.slice(1));
    }
    function _toss(name, expected, oper, arg, actual) {
        throw new assert$1.AssertionError({
            message: util$2.format('%s (%s) is required', name, expected),
            actual: (actual === undefined) ? typeof (arg) : actual(arg),
            expected: expected,
            operator: oper || '===',
            stackStartFunction: _toss.caller
        });
    }
    function _getClass(arg) {
        return (Object.prototype.toString.call(arg).slice(8, -1));
    }
    function noop() {
    }
    var types = {
        bool: {
            check: function (arg) { return typeof (arg) === 'boolean'; }
        },
        func: {
            check: function (arg) { return typeof (arg) === 'function'; }
        },
        string: {
            check: function (arg) { return typeof (arg) === 'string'; }
        },
        object: {
            check: function (arg) {
                return typeof (arg) === 'object' && arg !== null;
            }
        },
        number: {
            check: function (arg) {
                return typeof (arg) === 'number' && !isNaN(arg);
            }
        },
        finite: {
            check: function (arg) {
                return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);
            }
        },
        buffer: {
            check: function (arg) { return isBuffer$2(arg); },
            operator: 'Buffer.isBuffer'
        },
        array: {
            check: function (arg) { return Array.isArray(arg); },
            operator: 'Array.isArray'
        },
        stream: {
            check: function (arg) { return arg instanceof Stream; },
            operator: 'instanceof',
            actual: _getClass
        },
        date: {
            check: function (arg) { return arg instanceof Date; },
            operator: 'instanceof',
            actual: _getClass
        },
        regexp: {
            check: function (arg) { return arg instanceof RegExp; },
            operator: 'instanceof',
            actual: _getClass
        },
        uuid: {
            check: function (arg) {
                return typeof (arg) === 'string' && UUID_REGEXP.test(arg);
            },
            operator: 'isUUID'
        }
    };
    function _setExports(ndebug) {
        var keys = Object.keys(types);
        var out;
        if (process$1.env.NODE_NDEBUG) {
            out = noop;
        } else {
            out = function (arg, msg) {
                if (!arg) {
                    _toss(msg, 'true', arg);
                }
            };
        }
        keys.forEach(function (k) {
            if (ndebug) {
                out[k] = noop;
                return;
            }
            var type = types[k];
            out[k] = function (arg, msg) {
                if (!type.check(arg)) {
                    _toss(msg, k, type.operator, arg, type.actual);
                }
            };
        });
        keys.forEach(function (k) {
            var name = 'optional' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            out[name] = function (arg, msg) {
                if (arg === undefined || arg === null) {
                    return;
                }
                if (!type.check(arg)) {
                    _toss(msg, k, type.operator, arg, type.actual);
                }
            };
        });
        keys.forEach(function (k) {
            var name = 'arrayOf' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            var expected = '[' + k + ']';
            out[name] = function (arg, msg) {
                if (!Array.isArray(arg)) {
                    _toss(msg, expected, type.operator, arg, type.actual);
                }
                var i;
                for (i = 0; i < arg.length; i++) {
                    if (!type.check(arg[i])) {
                        _toss(msg, expected, type.operator, arg, type.actual);
                    }
                }
            };
        });
        keys.forEach(function (k) {
            var name = 'optionalArrayOf' + _capitalize(k);
            if (ndebug) {
                out[name] = noop;
                return;
            }
            var type = types[k];
            var expected = '[' + k + ']';
            out[name] = function (arg, msg) {
                if (arg === undefined || arg === null) {
                    return;
                }
                if (!Array.isArray(arg)) {
                    _toss(msg, expected, type.operator, arg, type.actual);
                }
                var i;
                for (i = 0; i < arg.length; i++) {
                    if (!type.check(arg[i])) {
                        _toss(msg, expected, type.operator, arg, type.actual);
                    }
                }
            };
        });
        Object.keys(assert$1).forEach(function (k) {
            if (k === 'AssertionError') {
                out[k] = assert$1[k];
                return;
            }
            if (ndebug) {
                out[k] = noop;
                return;
            }
            out[k] = assert$1[k];
        });
        out._setExports = _setExports;
        return out;
    }
    var assert_1 = _setExports(process$1.env.NODE_NDEBUG);

    var jsprim$1 = {};

    var extsprintf$1 = {};

    var mod_assert$2 = require$$0;
    var mod_util$2 = require$$2;
    extsprintf$1.sprintf = jsSprintf$1;
    extsprintf$1.printf = jsPrintf$1;
    extsprintf$1.fprintf = jsFprintf$1;
    function jsSprintf$1(fmt)
    {
    	var regex = [
    	    '([^%]*)',
    	    '%',
    	    '([\'\\-+ #0]*?)',
    	    '([1-9]\\d*)?',
    	    '(\\.([1-9]\\d*))?',
    	    '[lhjztL]*?',
    	    '([diouxXfFeEgGaAcCsSp%jr])'
    	].join('');
    	var re = new RegExp(regex);
    	var args = Array.prototype.slice.call(arguments, 1);
    	var flags, width, precision, conversion;
    	var left, pad, sign, arg, match;
    	var ret = '';
    	var argn = 1;
    	mod_assert$2.equal('string', typeof (fmt));
    	while ((match = re.exec(fmt)) !== null) {
    		ret += match[1];
    		fmt = fmt.substring(match[0].length);
    		flags = match[2] || '';
    		width = match[3] || 0;
    		precision = match[4] || '';
    		conversion = match[6];
    		left = false;
    		sign = false;
    		pad = ' ';
    		if (conversion == '%') {
    			ret += '%';
    			continue;
    		}
    		if (args.length === 0)
    			throw (new Error('too few args to sprintf'));
    		arg = args.shift();
    		argn++;
    		if (flags.match(/[\' #]/))
    			throw (new Error(
    			    'unsupported flags: ' + flags));
    		if (precision.length > 0)
    			throw (new Error(
    			    'non-zero precision not supported'));
    		if (flags.match(/-/))
    			left = true;
    		if (flags.match(/0/))
    			pad = '0';
    		if (flags.match(/\+/))
    			sign = true;
    		switch (conversion) {
    		case 's':
    			if (arg === undefined || arg === null)
    				throw (new Error('argument ' + argn +
    				    ': attempted to print undefined or null ' +
    				    'as a string'));
    			ret += doPad$1(pad, width, left, arg.toString());
    			break;
    		case 'd':
    			arg = Math.floor(arg);
    		case 'f':
    			sign = sign && arg > 0 ? '+' : '';
    			ret += sign + doPad$1(pad, width, left,
    			    arg.toString());
    			break;
    		case 'x':
    			ret += doPad$1(pad, width, left, arg.toString(16));
    			break;
    		case 'j':
    			if (width === 0)
    				width = 10;
    			ret += mod_util$2.inspect(arg, false, width);
    			break;
    		case 'r':
    			ret += dumpException$1(arg);
    			break;
    		default:
    			throw (new Error('unsupported conversion: ' +
    			    conversion));
    		}
    	}
    	ret += fmt;
    	return (ret);
    }
    function jsPrintf$1() {
    	var args = Array.prototype.slice.call(arguments);
    	args.unshift(process$1.stdout);
    	jsFprintf$1.apply(null, args);
    }
    function jsFprintf$1(stream) {
    	var args = Array.prototype.slice.call(arguments, 1);
    	return (stream.write(jsSprintf$1.apply(this, args)));
    }
    function doPad$1(chr, width, left, str)
    {
    	var ret = str;
    	while (ret.length < width) {
    		if (left)
    			ret += chr;
    		else
    			ret = chr + ret;
    	}
    	return (ret);
    }
    function dumpException$1(ex)
    {
    	var ret;
    	if (!(ex instanceof Error))
    		throw (new Error(jsSprintf$1('invalid type for %%r: %j', ex)));
    	ret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack;
    	if (ex.cause && typeof (ex.cause) === 'function') {
    		var cex = ex.cause();
    		if (cex) {
    			ret += '\nCaused by: ' + dumpException$1(cex);
    		}
    	}
    	return (ret);
    }

    var extsprintf = {};

    var mod_assert$1 = require$$0;
    var mod_util$1 = require$$2;
    extsprintf.sprintf = jsSprintf;
    extsprintf.printf = jsPrintf;
    extsprintf.fprintf = jsFprintf;
    function jsSprintf(ofmt)
    {
    	var regex = [
    	    '([^%]*)',
    	    '%',
    	    '([\'\\-+ #0]*?)',
    	    '([1-9]\\d*)?',
    	    '(\\.([1-9]\\d*))?',
    	    '[lhjztL]*?',
    	    '([diouxXfFeEgGaAcCsSp%jr])'
    	].join('');
    	var re = new RegExp(regex);
    	var args = Array.prototype.slice.call(arguments, 1);
    	var fmt = ofmt;
    	var flags, width, precision, conversion;
    	var left, pad, sign, arg, match;
    	var ret = '';
    	var argn = 1;
    	var posn = 0;
    	var convposn;
    	var curconv;
    	mod_assert$1.equal('string', typeof (fmt),
    	    'first argument must be a format string');
    	while ((match = re.exec(fmt)) !== null) {
    		ret += match[1];
    		fmt = fmt.substring(match[0].length);
    		curconv = match[0].substring(match[1].length);
    		convposn = posn + match[1].length + 1;
    		posn += match[0].length;
    		flags = match[2] || '';
    		width = match[3] || 0;
    		precision = match[4] || '';
    		conversion = match[6];
    		left = false;
    		sign = false;
    		pad = ' ';
    		if (conversion == '%') {
    			ret += '%';
    			continue;
    		}
    		if (args.length === 0) {
    			throw (jsError(ofmt, convposn, curconv,
    			    'has no matching argument ' +
    			    '(too few arguments passed)'));
    		}
    		arg = args.shift();
    		argn++;
    		if (flags.match(/[\' #]/)) {
    			throw (jsError(ofmt, convposn, curconv,
    			    'uses unsupported flags'));
    		}
    		if (precision.length > 0) {
    			throw (jsError(ofmt, convposn, curconv,
    			    'uses non-zero precision (not supported)'));
    		}
    		if (flags.match(/-/))
    			left = true;
    		if (flags.match(/0/))
    			pad = '0';
    		if (flags.match(/\+/))
    			sign = true;
    		switch (conversion) {
    		case 's':
    			if (arg === undefined || arg === null) {
    				throw (jsError(ofmt, convposn, curconv,
    				    'attempted to print undefined or null ' +
    				    'as a string (argument ' + argn + ' to ' +
    				    'sprintf)'));
    			}
    			ret += doPad(pad, width, left, arg.toString());
    			break;
    		case 'd':
    			arg = Math.floor(arg);
    		case 'f':
    			sign = sign && arg > 0 ? '+' : '';
    			ret += sign + doPad(pad, width, left,
    			    arg.toString());
    			break;
    		case 'x':
    			ret += doPad(pad, width, left, arg.toString(16));
    			break;
    		case 'j':
    			if (width === 0)
    				width = 10;
    			ret += mod_util$1.inspect(arg, false, width);
    			break;
    		case 'r':
    			ret += dumpException(arg);
    			break;
    		default:
    			throw (jsError(ofmt, convposn, curconv,
    			    'is not supported'));
    		}
    	}
    	ret += fmt;
    	return (ret);
    }
    function jsError(fmtstr, convposn, curconv, reason) {
    	mod_assert$1.equal(typeof (fmtstr), 'string');
    	mod_assert$1.equal(typeof (curconv), 'string');
    	mod_assert$1.equal(typeof (convposn), 'number');
    	mod_assert$1.equal(typeof (reason), 'string');
    	return (new Error('format string "' + fmtstr +
    	    '": conversion specifier "' + curconv + '" at character ' +
    	    convposn + ' ' + reason));
    }
    function jsPrintf() {
    	var args = Array.prototype.slice.call(arguments);
    	args.unshift(process$1.stdout);
    	jsFprintf.apply(null, args);
    }
    function jsFprintf(stream) {
    	var args = Array.prototype.slice.call(arguments, 1);
    	return (stream.write(jsSprintf.apply(this, args)));
    }
    function doPad(chr, width, left, str)
    {
    	var ret = str;
    	while (ret.length < width) {
    		if (left)
    			ret += chr;
    		else
    			ret = chr + ret;
    	}
    	return (ret);
    }
    function dumpException(ex)
    {
    	var ret;
    	if (!(ex instanceof Error))
    		throw (new Error(jsSprintf('invalid type for %%r: %j', ex)));
    	ret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack;
    	if (ex.cause && typeof (ex.cause) === 'function') {
    		var cex = ex.cause();
    		if (cex) {
    			ret += '\nCaused by: ' + dumpException(cex);
    		}
    	}
    	return (ret);
    }

    var util$1 = {};

    function isArray(arg) {
      if (Array.isArray) {
        return Array.isArray(arg);
      }
      return objectToString(arg) === '[object Array]';
    }
    util$1.isArray = isArray;
    function isBoolean(arg) {
      return typeof arg === 'boolean';
    }
    util$1.isBoolean = isBoolean;
    function isNull(arg) {
      return arg === null;
    }
    util$1.isNull = isNull;
    function isNullOrUndefined(arg) {
      return arg == null;
    }
    util$1.isNullOrUndefined = isNullOrUndefined;
    function isNumber(arg) {
      return typeof arg === 'number';
    }
    util$1.isNumber = isNumber;
    function isString(arg) {
      return typeof arg === 'string';
    }
    util$1.isString = isString;
    function isSymbol(arg) {
      return typeof arg === 'symbol';
    }
    util$1.isSymbol = isSymbol;
    function isUndefined(arg) {
      return arg === void 0;
    }
    util$1.isUndefined = isUndefined;
    function isRegExp(re) {
      return objectToString(re) === '[object RegExp]';
    }
    util$1.isRegExp = isRegExp;
    function isObject(arg) {
      return typeof arg === 'object' && arg !== null;
    }
    util$1.isObject = isObject;
    function isDate(d) {
      return objectToString(d) === '[object Date]';
    }
    util$1.isDate = isDate;
    function isError(e) {
      return (objectToString(e) === '[object Error]' || e instanceof Error);
    }
    util$1.isError = isError;
    function isFunction(arg) {
      return typeof arg === 'function';
    }
    util$1.isFunction = isFunction;
    function isPrimitive(arg) {
      return arg === null ||
             typeof arg === 'boolean' ||
             typeof arg === 'number' ||
             typeof arg === 'string' ||
             typeof arg === 'symbol' ||
             typeof arg === 'undefined';
    }
    util$1.isPrimitive = isPrimitive;
    util$1.isBuffer = isBuffer$2;
    function objectToString(o) {
      return Object.prototype.toString.call(o);
    }

    var mod_assertplus = assert_1;
    var mod_util = require$$2;
    var mod_extsprintf$1 = extsprintf;
    var mod_isError = util$1.isError;
    var sprintf = mod_extsprintf$1.sprintf;
    var verror = VError;
    VError.VError = VError;
    VError.SError = SError;
    VError.WError = WError;
    VError.MultiError = MultiError;
    function parseConstructorArguments(args)
    {
    	var argv, options, sprintf_args, shortmessage, k;
    	mod_assertplus.object(args, 'args');
    	mod_assertplus.bool(args.strict, 'args.strict');
    	mod_assertplus.array(args.argv, 'args.argv');
    	argv = args.argv;
    	if (argv.length === 0) {
    		options = {};
    		sprintf_args = [];
    	} else if (mod_isError(argv[0])) {
    		options = { 'cause': argv[0] };
    		sprintf_args = argv.slice(1);
    	} else if (typeof (argv[0]) === 'object') {
    		options = {};
    		for (k in argv[0]) {
    			options[k] = argv[0][k];
    		}
    		sprintf_args = argv.slice(1);
    	} else {
    		mod_assertplus.string(argv[0],
    		    'first argument to VError, SError, or WError ' +
    		    'constructor must be a string, object, or Error');
    		options = {};
    		sprintf_args = argv;
    	}
    	mod_assertplus.object(options);
    	if (!options.strict && !args.strict) {
    		sprintf_args = sprintf_args.map(function (a) {
    			return (a === null ? 'null' :
    			    a === undefined ? 'undefined' : a);
    		});
    	}
    	if (sprintf_args.length === 0) {
    		shortmessage = '';
    	} else {
    		shortmessage = sprintf.apply(null, sprintf_args);
    	}
    	return ({
    	    'options': options,
    	    'shortmessage': shortmessage
    	});
    }
    function VError()
    {
    	var args, obj, parsed, cause, ctor, message, k;
    	args = Array.prototype.slice.call(arguments, 0);
    	if (!(this instanceof VError)) {
    		obj = Object.create(VError.prototype);
    		VError.apply(obj, arguments);
    		return (obj);
    	}
    	parsed = parseConstructorArguments({
    	    'argv': args,
    	    'strict': false
    	});
    	if (parsed.options.name) {
    		mod_assertplus.string(parsed.options.name,
    		    'error\'s "name" must be a string');
    		this.name = parsed.options.name;
    	}
    	this.jse_shortmsg = parsed.shortmessage;
    	message = parsed.shortmessage;
    	cause = parsed.options.cause;
    	if (cause) {
    		mod_assertplus.ok(mod_isError(cause), 'cause is not an Error');
    		this.jse_cause = cause;
    		if (!parsed.options.skipCauseMessage) {
    			message += ': ' + cause.message;
    		}
    	}
    	this.jse_info = {};
    	if (parsed.options.info) {
    		for (k in parsed.options.info) {
    			this.jse_info[k] = parsed.options.info[k];
    		}
    	}
    	this.message = message;
    	Error.call(this, message);
    	if (Error.captureStackTrace) {
    		ctor = parsed.options.constructorOpt || this.constructor;
    		Error.captureStackTrace(this, ctor);
    	}
    	return (this);
    }
    mod_util.inherits(VError, Error);
    VError.prototype.name = 'VError';
    VError.prototype.toString = function ve_toString()
    {
    	var str = (this.hasOwnProperty('name') && this.name ||
    		this.constructor.name || this.constructor.prototype.name);
    	if (this.message)
    		str += ': ' + this.message;
    	return (str);
    };
    VError.prototype.cause = function ve_cause()
    {
    	var cause = VError.cause(this);
    	return (cause === null ? undefined : cause);
    };
    VError.cause = function (err)
    {
    	mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    	return (mod_isError(err.jse_cause) ? err.jse_cause : null);
    };
    VError.info = function (err)
    {
    	var rv, cause, k;
    	mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    	cause = VError.cause(err);
    	if (cause !== null) {
    		rv = VError.info(cause);
    	} else {
    		rv = {};
    	}
    	if (typeof (err.jse_info) == 'object' && err.jse_info !== null) {
    		for (k in err.jse_info) {
    			rv[k] = err.jse_info[k];
    		}
    	}
    	return (rv);
    };
    VError.findCauseByName = function (err, name)
    {
    	var cause;
    	mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    	mod_assertplus.string(name, 'name');
    	mod_assertplus.ok(name.length > 0, 'name cannot be empty');
    	for (cause = err; cause !== null; cause = VError.cause(cause)) {
    		mod_assertplus.ok(mod_isError(cause));
    		if (cause.name == name) {
    			return (cause);
    		}
    	}
    	return (null);
    };
    VError.hasCauseWithName = function (err, name)
    {
    	return (VError.findCauseByName(err, name) !== null);
    };
    VError.fullStack = function (err)
    {
    	mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    	var cause = VError.cause(err);
    	if (cause) {
    		return (err.stack + '\ncaused by: ' + VError.fullStack(cause));
    	}
    	return (err.stack);
    };
    VError.errorFromList = function (errors)
    {
    	mod_assertplus.arrayOfObject(errors, 'errors');
    	if (errors.length === 0) {
    		return (null);
    	}
    	errors.forEach(function (e) {
    		mod_assertplus.ok(mod_isError(e));
    	});
    	if (errors.length == 1) {
    		return (errors[0]);
    	}
    	return (new MultiError(errors));
    };
    VError.errorForEach = function (err, func)
    {
    	mod_assertplus.ok(mod_isError(err), 'err must be an Error');
    	mod_assertplus.func(func, 'func');
    	if (err instanceof MultiError) {
    		err.errors().forEach(function iterError(e) { func(e); });
    	} else {
    		func(err);
    	}
    };
    function SError()
    {
    	var args, obj, parsed, options;
    	args = Array.prototype.slice.call(arguments, 0);
    	if (!(this instanceof SError)) {
    		obj = Object.create(SError.prototype);
    		SError.apply(obj, arguments);
    		return (obj);
    	}
    	parsed = parseConstructorArguments({
    	    'argv': args,
    	    'strict': true
    	});
    	options = parsed.options;
    	VError.call(this, options, '%s', parsed.shortmessage);
    	return (this);
    }
    mod_util.inherits(SError, VError);
    function MultiError(errors)
    {
    	mod_assertplus.array(errors, 'list of errors');
    	mod_assertplus.ok(errors.length > 0, 'must be at least one error');
    	this.ase_errors = errors;
    	VError.call(this, {
    	    'cause': errors[0]
    	}, 'first of %d error%s', errors.length, errors.length == 1 ? '' : 's');
    }
    mod_util.inherits(MultiError, VError);
    MultiError.prototype.name = 'MultiError';
    MultiError.prototype.errors = function me_errors()
    {
    	return (this.ase_errors.slice(0));
    };
    function WError()
    {
    	var args, obj, parsed, options;
    	args = Array.prototype.slice.call(arguments, 0);
    	if (!(this instanceof WError)) {
    		obj = Object.create(WError.prototype);
    		WError.apply(obj, args);
    		return (obj);
    	}
    	parsed = parseConstructorArguments({
    	    'argv': args,
    	    'strict': false
    	});
    	options = parsed.options;
    	options['skipCauseMessage'] = true;
    	VError.call(this, options, '%s', parsed.shortmessage);
    	return (this);
    }
    mod_util.inherits(WError, VError);
    WError.prototype.name = 'WError';
    WError.prototype.toString = function we_toString()
    {
    	var str = (this.hasOwnProperty('name') && this.name ||
    		this.constructor.name || this.constructor.prototype.name);
    	if (this.message)
    		str += ': ' + this.message;
    	if (this.jse_cause && this.jse_cause.message)
    		str += '; caused by ' + this.jse_cause.toString();
    	return (str);
    };
    WError.prototype.cause = function we_cause(c)
    {
    	if (mod_isError(c))
    		this.jse_cause = c;
    	return (this.jse_cause);
    };

    var validate = {exports: {}};

    (function (module) {
    (function (root, factory) {
        if (module.exports) {
            module.exports = factory();
        } else {
            root.jsonSchema = factory();
        }
    }(commonjsGlobal, function () {
    var exports = validate;
    exports.Integer = {type:"integer"};
    var primitiveConstructors = {
    	String: String,
    	Boolean: Boolean,
    	Number: Number,
    	Object: Object,
    	Array: Array,
    	Date: Date
    };
    exports.validate = validate;
    function validate(instance,schema) {
    		return validate(instance, schema, {changing: false});
    	}exports.checkPropertyChange = function(value,schema, property) {
    		return validate(value, schema, {changing: property || "property"});
    	};
    var validate = exports._validate = function(instance,schema,options) {
    	if (!options) options = {};
    	var _changing = options.changing;
    	function getType(schema){
    		return schema.type || (primitiveConstructors[schema.name] == schema && schema.name.toLowerCase());
    	}
    	var errors = [];
    	function checkProp(value, schema, path,i){
    		var l;
    		path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i;
    		function addError(message){
    			errors.push({property:path,message:message});
    		}
    		if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function') && !(schema && getType(schema))){
    			if(typeof schema == 'function'){
    				if(!(value instanceof schema)){
    					addError("is not an instance of the class/constructor " + schema.name);
    				}
    			}else if(schema){
    				addError("Invalid schema/property definition " + schema);
    			}
    			return null;
    		}
    		if(_changing && schema.readonly){
    			addError("is a readonly field, it can not be changed");
    		}
    		if(schema['extends']){
    			checkProp(value,schema['extends'],path,i);
    		}
    		function checkType(type,value){
    			if(type){
    				if(typeof type == 'string' && type != 'any' &&
    						(type == 'null' ? value !== null : typeof value != type) &&
    						!(value instanceof Array && type == 'array') &&
    						!(value instanceof Date && type == 'date') &&
    						!(type == 'integer' && value%1===0)){
    					return [{property:path,message:value + " - " + (typeof value) + " value found, but a " + type + " is required"}];
    				}
    				if(type instanceof Array){
    					var unionErrors=[];
    					for(var j = 0; j < type.length; j++){
    						if(!(unionErrors=checkType(type[j],value)).length){
    							break;
    						}
    					}
    					if(unionErrors.length){
    						return unionErrors;
    					}
    				}else if(typeof type == 'object'){
    					var priorErrors = errors;
    					errors = [];
    					checkProp(value,type,path);
    					var theseErrors = errors;
    					errors = priorErrors;
    					return theseErrors;
    				}
    			}
    			return [];
    		}
    		if(value === undefined){
    			if(schema.required){
    				addError("is missing and it is required");
    			}
    		}else {
    			errors = errors.concat(checkType(getType(schema),value));
    			if(schema.disallow && !checkType(schema.disallow,value).length){
    				addError(" disallowed value was matched");
    			}
    			if(value !== null){
    				if(value instanceof Array){
    					if(schema.items){
    						var itemsIsArray = schema.items instanceof Array;
    						var propDef = schema.items;
    						for (i = 0, l = value.length; i < l; i += 1) {
    							if (itemsIsArray)
    								propDef = schema.items[i];
    							if (options.coerce)
    								value[i] = options.coerce(value[i], propDef);
    							errors.concat(checkProp(value[i],propDef,path,i));
    						}
    					}
    					if(schema.minItems && value.length < schema.minItems){
    						addError("There must be a minimum of " + schema.minItems + " in the array");
    					}
    					if(schema.maxItems && value.length > schema.maxItems){
    						addError("There must be a maximum of " + schema.maxItems + " in the array");
    					}
    				}else if(schema.properties || schema.additionalProperties){
    					errors.concat(checkObj(value, schema.properties, path, schema.additionalProperties));
    				}
    				if(schema.pattern && typeof value == 'string' && !value.match(schema.pattern)){
    					addError("does not match the regex pattern " + schema.pattern);
    				}
    				if(schema.maxLength && typeof value == 'string' && value.length > schema.maxLength){
    					addError("may only be " + schema.maxLength + " characters long");
    				}
    				if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){
    					addError("must be at least " + schema.minLength + " characters long");
    				}
    				if(typeof schema.minimum !== 'undefined' && typeof value == typeof schema.minimum &&
    						schema.minimum > value){
    					addError("must have a minimum value of " + schema.minimum);
    				}
    				if(typeof schema.maximum !== 'undefined' && typeof value == typeof schema.maximum &&
    						schema.maximum < value){
    					addError("must have a maximum value of " + schema.maximum);
    				}
    				if(schema['enum']){
    					var enumer = schema['enum'];
    					l = enumer.length;
    					var found;
    					for(var j = 0; j < l; j++){
    						if(enumer[j]===value){
    							found=1;
    							break;
    						}
    					}
    					if(!found){
    						addError("does not have a value in the enumeration " + enumer.join(", "));
    					}
    				}
    				if(typeof schema.maxDecimal == 'number' &&
    					(value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){
    					addError("may only have " + schema.maxDecimal + " digits of decimal places");
    				}
    			}
    		}
    		return null;
    	}
    	function checkObj(instance,objTypeDef,path,additionalProp){
    		if(typeof objTypeDef =='object'){
    			if(typeof instance != 'object' || instance instanceof Array){
    				errors.push({property:path,message:"an object is required"});
    			}
    			for(var i in objTypeDef){
    				if(objTypeDef.hasOwnProperty(i) && i != '__proto__' && i != 'constructor'){
    					var value = instance.hasOwnProperty(i) ? instance[i] : undefined;
    					if (value === undefined && options.existingOnly) continue;
    					var propDef = objTypeDef[i];
    					if(value === undefined && propDef["default"]){
    						value = instance[i] = propDef["default"];
    					}
    					if(options.coerce && i in instance){
    						value = instance[i] = options.coerce(value, propDef);
    					}
    					checkProp(value,propDef,path,i);
    				}
    			}
    		}
    		for(i in instance){
    			if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){
    				if (options.filter) {
    					delete instance[i];
    					continue;
    				} else {
    					errors.push({property:path,message:"The property " + i +
    						" is not defined in the schema and the schema does not allow additional properties"});
    				}
    			}
    			var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires;
    			if(requires && !(requires in instance)){
    				errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"});
    			}
    			value = instance[i];
    			if(additionalProp && (!(objTypeDef && typeof objTypeDef == 'object') || !(i in objTypeDef))){
    				if(options.coerce){
    					value = instance[i] = options.coerce(value, additionalProp);
    				}
    				checkProp(value,additionalProp,path,i);
    			}
    			if(!_changing && value && value.$schema){
    				errors = errors.concat(checkProp(value,value.$schema,path,i));
    			}
    		}
    		return errors;
    	}
    	if(schema){
    		checkProp(instance,schema,'',_changing || '');
    	}
    	if(!_changing && instance && instance.$schema){
    		checkProp(instance,instance.$schema,'','');
    	}
    	return {valid:!errors.length,errors:errors};
    };
    exports.mustBeValid = function(result){
    	if(!result.valid){
    		throw new TypeError(result.errors.map(function(error){return "for property " + error.property + ': ' + error.message;}).join(", \n"));
    	}
    };
    return exports;
    }));
    }(validate));

    var mod_assert = assert_1;
    var mod_extsprintf = extsprintf$1;
    var mod_verror = verror;
    var mod_jsonschema = validate.exports;
    jsprim$1.deepCopy = deepCopy;
    jsprim$1.deepEqual = deepEqual;
    jsprim$1.isEmpty = isEmpty;
    jsprim$1.hasKey = hasKey;
    jsprim$1.forEachKey = forEachKey;
    jsprim$1.pluck = pluck;
    jsprim$1.flattenObject = flattenObject;
    jsprim$1.flattenIter = flattenIter;
    jsprim$1.validateJsonObject = validateJsonObjectJS;
    jsprim$1.validateJsonObjectJS = validateJsonObjectJS;
    jsprim$1.randElt = randElt;
    jsprim$1.extraProperties = extraProperties;
    jsprim$1.mergeObjects = mergeObjects;
    jsprim$1.startsWith = startsWith;
    jsprim$1.endsWith = endsWith;
    jsprim$1.parseInteger = parseInteger;
    jsprim$1.iso8601 = iso8601;
    jsprim$1.rfc1123 = rfc1123;
    jsprim$1.parseDateTime = parseDateTime;
    jsprim$1.hrtimediff = hrtimeDiff;
    jsprim$1.hrtimeDiff = hrtimeDiff;
    jsprim$1.hrtimeAccum = hrtimeAccum;
    jsprim$1.hrtimeAdd = hrtimeAdd;
    jsprim$1.hrtimeNanosec = hrtimeNanosec;
    jsprim$1.hrtimeMicrosec = hrtimeMicrosec;
    jsprim$1.hrtimeMillisec = hrtimeMillisec;
    function deepCopy(obj)
    {
    	var ret, key;
    	var marker = '__deepCopy';
    	if (obj && obj[marker])
    		throw (new Error('attempted deep copy of cyclic object'));
    	if (obj && obj.constructor == Object) {
    		ret = {};
    		obj[marker] = true;
    		for (key in obj) {
    			if (key == marker)
    				continue;
    			ret[key] = deepCopy(obj[key]);
    		}
    		delete (obj[marker]);
    		return (ret);
    	}
    	if (obj && obj.constructor == Array) {
    		ret = [];
    		obj[marker] = true;
    		for (key = 0; key < obj.length; key++)
    			ret.push(deepCopy(obj[key]));
    		delete (obj[marker]);
    		return (ret);
    	}
    	return (obj);
    }
    function deepEqual(obj1, obj2)
    {
    	if (typeof (obj1) != typeof (obj2))
    		return (false);
    	if (obj1 === null || obj2 === null || typeof (obj1) != 'object')
    		return (obj1 === obj2);
    	if (obj1.constructor != obj2.constructor)
    		return (false);
    	var k;
    	for (k in obj1) {
    		if (!(k in obj2))
    			return (false);
    		if (!deepEqual(obj1[k], obj2[k]))
    			return (false);
    	}
    	for (k in obj2) {
    		if (!(k in obj1))
    			return (false);
    	}
    	return (true);
    }
    function isEmpty(obj)
    {
    	var key;
    	for (key in obj)
    		return (false);
    	return (true);
    }
    function hasKey(obj, key)
    {
    	mod_assert.equal(typeof (key), 'string');
    	return (Object.prototype.hasOwnProperty.call(obj, key));
    }
    function forEachKey(obj, callback)
    {
    	for (var key in obj) {
    		if (hasKey(obj, key)) {
    			callback(key, obj[key]);
    		}
    	}
    }
    function pluck(obj, key)
    {
    	mod_assert.equal(typeof (key), 'string');
    	return (pluckv(obj, key));
    }
    function pluckv(obj, key)
    {
    	if (obj === null || typeof (obj) !== 'object')
    		return (undefined);
    	if (obj.hasOwnProperty(key))
    		return (obj[key]);
    	var i = key.indexOf('.');
    	if (i == -1)
    		return (undefined);
    	var key1 = key.substr(0, i);
    	if (!obj.hasOwnProperty(key1))
    		return (undefined);
    	return (pluckv(obj[key1], key.substr(i + 1)));
    }
    function flattenIter(data, depth, callback)
    {
    	doFlattenIter(data, depth, [], callback);
    }
    function doFlattenIter(data, depth, accum, callback)
    {
    	var each;
    	var key;
    	if (depth === 0) {
    		each = accum.slice(0);
    		each.push(data);
    		callback(each);
    		return;
    	}
    	mod_assert.ok(data !== null);
    	mod_assert.equal(typeof (data), 'object');
    	mod_assert.equal(typeof (depth), 'number');
    	mod_assert.ok(depth >= 0);
    	for (key in data) {
    		each = accum.slice(0);
    		each.push(key);
    		doFlattenIter(data[key], depth - 1, each, callback);
    	}
    }
    function flattenObject(data, depth)
    {
    	if (depth === 0)
    		return ([ data ]);
    	mod_assert.ok(data !== null);
    	mod_assert.equal(typeof (data), 'object');
    	mod_assert.equal(typeof (depth), 'number');
    	mod_assert.ok(depth >= 0);
    	var rv = [];
    	var key;
    	for (key in data) {
    		flattenObject(data[key], depth - 1).forEach(function (p) {
    			rv.push([ key ].concat(p));
    		});
    	}
    	return (rv);
    }
    function startsWith(str, prefix)
    {
    	return (str.substr(0, prefix.length) == prefix);
    }
    function endsWith(str, suffix)
    {
    	return (str.substr(
    	    str.length - suffix.length, suffix.length) == suffix);
    }
    function iso8601(d)
    {
    	if (typeof (d) == 'number')
    		d = new Date(d);
    	mod_assert.ok(d.constructor === Date);
    	return (mod_extsprintf.sprintf('%4d-%02d-%02dT%02d:%02d:%02d.%03dZ',
    	    d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(),
    	    d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(),
    	    d.getUTCMilliseconds()));
    }
    var RFC1123_MONTHS = [
        'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
        'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var RFC1123_DAYS = [
        'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    function rfc1123(date) {
    	return (mod_extsprintf.sprintf('%s, %02d %s %04d %02d:%02d:%02d GMT',
    	    RFC1123_DAYS[date.getUTCDay()], date.getUTCDate(),
    	    RFC1123_MONTHS[date.getUTCMonth()], date.getUTCFullYear(),
    	    date.getUTCHours(), date.getUTCMinutes(),
    	    date.getUTCSeconds()));
    }
    function parseDateTime(str)
    {
    	var numeric = +str;
    	if (!isNaN(numeric)) {
    		return (new Date(numeric));
    	} else {
    		return (new Date(str));
    	}
    }
    var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
    var MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
    var PI_DEFAULTS = {
    	base: 10,
    	allowSign: true,
    	allowPrefix: false,
    	allowTrailing: false,
    	allowImprecise: false,
    	trimWhitespace: false,
    	leadingZeroIsOctal: false
    };
    var CP_0 = 0x30;
    var CP_9 = 0x39;
    var CP_A = 0x41;
    var CP_B = 0x42;
    var CP_O = 0x4f;
    var CP_T = 0x54;
    var CP_X = 0x58;
    var CP_Z = 0x5a;
    var CP_a = 0x61;
    var CP_b = 0x62;
    var CP_o = 0x6f;
    var CP_t = 0x74;
    var CP_x = 0x78;
    var CP_z = 0x7a;
    var PI_CONV_DEC = 0x30;
    var PI_CONV_UC = 0x37;
    var PI_CONV_LC = 0x57;
    function parseInteger(str, uopts)
    {
    	mod_assert.string(str, 'str');
    	mod_assert.optionalObject(uopts, 'options');
    	var baseOverride = false;
    	var options = PI_DEFAULTS;
    	if (uopts) {
    		baseOverride = hasKey(uopts, 'base');
    		options = mergeObjects(options, uopts);
    		mod_assert.number(options.base, 'options.base');
    		mod_assert.ok(options.base >= 2, 'options.base >= 2');
    		mod_assert.ok(options.base <= 36, 'options.base <= 36');
    		mod_assert.bool(options.allowSign, 'options.allowSign');
    		mod_assert.bool(options.allowPrefix, 'options.allowPrefix');
    		mod_assert.bool(options.allowTrailing,
    		    'options.allowTrailing');
    		mod_assert.bool(options.allowImprecise,
    		    'options.allowImprecise');
    		mod_assert.bool(options.trimWhitespace,
    		    'options.trimWhitespace');
    		mod_assert.bool(options.leadingZeroIsOctal,
    		    'options.leadingZeroIsOctal');
    		if (options.leadingZeroIsOctal) {
    			mod_assert.ok(!baseOverride,
    			    '"base" and "leadingZeroIsOctal" are ' +
    			    'mutually exclusive');
    		}
    	}
    	var c;
    	var pbase = -1;
    	var base = options.base;
    	var start;
    	var mult = 1;
    	var value = 0;
    	var idx = 0;
    	var len = str.length;
    	if (options.trimWhitespace) {
    		while (idx < len && isSpace(str.charCodeAt(idx))) {
    			++idx;
    		}
    	}
    	if (options.allowSign) {
    		if (str[idx] === '-') {
    			idx += 1;
    			mult = -1;
    		} else if (str[idx] === '+') {
    			idx += 1;
    		}
    	}
    	if (str[idx] === '0') {
    		if (options.allowPrefix) {
    			pbase = prefixToBase(str.charCodeAt(idx + 1));
    			if (pbase !== -1 && (!baseOverride || pbase === base)) {
    				base = pbase;
    				idx += 2;
    			}
    		}
    		if (pbase === -1 && options.leadingZeroIsOctal) {
    			base = 8;
    		}
    	}
    	for (start = idx; idx < len; ++idx) {
    		c = translateDigit(str.charCodeAt(idx));
    		if (c !== -1 && c < base) {
    			value *= base;
    			value += c;
    		} else {
    			break;
    		}
    	}
    	if (start === idx) {
    		return (new Error('invalid number: ' + JSON.stringify(str)));
    	}
    	if (options.trimWhitespace) {
    		while (idx < len && isSpace(str.charCodeAt(idx))) {
    			++idx;
    		}
    	}
    	if (idx < len && !options.allowTrailing) {
    		return (new Error('trailing characters after number: ' +
    		    JSON.stringify(str.slice(idx))));
    	}
    	if (value === 0) {
    		return (0);
    	}
    	var result = value * mult;
    	if (!options.allowImprecise &&
    	    (value > MAX_SAFE_INTEGER || result < MIN_SAFE_INTEGER)) {
    		return (new Error('number is outside of the supported range: ' +
    		    JSON.stringify(str.slice(start, idx))));
    	}
    	return (result);
    }
    function translateDigit(d)
    {
    	if (d >= CP_0 && d <= CP_9) {
    		return (d - PI_CONV_DEC);
    	} else if (d >= CP_A && d <= CP_Z) {
    		return (d - PI_CONV_UC);
    	} else if (d >= CP_a && d <= CP_z) {
    		return (d - PI_CONV_LC);
    	} else {
    		return (-1);
    	}
    }
    function isSpace(c)
    {
    	return (c === 0x20) ||
    	    (c >= 0x0009 && c <= 0x000d) ||
    	    (c === 0x00a0) ||
    	    (c === 0x1680) ||
    	    (c === 0x180e) ||
    	    (c >= 0x2000 && c <= 0x200a) ||
    	    (c === 0x2028) ||
    	    (c === 0x2029) ||
    	    (c === 0x202f) ||
    	    (c === 0x205f) ||
    	    (c === 0x3000) ||
    	    (c === 0xfeff);
    }
    function prefixToBase(c)
    {
    	if (c === CP_b || c === CP_B) {
    		return (2);
    	} else if (c === CP_o || c === CP_O) {
    		return (8);
    	} else if (c === CP_t || c === CP_T) {
    		return (10);
    	} else if (c === CP_x || c === CP_X) {
    		return (16);
    	} else {
    		return (-1);
    	}
    }
    function validateJsonObjectJS(schema, input)
    {
    	var report = mod_jsonschema.validate(input, schema);
    	if (report.errors.length === 0)
    		return (null);
    	var error = report.errors[0];
    	var propname = error['property'];
    	var reason = error['message'].toLowerCase();
    	var i, j;
    	if ((i = reason.indexOf('the property ')) != -1 &&
    	    (j = reason.indexOf(' is not defined in the schema and the ' +
    	    'schema does not allow additional properties')) != -1) {
    		i += 'the property '.length;
    		if (propname === '')
    			propname = reason.substr(i, j - i);
    		else
    			propname = propname + '.' + reason.substr(i, j - i);
    		reason = 'unsupported property';
    	}
    	var rv = new mod_verror.VError('property "%s": %s', propname, reason);
    	rv.jsv_details = error;
    	return (rv);
    }
    function randElt(arr)
    {
    	mod_assert.ok(Array.isArray(arr) && arr.length > 0,
    	    'randElt argument must be a non-empty array');
    	return (arr[Math.floor(Math.random() * arr.length)]);
    }
    function assertHrtime(a)
    {
    	mod_assert.ok(a[0] >= 0 && a[1] >= 0,
    	    'negative numbers not allowed in hrtimes');
    	mod_assert.ok(a[1] < 1e9, 'nanoseconds column overflow');
    }
    function hrtimeDiff(a, b)
    {
    	assertHrtime(a);
    	assertHrtime(b);
    	mod_assert.ok(a[0] > b[0] || (a[0] == b[0] && a[1] >= b[1]),
    	    'negative differences not allowed');
    	var rv = [ a[0] - b[0], 0 ];
    	if (a[1] >= b[1]) {
    		rv[1] = a[1] - b[1];
    	} else {
    		rv[0]--;
    		rv[1] = 1e9 - (b[1] - a[1]);
    	}
    	return (rv);
    }
    function hrtimeNanosec(a)
    {
    	assertHrtime(a);
    	return (Math.floor(a[0] * 1e9 + a[1]));
    }
    function hrtimeMicrosec(a)
    {
    	assertHrtime(a);
    	return (Math.floor(a[0] * 1e6 + a[1] / 1e3));
    }
    function hrtimeMillisec(a)
    {
    	assertHrtime(a);
    	return (Math.floor(a[0] * 1e3 + a[1] / 1e6));
    }
    function hrtimeAccum(a, b)
    {
    	assertHrtime(a);
    	assertHrtime(b);
    	a[1] += b[1];
    	if (a[1] >= 1e9) {
    		a[0]++;
    		a[1] -= 1e9;
    	}
    	a[0] += b[0];
    	return (a);
    }
    function hrtimeAdd(a, b)
    {
    	assertHrtime(a);
    	var rv = [ a[0], a[1] ];
    	return (hrtimeAccum(rv, b));
    }
    function extraProperties(obj, allowed)
    {
    	mod_assert.ok(typeof (obj) === 'object' && obj !== null,
    	    'obj argument must be a non-null object');
    	mod_assert.ok(Array.isArray(allowed),
    	    'allowed argument must be an array of strings');
    	for (var i = 0; i < allowed.length; i++) {
    		mod_assert.ok(typeof (allowed[i]) === 'string',
    		    'allowed argument must be an array of strings');
    	}
    	return (Object.keys(obj).filter(function (key) {
    		return (allowed.indexOf(key) === -1);
    	}));
    }
    function mergeObjects(provided, overrides, defaults)
    {
    	var rv, k;
    	rv = {};
    	if (defaults) {
    		for (k in defaults)
    			rv[k] = defaults[k];
    	}
    	if (provided) {
    		for (k in provided)
    			rv[k] = provided[k];
    	}
    	if (overrides) {
    		for (k in overrides)
    			rv[k] = overrides[k];
    	}
    	return (rv);
    }

    var assert = assert_1;
    var jsprim = jsprim$1;
    var util = require$$2;
    function ParseError(input, message, index) {
      if (Error.captureStackTrace)
        Error.captureStackTrace(this, ParseError);
      this.input = input;
      this.message = message;
      if (index !== undefined) {
        this.message += ' at index ' + index;
      }
    }
    util.inherits(ParseError, Error);
    function modulo(a, n) {
      return (n + (a % n)) % n;
    }
    function _arrayToOctetString(input) {
      var out;
      out = (input[0] >> 8) + '.' + (input[0] & 0xff) + '.';
      out += (input[1] >> 8) + '.' + (input[1] & 0xff);
      return out;
    }
    function _isAddr(addr) {
      if (typeof (addr) === 'object') {
        if (Array.isArray(addr._fields) && typeof (addr._attrs) === 'object') {
          return true;
        }
      }
      return false;
    }
    function _toAddr(input) {
      if (typeof (input) === 'string') {
        return ip6addrParse(input);
      } else if (_isAddr(input)) {
        return input;
      } else {
        throw new Error('Invalid argument: Addr or parsable string expected');
      }
    }
    function _arrayToHex(input, zeroElide, zeroPad) {
      var i;
      var elStart = null;
      var elLen = 0;
      if (zeroElide) {
        var start = null;
        var len = null;
        for (i = 0; i < input.length; i++) {
          if (input[i] === 0) {
            if (start === null) {
              start = i;
              len = 1;
            } else {
              len++;
            }
          } else if (start !== null) {
            if (len > elLen) {
              elStart = start;
              elLen = len;
            }
            start = null;
          }
        }
        if (start !== null && len > elLen) {
          elStart = start;
          elLen = len;
        }
      }
      var output = [];
      var num;
      for (i = 0; i < input.length; i++) {
        if (elStart !== null) {
          if (i === elStart) {
            if (elLen === 8) {
              return ['::'];
            } else if (elStart === 0 || elStart + elLen === input.length) {
              output.push(':');
            } else {
              output.push('');
            }
          }
          if (i >= elStart && i < elStart + elLen) {
            continue;
          }
        }
        num = input[i].toString(16);
        if (zeroPad && num.length != 4) {
          num = '0000'.slice(num.length) + num;
        }
        output.push(num);
      }
      return output;
    }
    function _ipv4Mapped(input) {
      var comp = [0, 0, 0, 0, 0, 0xffff];
      var i;
      for (i = 0; i < 6; i++) {
        if (input[i] != comp[i])
          return false;
      }
      return true;
    }
    function _prefixToAddr(len) {
      assert.number(len);
      len = len | 0;
      assert.ok(len <= 128);
      assert.ok(len >= 0);
      var output = new Addr();
      var i;
      for (i = 0; len > 16; i++, len -= 16) {
        output._fields[i] = 0xffff;
      }
      if (len > 0) {
        output._fields[i] = 0xffff - ((1 << (16 - len)) - 1);
      }
      return output;
    }
    function _toCIDR(input) {
      if (typeof (input) === 'string') {
        return new CIDR(input);
      } else if (input instanceof CIDR) {
        return input;
      } else {
        throw new Error('Invalid argument: CIDR or parsable string expected');
      }
    }
    var strDefaults = {
      format: 'auto',
      zeroElide: true,
      zeroPad: false
    };
    function getStrOpt(opts, name) {
      if (opts && opts.hasOwnProperty(name)) {
        return opts[name];
      } else {
        return strDefaults[name];
      }
    }
    function Addr() {
      this._fields = [0, 0, 0, 0, 0, 0, 0, 0];
      this._attrs = {};
    }
    Addr.prototype.kind = function getKind() {
      if (v4subnet.contains(this)) {
        return 'ipv4';
      } else {
        return 'ipv6';
      }
    };
    Addr.prototype.toString = function toString(opts) {
      assert.optionalObject(opts, 'opts');
      var format = getStrOpt(opts, 'format');
      var zeroElide = getStrOpt(opts, 'zeroElide');
      var zeroPad = getStrOpt(opts, 'zeroPad');
      assert.string(format, 'opts.format');
      assert.bool(zeroElide, 'opts.zeroElide');
      assert.bool(zeroPad, 'opts.zeroPad');
      if (format === 'auto') {
        if (this._attrs.ipv4Bare) {
          format = 'v4';
        } else if (this._attrs.ipv4Mapped) {
          format = 'v4-mapped';
        } else {
          format = 'v6';
        }
      }
      switch (format) {
      case 'v4':
        if (!v4subnet.contains(this)) {
            throw new Error('cannot print non-v4 address in dotted quad notation');
        }
        return _arrayToOctetString(this._fields.slice(6));
      case 'v4-mapped':
        if (!v4subnet.contains(this)) {
            throw new Error('cannot print non-v4 address as a v4-mapped address');
        }
        var output = _arrayToHex(this._fields.slice(0, 6), zeroElide, zeroPad);
        output.push(_arrayToOctetString(this._fields.slice(6)));
        return output.join(':');
      case 'v6':
        return _arrayToHex(this._fields, zeroElide, zeroPad).join(':');
      default:
        throw new Error('unrecognized format method "' + format + '"');
      }
    };
    Addr.prototype.toBuffer = function toBuffer(buf) {
      if (buf !== undefined) {
        if (!isBuffer$2(buf)) {
          throw new Error('optional arg must be Buffer');
        }
      } else {
        buf = new Buffer$1(16);
      }
      var i;
      for (i = 0; i < 8; i++) {
        buf.writeUInt16BE(this._fields[i], i*2);
      }
      return buf;
    };
    Addr.prototype.toLong = function toLong() {
      if (!v4subnet.contains(this)) {
        throw new Error('only possible for ipv4-mapped addresses');
      }
      return ((this._fields[6] << 16) >>> 0) + this._fields[7];
    };
    Addr.prototype.clone = function cloneAddr() {
      var out = new Addr();
      out._fields = this._fields.slice();
      for (var k in this._attrs) {
          out._attrs[k] = this._attrs[k];
      }
      return out;
    };
    Addr.prototype.offset = function offset(num) {
      if (num < -4294967295 || num > 4294967295) {
        throw new Error('offsets should be between -4294967295 and 4294967295');
      }
      var out = this.clone();
      var i, moved;
      for (i = 7; i >= 0; i--) {
        moved = out._fields[i] + num;
        if (moved > 65535) {
          num = moved >>> 16;
          moved = moved & 0xffff;
        } else if (moved < 0) {
          num = Math.floor(moved / (1 << 16));
          moved = modulo(moved, 1 << 16);
        } else {
          num = 0;
        }
        out._fields[i] = moved;
        if (num !== 0) {
          if ((i === 0) || (i === 6 && this._attrs.ipv4Mapped)) {
            return null;
          }
        } else {
          break;
        }
      }
      return out;
    };
    Addr.prototype.and = function addrAnd(input) {
      input = _toAddr(input);
      var i;
      var output = this.clone();
      for (i = 0; i < 8; i++) {
        output._fields[i] = output._fields[i] & input._fields[i];
      }
      return output;
    };
    Addr.prototype.or = function addrOr(input) {
      input = _toAddr(input);
      var i;
      var output = this.clone();
      for (i = 0; i < 8; i++) {
        output._fields[i] = output._fields[i] | input._fields[i];
      }
      return output;
    };
    Addr.prototype.not = function addrNot() {
      var i;
      var output = this.clone();
      for (i = 0; i < 8; i++) {
        output._fields[i] = (~ output._fields[i]) & 0xffff;
      }
      return output;
    };
    Addr.prototype.compare = function compareMember(addr) {
      return ip6addrCompare(this, addr);
    };
    function CIDR(addr, prefixLen) {
      if (prefixLen === undefined) {
        assert.string(addr);
        var fields = addr.match(/^([a-fA-F0-9:.]+)\/([0-9]+)$/);
        if (fields === null) {
          throw new Error('Invalid argument: <addr>/<prefix> expected');
        }
        addr = fields[1];
        prefixLen = parseInt(fields[2], 10);
      }
      assert.number(prefixLen);
      prefixLen = prefixLen | 0;
      addr = _toAddr(addr);
      if (addr._attrs.ipv4Bare) {
        prefixLen += 96;
      }
      if (prefixLen < 0 || prefixLen > 128) {
        throw new Error('Invalid prefix length');
      }
      this._prefix = prefixLen;
      this._mask = _prefixToAddr(prefixLen);
      this._addr = addr.and(this._mask);
    }
    CIDR.prototype.contains = function cidrContains(input) {
      input = _toAddr(input);
      return (this._addr.compare(input.and(this._mask)) === 0);
    };
    CIDR.prototype.first = function cidrFirst() {
      if (this._prefix >= 127) {
        return this._addr;
      } else {
        return this._addr.offset(1);
      }
    };
    CIDR.prototype.last = function cidrLast() {
      var ending = this._addr.or(this._mask.not());
      if (this._prefix >= 127) {
        return ending;
      } else {
        if (this._addr._attrs.ipv4Mapped) {
          return ending.offset(-1);
        } else {
          return ending;
        }
      }
    };
    CIDR.prototype.broadcast = function getBroadcast() {
      if (!v4subnet.contains(this._addr)) {
        throw new Error('Only IPv4 networks have broadcast addresses');
      }
      return this._addr.or(this._mask.not());
    };
    CIDR.prototype.compare = function compareCIDR(cidr) {
      return ip6cidrCompare(this, cidr);
    };
    CIDR.prototype.prefixLength = function getPrefixLength(format) {
      assert.optionalString(format, 'format');
      if (format === undefined || format === 'auto') {
        format = this._addr._attrs.ipv4Bare ? 'v4' : 'v6';
      }
      switch (format) {
      case 'v4':
        if (!v4subnet.contains(this._addr)) {
            throw new Error('cannot return v4 prefix length for non-v4 address');
        }
        return this._prefix - 96;
      case 'v6':
        return this._prefix;
      default:
        throw new Error('unrecognized format method "' + format + '"');
      }
    };
    CIDR.prototype.address = function getAddressComponent() {
      return this._addr;
    };
    CIDR.prototype.toString = function cidrString(opts) {
      assert.optionalObject(opts, 'opts');
      var format = getStrOpt(opts, 'format');
      if (format === 'v4-mapped') {
        format = 'v6';
      }
      return this._addr.toString(opts) + '/' + this.prefixLength(format);
    };
    var v4subnet = new CIDR('::ffff:0:0', 96);
    function ip6cidrCompare(a, b) {
      a = _toCIDR(a);
      b = _toCIDR(b);
      var cmp = ip6addrCompare(a._addr, b._addr);
      return cmp === 0 ? b._prefix - a._prefix : cmp;
    }
    function AddrRange(begin, end) {
      begin = _toAddr(begin);
      end = _toAddr(end);
      if (begin.compare(end) > 0) {
        throw new Error('begin address must be <= end address');
      }
      this._begin = begin;
      this._end = end;
    }
    AddrRange.prototype.contains = function addrRangeContains(input) {
      input = _toAddr(input);
      return (this._begin.compare(input) <= 0 && this._end.compare(input) >= 0);
    };
    AddrRange.prototype.first = function addrRangeFirst() {
      return this._begin;
    };
    AddrRange.prototype.last = function addrRangeLast() {
      return this._end;
    };
    function ip6addrParse(input) {
      if (typeof (input) === 'string') {
        return parseString(input);
      } else if (typeof (input) === 'number') {
        return parseLong(input);
      } else if (typeof (input) === 'object' && _isAddr(input)) {
        return input;
      } else {
        throw new Error('Invalid argument: only string|number allowed');
      }
    }
    function parseString(input) {
      assert.string(input);
      input = input.toLowerCase();
      var result = new Addr();
      var ip6Fields = [];
      var ip4Fields = [];
      var expIndex = null;
      var value = '';
      var i, c;
      if (input.length > 40) {
        throw new ParseError(input, 'Input too long');
      }
      for (i = 0; i < input.length; i++) {
        c = input[i];
        if (c === ':') {
          if ((i+1) < input.length && input[i+1] === ':') {
            if (expIndex !== null) {
              throw new ParseError(input, 'Multiple :: delimiters', i);
            }
            if (value !== '') {
              ip6Fields.push(value);
              value = '';
            }
            expIndex = ip6Fields.length;
            i++;
          } else {
            if (value === '') {
              throw new ParseError(input, 'illegal delimiter', i);
            }
            ip6Fields.push(value);
            value = '';
          }
        } else if (c === '.') {
          ip4Fields.push(value);
          value = '';
        } else {
          value = value + c;
        }
      }
      if (value !== '') {
        if (ip4Fields.length !== 0) {
          ip4Fields.push(value);
        } else {
          ip6Fields.push(value);
        }
        value = '';
      } else {
        if (expIndex !== ip6Fields.length || ip4Fields.length > 0) {
          throw new ParseError(input, 'Cannot end with delimiter besides ::');
        }
      }
      if (ip4Fields.length === 0) {
        if (ip6Fields.length > 8) {
          throw new ParseError(input, 'Too many fields');
        } else if (ip6Fields.length < 8 && expIndex === null) {
          throw new ParseError(input, 'Too few fields');
        }
      } else {
        if (ip4Fields.length !== 4) {
          throw new ParseError(input, 'IPv4 portion must have 4 fields');
        }
        if (ip6Fields.length === 0 && expIndex === null) {
          result._attrs.ipv4Bare = true;
          ip6Fields = ['ffff'];
          expIndex = 0;
        }
        if (ip6Fields.length > 6) {
          throw new ParseError(input, 'Too many fields');
        } else if (ip6Fields.length < 6 && expIndex === null) {
          throw new ParseError(input, 'Too few fields');
        }
      }
      var field, num;
      for (i = 0; i < ip6Fields.length; i++) {
        field = ip6Fields[i];
        num = jsprim.parseInteger(field, { base: 16, allowSign: false });
        if (num instanceof Error || num < 0 || num > 65535) {
          throw new ParseError(input, 'Invalid field value: ' + field);
        }
        ip6Fields[i] = num;
      }
      for (i = 0; i < ip4Fields.length; i++) {
        field = ip4Fields[i];
        num = jsprim.parseInteger(field, { base: 10, allowSign: false });
        if (num instanceof Error || num < 0 || num > 255) {
          throw new ParseError(input, 'Invalid field value: ' + field);
        }
        ip4Fields[i] = num;
      }
      if (ip4Fields.length !== 0) {
        ip6Fields.push((ip4Fields[0]*256) + ip4Fields[1]);
        ip6Fields.push((ip4Fields[2]*256) + ip4Fields[3]);
      }
      if (ip6Fields.length < 8 && expIndex !== null) {
        var filler = [];
        for (i = 0; i < (8 - ip6Fields.length); i++) {
          filler.push(0);
        }
        ip6Fields = Array.prototype.concat(
          ip6Fields.slice(0, expIndex),
          filler,
          ip6Fields.slice(expIndex)
        );
      }
      if (ip4Fields.length !== 0) {
        if (!_ipv4Mapped(ip6Fields)) {
          throw new ParseError(input, 'invalid dotted-quad notation');
        } else {
          result._attrs.ipv4Mapped = true;
        }
      }
      result._fields = ip6Fields;
      return result;
    }
    function parseLong(input) {
      assert.number(input);
      if (input !== Math.floor(input)) {
        throw new Error('Value must be integer');
      }
      if (input < 0 || input > 0xffffffff) {
        throw new Error('Value must be 32 bit');
      }
      var out = new Addr();
      out._fields[7] = input & 0xffff;
      out._fields[6] = (input >>> 16);
      out._fields[5] = 0xffff;
      out._attrs.ipv4Bare = true;
      out._attrs.ipv4Mapped = true;
      return out;
    }
    function ip6addrCompare(a, b) {
      a = _toAddr(a);
      b = _toAddr(b);
      var i;
      for (i = 0; i < 8; i++) {
        if (a._fields[i] < b._fields[i]) {
          return -1;
        } else if (a._fields[i] > b._fields[i]) {
          return 1;
        }
      }
      return 0;
    }
    var ip6addr = {
      parse: ip6addrParse,
      compare: ip6addrCompare,
      createCIDR: function (addr, len) {
        return new CIDR(addr, len);
      },
      compareCIDR: ip6cidrCompare,
      createAddrRange: function (begin, end) {
        return new AddrRange(begin, end);
      }
    };

    /**
     * This is the base class representing double values modifiers
     */
    var BaseValuesModifier = /** @class */ (function () {
        /**
         * Parses the values string
         *
         * @param values - values string
         *
         * @throws an error if the string is empty or invalid
         */
        function BaseValuesModifier(values) {
            /**
             * Separator between values
             */
            this.SEPARATOR = '|';
            if (!values) {
                throw new SyntaxError('Modifier cannot be empty');
            }
            this.value = values;
            var permittedValues = [];
            var restrictedValues = [];
            var parts = values.split(this.SEPARATOR);
            for (var i = 0; i < parts.length; i += 1) {
                var app = parts[i];
                var restricted = false;
                if (app.startsWith('~')) {
                    restricted = true;
                    app = app.substring(1).trim();
                }
                if (app === '') {
                    throw new SyntaxError("Empty values specified in \"".concat(values, "\""));
                }
                if (restricted) {
                    restrictedValues.push(app);
                }
                else {
                    permittedValues.push(app);
                }
            }
            this.restricted = restrictedValues.length > 0 ? restrictedValues : null;
            this.permitted = permittedValues.length > 0 ? permittedValues : null;
        }
        BaseValuesModifier.prototype.getPermitted = function () {
            return this.permitted;
        };
        BaseValuesModifier.prototype.getRestricted = function () {
            return this.restricted;
        };
        BaseValuesModifier.prototype.getValue = function () {
            return this.value;
        };
        BaseValuesModifier.prototype.match = function (value) {
            if (!this.restricted && !this.permitted) {
                return true;
            }
            if (this.restricted && this.restricted.includes(value)) {
                return false;
            }
            if (this.permitted) {
                return this.permitted.includes(value);
            }
            return true;
        };
        return BaseValuesModifier;
    }());

    /**
     * Netmasks class
     */
    var NetmasksCollection = /** @class */ (function () {
        function NetmasksCollection() {
            this.ipv4Masks = [];
            this.ipv6Masks = [];
        }
        /**
         * Returns true if any of the containing masks contains provided value
         *
         * @param value
         */
        NetmasksCollection.prototype.contains = function (value) {
            if (isIp_1.v4(value)) {
                return this.ipv4Masks.some(function (x) { return x.contains(value); });
            }
            return this.ipv6Masks.some(function (x) { return x.contains(value); });
        };
        return NetmasksCollection;
    }());
    /**
     * The client modifier allows specifying clients this rule will be working for.
     * It accepts client names (not ClientIDs), IP addresses, or CIDR ranges.
     */
    var ClientModifier = /** @class */ (function (_super) {
        __extends(ClientModifier, _super);
        /**
         * Constructor
         *
         * @param value
         */
        function ClientModifier(value) {
            var _this = _super.call(this, value) || this;
            var permitted = _this.getPermitted();
            if (permitted) {
                _this.permitted = ClientModifier.stripValues(permitted);
                _this.permittedNetmasks = ClientModifier.parseNetmasks(_this.permitted);
            }
            var restricted = _this.getRestricted();
            if (restricted) {
                _this.restricted = ClientModifier.stripValues(restricted);
                _this.restrictedNetmasks = ClientModifier.parseNetmasks(_this.restricted);
            }
            return _this;
        }
        /**
         * Unquotes and unescapes string
         *
         * @param values
         */
        ClientModifier.stripValues = function (values) {
            return values.map(function (v) {
                if ((v.startsWith('"') && v.endsWith('"'))
                    || (v.startsWith('\'') && v.endsWith('\''))) {
                    // eslint-disable-next-line no-param-reassign
                    v = v.substr(1, v.length - 2);
                }
                return v.replace(/\\/ig, '');
            });
        };
        /**
         * Checks if this modifier matches provided params
         *
         * @param clientName
         * @param clientIP
         */
        ClientModifier.prototype.matchAny = function (clientName, clientIP) {
            if (this.restricted) {
                if (clientName && this.restricted.includes(clientName)) {
                    return false;
                }
                if (clientIP && this.restricted.includes(clientIP)) {
                    return false;
                }
                return true;
            }
            if (this.restrictedNetmasks) {
                if (clientIP && this.restrictedNetmasks.contains(clientIP)) {
                    return false;
                }
                return true;
            }
            if (this.permitted) {
                if (clientName && this.permitted.includes(clientName)) {
                    return true;
                }
                if (clientIP && this.permitted.includes(clientIP)) {
                    return true;
                }
            }
            if (this.permittedNetmasks) {
                if (clientIP && this.permittedNetmasks.contains(clientIP)) {
                    return true;
                }
            }
            return false;
        };
        /**
         * Parses netmasks from client's strings
         *
         * @param values
         */
        ClientModifier.parseNetmasks = function (values) {
            var result = new NetmasksCollection();
            values.forEach(function (x) {
                var cidrVersion = isCidr(x);
                if (cidrVersion === 4) {
                    result.ipv4Masks.push(new Netmask_1(x));
                }
                else if (cidrVersion === 6) {
                    result.ipv6Masks.push(ip6addr.createCIDR(x));
                }
            });
            return result;
        };
        return ClientModifier;
    }(BaseValuesModifier));

    /**
     * The dnsrewrite response modifier allows replacing the content of the response
     * to the DNS request for the matching hosts.
     *
     * TODO: This modifier is not yet implemented
     * https://github.com/AdguardTeam/AdGuardHome/wiki/Hosts-Blocklists#dnsrewrite
     */
    var DnsRewriteModifier = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param value
         */
        function DnsRewriteModifier(value) {
            this.value = value;
        }
        /**
         * Modifier value
         */
        DnsRewriteModifier.prototype.getValue = function () {
            return this.value;
        };
        return DnsRewriteModifier;
    }());

    /**
     * The dnstype modifier allows specifying DNS request type on which this rule will be triggered.
     */
    var DnsTypeModifier = /** @class */ (function (_super) {
        __extends(DnsTypeModifier, _super);
        /**
         * Constructor
         *
         * @param value
         */
        function DnsTypeModifier(value) {
            var _this = _super.call(this, value) || this;
            if (_this.permitted) {
                _this.restricted = null;
            }
            return _this;
        }
        return DnsTypeModifier;
    }(BaseValuesModifier));

    /**
     * The ctag modifier allows to block domains only for specific types of DNS client tags.
     */
    var CtagModifier = /** @class */ (function (_super) {
        __extends(CtagModifier, _super);
        /**
         * Constructor
         *
         * @param value
         */
        function CtagModifier(value) {
            var _this = _super.call(this, value) || this;
            _this.validate();
            return _this;
        }
        /**
         * Validates tag values
         */
        CtagModifier.prototype.validate = function () {
            if (!this.getValue()) {
                throw new Error('Invalid rule: Ctag modifier must not be empty');
            }
            var tags = this.permitted ? this.permitted : this.restricted;
            if (tags && tags.some(function (x) { return !CtagModifier.ALLOWED_TAGS.includes(x); })) {
                throw new Error('Invalid rule: Invalid ctag modifier');
            }
        };
        /**
         * The list of allowed tags
         */
        CtagModifier.ALLOWED_TAGS = [
            // By device type:
            'device_audio',
            'device_camera',
            'device_gameconsole',
            'device_laptop',
            'device_nas',
            'device_pc',
            'device_phone',
            'device_printer',
            'device_securityalarm',
            'device_tablet',
            'device_tv',
            'device_other',
            // By operating system:
            'os_android',
            'os_ios',
            'os_linux',
            'os_macos',
            'os_windows',
            'os_other',
            // By user group:
            'user_admin',
            'user_regular',
            'user_child',
        ];
        return CtagModifier;
    }(BaseValuesModifier));

    /**
     * Rule pattern class
     *
     * This class parses rule pattern text to simple fields.
     */
    var Pattern = /** @class */ (function () {
        /**
         * Constructor
         * @param pattern
         * @param matchcase
         */
        function Pattern(pattern, matchcase) {
            if (matchcase === void 0) { matchcase = false; }
            this.pattern = pattern;
            this.shortcut = SimpleRegex.extractShortcut(this.pattern);
            this.matchcase = matchcase;
        }
        /**
         * Checks if this rule pattern matches the specified request.
         *
         * @param request - request to check
         * @param shortcutMatched if true, it means that the request already matches
         * this pattern's shortcut and we don't need to match it again.
         * @returns true if pattern matches
         */
        Pattern.prototype.matchPattern = function (request, shortcutMatched) {
            this.prepare();
            if (this.patternShortcut) {
                return shortcutMatched || this.matchShortcut(request.urlLowercase);
            }
            if (this.hostname) {
                // If we have a `||example.org^` rule, it's easier to match
                // against the request's hostname only without matching
                // a regular expression.
                return request.hostname === this.hostname
                    || ( // First light check without new string memory allocation
                    request.hostname.endsWith(this.hostname)
                        // Strict check
                        && request.hostname.endsWith(".".concat(this.hostname)));
            }
            // If the regular expression is invalid, just return false right away.
            if (this.regexInvalid || !this.regex) {
                return false;
            }
            // This is needed for DNS filtering only, not used in browser blocking.
            if (this.shouldMatchHostname(request)) {
                return this.regex.test(request.hostname);
            }
            return this.regex.test(request.url);
        };
        /**
         * Checks if this rule pattern matches the specified relative path string.
         * This method is used in cosmetic rules to implement the $path modifier matching logic.
         *
         * @param path - path to check
         * @returns true if pattern matches
         */
        Pattern.prototype.matchPathPattern = function (path) {
            this.prepare();
            if (this.hostname) {
                return false;
            }
            if (this.patternShortcut) {
                return this.matchShortcut(path);
            }
            // If the regular expression is invalid, just return false right away.
            if (this.regexInvalid || !this.regex) {
                return false;
            }
            return this.regex.test(path);
        };
        /**
         * matchShortcut simply checks if shortcut is a substring of the URL.
         * @param request - request to check.
         */
        Pattern.prototype.matchShortcut = function (str) {
            return str.indexOf(this.shortcut) >= 0;
        };
        /**
         * Prepares this pattern
         */
        Pattern.prototype.prepare = function () {
            if (this.prepared) {
                return;
            }
            this.prepared = true;
            // If shortcut and pattern are the same, we don't need to actually compile
            // a regex and can simply use matchShortcut instead.
            if (this.pattern === this.shortcut) {
                this.patternShortcut = true;
                return;
            }
            // Rules like `/example/*` are rather often in the real-life filters,
            // we might want to process them.
            if (this.pattern.startsWith(this.shortcut)
                && this.pattern.length === this.shortcut.length + 1
                && this.pattern.endsWith('*')) {
                this.patternShortcut = true;
                return;
            }
            if (this.pattern.startsWith(SimpleRegex.MASK_START_URL)
                && this.pattern.endsWith(SimpleRegex.MASK_SEPARATOR)
                && this.pattern.indexOf('*') < 0
                && this.pattern.indexOf('/') < 0) {
                this.hostname = this.pattern.slice(2, this.pattern.length - 1);
                return;
            }
            this.compileRegex();
        };
        /**
         * Compiles this pattern regex
         */
        Pattern.prototype.compileRegex = function () {
            var regexText = SimpleRegex.patternToRegexp(this.pattern);
            try {
                var flags = 'i';
                if (this.matchcase) {
                    flags = '';
                }
                this.regex = new RegExp(regexText, flags);
            }
            catch (e) {
                this.regexInvalid = true;
            }
        };
        /**
         * Checks if we should match hostnames and not the URL
         * this is important for the cases when we use urlfilter for DNS-level blocking
         * Note, that even though we may work on a DNS-level, we should still sometimes match full URL instead
         *
         * @param request
         */
        Pattern.prototype.shouldMatchHostname = function (request) {
            if (!request.isHostnameRequest) {
                return false;
            }
            return !this.isPatternDomainSpecific();
        };
        /**
         * In case pattern starts with the following it targets some specific domain
         */
        Pattern.prototype.isPatternDomainSpecific = function () {
            if (this.patternDomainSpecific === undefined) {
                this.patternDomainSpecific = this.pattern.startsWith(SimpleRegex.MASK_START_URL)
                    || this.pattern.startsWith('http://')
                    || this.pattern.startsWith('https:/')
                    || this.pattern.startsWith('://');
            }
            return this.patternDomainSpecific;
        };
        return Pattern;
    }());

    /**
     * NetworkRuleOption is the enumeration of various rule options.
     * In order to save memory, we store some options as a flag.
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#modifiers
     */
    exports.NetworkRuleOption = void 0;
    (function (NetworkRuleOption) {
        /** $third-party modifier */
        NetworkRuleOption[NetworkRuleOption["ThirdParty"] = 1] = "ThirdParty";
        /** $match-case modifier */
        NetworkRuleOption[NetworkRuleOption["MatchCase"] = 2] = "MatchCase";
        /** $important modifier */
        NetworkRuleOption[NetworkRuleOption["Important"] = 4] = "Important";
        // Allowlist rules modifiers
        // Each of them can disable part of the functionality
        /** $elemhide modifier */
        NetworkRuleOption[NetworkRuleOption["Elemhide"] = 8] = "Elemhide";
        /** $generichide modifier */
        NetworkRuleOption[NetworkRuleOption["Generichide"] = 16] = "Generichide";
        /** $specifichide modifier */
        NetworkRuleOption[NetworkRuleOption["Specifichide"] = 32] = "Specifichide";
        /** $genericblock modifier */
        NetworkRuleOption[NetworkRuleOption["Genericblock"] = 64] = "Genericblock";
        /** $jsinject modifier */
        NetworkRuleOption[NetworkRuleOption["Jsinject"] = 128] = "Jsinject";
        /** $urlblock modifier */
        NetworkRuleOption[NetworkRuleOption["Urlblock"] = 256] = "Urlblock";
        /** $content modifier */
        NetworkRuleOption[NetworkRuleOption["Content"] = 512] = "Content";
        /** $extension modifier */
        NetworkRuleOption[NetworkRuleOption["Extension"] = 1024] = "Extension";
        /** $stealth modifier */
        NetworkRuleOption[NetworkRuleOption["Stealth"] = 2048] = "Stealth";
        // Content modifying
        // $empty modifier
        NetworkRuleOption[NetworkRuleOption["Empty"] = 4096] = "Empty";
        // $mp4 modifier
        NetworkRuleOption[NetworkRuleOption["Mp4"] = 8192] = "Mp4";
        // Other modifiers
        /** $popup modifier */
        NetworkRuleOption[NetworkRuleOption["Popup"] = 16384] = "Popup";
        /** $csp modifier */
        NetworkRuleOption[NetworkRuleOption["Csp"] = 32768] = "Csp";
        /** $replace modifier */
        NetworkRuleOption[NetworkRuleOption["Replace"] = 65536] = "Replace";
        /** $cookie modifier */
        NetworkRuleOption[NetworkRuleOption["Cookie"] = 131072] = "Cookie";
        /** $redirect modifier */
        NetworkRuleOption[NetworkRuleOption["Redirect"] = 262144] = "Redirect";
        /** $badfilter modifier */
        NetworkRuleOption[NetworkRuleOption["Badfilter"] = 524288] = "Badfilter";
        /** $removeparam modifier */
        NetworkRuleOption[NetworkRuleOption["RemoveParam"] = 1048576] = "RemoveParam";
        /** $removeheader modifier */
        NetworkRuleOption[NetworkRuleOption["RemoveHeader"] = 2097152] = "RemoveHeader";
        // Compatibility dependent
        /** $network modifier */
        NetworkRuleOption[NetworkRuleOption["Network"] = 4194304] = "Network";
        /** dns modifiers */
        NetworkRuleOption[NetworkRuleOption["Client"] = 8388608] = "Client";
        NetworkRuleOption[NetworkRuleOption["DnsRewrite"] = 16777216] = "DnsRewrite";
        NetworkRuleOption[NetworkRuleOption["DnsType"] = 33554432] = "DnsType";
        NetworkRuleOption[NetworkRuleOption["Ctag"] = 67108864] = "Ctag";
        // Document
        NetworkRuleOption[NetworkRuleOption["Document"] = 134217728] = "Document";
        // Groups (for validation)
        /** Blacklist-only modifiers */
        NetworkRuleOption[NetworkRuleOption["BlacklistOnly"] = 12288] = "BlacklistOnly";
        /** Allowlist-only modifiers */
        NetworkRuleOption[NetworkRuleOption["AllowlistOnly"] = 4088] = "AllowlistOnly";
        /** Options supported by host-level network rules * */
        NetworkRuleOption[NetworkRuleOption["OptionHostLevelRules"] = 126353412] = "OptionHostLevelRules";
        /**
         * Removeparam compatible modifiers
         *
         * $removeparam rules are compatible only with content type modifiers ($script, $stylesheet, etc)
         * and this list of modifiers:
         */
        NetworkRuleOption[NetworkRuleOption["RemoveParamCompatibleOptions"] = 135790599] = "RemoveParamCompatibleOptions";
        /**
         * Removeheader compatible modifiers
         *
         * $removeheader rules are compatible only with content type modifiers ($script, $stylesheet, etc)
         * and this list of modifiers:
         */
        NetworkRuleOption[NetworkRuleOption["RemoveHeaderCompatibleOptions"] = 136839175] = "RemoveHeaderCompatibleOptions";
    })(exports.NetworkRuleOption || (exports.NetworkRuleOption = {}));
    /**
     * Helper class that is used for passing {@link NetworkRule.parseRuleText}
     * result to the caller. Should not be used outside of this file.
     */
    var BasicRuleParts = /** @class */ (function () {
        function BasicRuleParts() {
        }
        return BasicRuleParts;
    }());
    /**
     * Basic network filtering rule.
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules
     */
    var NetworkRule = /** @class */ (function () {
        /**
         * Creates an instance of the {@link NetworkRule}.
         * It parses this rule and extracts the rule pattern (see {@link SimpleRegex}),
         * and rule modifiers.
         *
         * @param ruleText - original rule text.
         * @param filterListId - ID of the filter list this rule belongs to.
         *
         * @throws error if it fails to parse the rule.
         */
        function NetworkRule(ruleText, filterListId) {
            this.permittedDomains = null;
            this.restrictedDomains = null;
            /**
             * Domains in denyallow modifier providing exceptions for permitted domains
             * https://github.com/AdguardTeam/CoreLibs/issues/1304
             */
            this.denyAllowDomains = null;
            /** Flag with all enabled rule options */
            this.enabledOptions = 0;
            /** Flag with all disabled rule options */
            this.disabledOptions = 0;
            /** Flag with all permitted request types. 0 means ALL. */
            this.permittedRequestTypes = 0;
            /** Flag with all restricted request types. 0 means NONE. */
            this.restrictedRequestTypes = 0;
            /**
             * Rule Advanced modifier
             */
            this.advancedModifier = null;
            /**
             * Rule App modifier
             */
            this.appModifier = null;
            /**
             * Priority weight
             * Used in rules priority comparision
             */
            this.priorityWeight = 0;
            this.ruleText = ruleText;
            this.filterListId = filterListId;
            var ruleParts = NetworkRule.parseRuleText(ruleText);
            this.allowlist = !!ruleParts.allowlist;
            var pattern = ruleParts.pattern;
            if (pattern && NetworkRule.hasSpaces(pattern)) {
                throw new SyntaxError('Rule has spaces, seems to be an host rule');
            }
            if (ruleParts.options) {
                this.loadOptions(ruleParts.options);
            }
            if (pattern === SimpleRegex.MASK_START_URL
                || pattern === SimpleRegex.MASK_ANY_CHARACTER
                || pattern === ''
                || pattern.length < SimpleRegex.MIN_GENERIC_RULE_LENGTH) {
                // Except cookie and removeparam rules, they have their own atmosphere
                if (!(this.advancedModifier instanceof CookieModifier)
                    && !(this.advancedModifier instanceof RemoveParamModifier)) {
                    if (!(this.hasPermittedDomains() || this.hasPermittedApps())) {
                        // Rule matches too much and does not have any domain restriction
                        // We should not allow this kind of rules
                        // eslint-disable-next-line max-len
                        throw new SyntaxError('The rule is too wide, add domain restriction or make the pattern more specific');
                    }
                }
            }
            this.pattern = new Pattern(pattern, this.isOptionEnabled(exports.NetworkRuleOption.MatchCase));
        }
        NetworkRule.prototype.getText = function () {
            return this.ruleText;
        };
        NetworkRule.prototype.getFilterListId = function () {
            return this.filterListId;
        };
        /**
         * Returns rule pattern,
         * which currently is used only in the rule validator module
         */
        NetworkRule.prototype.getPattern = function () {
            return this.pattern.pattern;
        };
        /**
         * Returns `true` if the rule is "allowlist", e.g. if it disables other
         * rules when the pattern matches the request.
         */
        NetworkRule.prototype.isAllowlist = function () {
            return this.allowlist;
        };
        /**
         * Checks if the rule is a document-level allowlist rule
         * This means that the rule is supposed to disable or modify blocking
         * of the page subrequests.
         * For instance, `@@||example.org^$urlblock` unblocks all sub-requests.
         */
        NetworkRule.prototype.isDocumentLevelAllowlistRule = function () {
            if (!this.isAllowlist()) {
                return false;
            }
            return this.isOptionEnabled(exports.NetworkRuleOption.Urlblock)
                || this.isOptionEnabled(exports.NetworkRuleOption.Genericblock)
                || this.isOptionEnabled(exports.NetworkRuleOption.Content);
        };
        /**
         * Checks if the rule is a document allowlist rule.
         * For instance,
         * "@@||example.org^$document"
         * completely disables filtering on all pages at example.com and all subdomains.
         */
        NetworkRule.prototype.isDocumentAllowlistRule = function () {
            if (!this.isAllowlist()) {
                return false;
            }
            return this.isOptionEnabled(exports.NetworkRuleOption.Document);
        };
        /**
         * The longest part of pattern without any special characters.
         * It is used to improve the matching performance.
         */
        NetworkRule.prototype.getShortcut = function () {
            return this.pattern.shortcut;
        };
        /**
         * Gets list of permitted domains.
         * See https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#domain-modifier
         */
        NetworkRule.prototype.getPermittedDomains = function () {
            return this.permittedDomains;
        };
        /**
         * Gets list of restricted domains.
         * See https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#domain-modifier
         */
        NetworkRule.prototype.getRestrictedDomains = function () {
            return this.restrictedDomains;
        };
        /**
         * Gets list of permitted domains.
         * See https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#app
         */
        NetworkRule.prototype.getPermittedApps = function () {
            if (this.appModifier) {
                return this.appModifier.permittedApps;
            }
            return null;
        };
        /**
         * Gets list of restricted domains.
         * See https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#app
         */
        NetworkRule.prototype.getRestrictedApps = function () {
            if (this.appModifier) {
                return this.appModifier.restrictedApps;
            }
            return null;
        };
        /** Flag with all permitted request types. 0 means ALL. */
        NetworkRule.prototype.getPermittedRequestTypes = function () {
            return this.permittedRequestTypes;
        };
        /** Flag with all restricted request types. 0 means NONE. */
        NetworkRule.prototype.getRestrictedRequestTypes = function () {
            return this.restrictedRequestTypes;
        };
        /**
         * Advanced modifier
         */
        NetworkRule.prototype.getAdvancedModifier = function () {
            return this.advancedModifier;
        };
        /**
         * Advanced modifier value
         */
        NetworkRule.prototype.getAdvancedModifierValue = function () {
            return this.advancedModifier && this.advancedModifier.getValue();
        };
        /**
         * isRegexRule returns true if rule's pattern is a regular expression.
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#regexp-support
         */
        NetworkRule.prototype.isRegexRule = function () {
            return (this.getPattern().startsWith(SimpleRegex.MASK_REGEX_RULE)
                && this.getPattern().endsWith(SimpleRegex.MASK_REGEX_RULE));
        };
        NetworkRule.prototype.matchesPermittedDomains = function (hostname) {
            if (this.hasPermittedDomains()
                && DomainModifier.isDomainOrSubdomainOfAny(hostname, this.permittedDomains)) {
                return true;
            }
            return false;
        };
        /**
         * Checks if this filtering rule matches the specified request.
         * @param request - request to check.
         * @param useShortcut - the flag to use this rule shortcut
         *
         * In case we use Trie in lookup table, we don't need to use shortcut cause we already check if request's url
         * includes full rule shortcut.
         */
        NetworkRule.prototype.match = function (request, useShortcut) {
            if (useShortcut === void 0) { useShortcut = true; }
            if (useShortcut && !this.matchShortcut(request)) {
                return false;
            }
            if (this.isOptionEnabled(exports.NetworkRuleOption.ThirdParty) && !request.thirdParty) {
                return false;
            }
            if (this.isOptionDisabled(exports.NetworkRuleOption.ThirdParty) && request.thirdParty) {
                return false;
            }
            if (!this.matchRequestType(request.requestType)) {
                return false;
            }
            if (!this.matchDomainModifier(request)) {
                return false;
            }
            if (this.isOptionEnabled(exports.NetworkRuleOption.RemoveParam)) {
                if (!this.matchRequestTypeExplicit(request.requestType)) {
                    return false;
                }
            }
            if (!this.matchDenyAllowDomains(request.hostname)) {
                return false;
            }
            if (!this.matchDnsType(request.dnsType)) {
                return false;
            }
            if (!this.matchClientTags(request.clientTags)) {
                return false;
            }
            if (!this.matchClient(request.clientName, request.clientIP)) {
                return false;
            }
            return this.pattern.matchPattern(request, true);
        };
        /**
         * matchShortcut simply checks if shortcut is a substring of the URL.
         * @param request - request to check.
         */
        NetworkRule.prototype.matchShortcut = function (request) {
            return request.urlLowercase.indexOf(this.getShortcut()) >= 0;
        };
        /**
         * matchDomain checks if the filtering rule is allowed on this domain.
         * @param domain - domain to check.
         */
        NetworkRule.prototype.matchDomain = function (domain) {
            if (this.hasRestrictedDomains()) {
                if (DomainModifier.isDomainOrSubdomainOfAny(domain, this.restrictedDomains)) {
                    // Domain or host is restricted
                    // i.e. $domain=~example.org
                    return false;
                }
            }
            if (this.hasPermittedDomains()) {
                if (!DomainModifier.isDomainOrSubdomainOfAny(domain, this.permittedDomains)) {
                    // Domain is not among permitted
                    // i.e. $domain=example.org and we're checking example.com
                    return false;
                }
            }
            return true;
        };
        /**
         * Check if request matches domain modifier by request referrer (general case) or by request target
         *
         * In some cases the $domain modifier can match not only the referrer domain, but also the target domain.
         * This happens when the following is true (1 AND ((2 AND 3) OR 4):
         *
         * 1) The request has document type
         * 2) The rule's pattern doesn't match any particular domain(s)
         * 3) The rule's pattern doesn't contain regular expressions
         * 4) The $domain modifier contains only excluded domains (e.g., $domain=~example.org|~example.com)
         *
         * When all these conditions are met, the domain modifier will match both the referrer domain and the target domain.
         * https://github.com/AdguardTeam/tsurlfilter/issues/45
         * @param request
         */
        NetworkRule.prototype.matchDomainModifier = function (request) {
            if (!this.permittedDomains && !this.restrictedDomains) {
                return true;
            }
            var isDocumentType = request.requestType === exports.RequestType.Document
                || request.requestType === exports.RequestType.Subdocument;
            var hasOnlyExcludedDomains = (!this.permittedDomains || this.permittedDomains.length === 0)
                && this.restrictedDomains
                && this.restrictedDomains.length > 0;
            var patternIsRegex = this.isRegexRule();
            var patternIsDomainSpecific = this.pattern.isPatternDomainSpecific();
            var matchesTargetByPatternCondition = !patternIsRegex && !patternIsDomainSpecific;
            if (isDocumentType && (hasOnlyExcludedDomains || matchesTargetByPatternCondition)) {
                // check if matches source hostname if exists or if matches target hostname
                return (request.sourceHostname && this.matchDomain(request.sourceHostname))
                    || this.matchDomain(request.hostname);
            }
            return this.matchDomain(request.sourceHostname || '');
        };
        /**
         * checks if the filtering rule is allowed on this domain.
         * @param domain
         */
        NetworkRule.prototype.matchDenyAllowDomains = function (domain) {
            if (!this.denyAllowDomains) {
                return true;
            }
            if (this.denyAllowDomains.length > 0) {
                if (DomainModifier.isDomainOrSubdomainOfAny(domain, this.denyAllowDomains)) {
                    return false;
                }
            }
            return true;
        };
        /**
         * Return TRUE if this rule matches with the tags associated with a client
         *
         * @param clientTags
         */
        NetworkRule.prototype.matchClientTags = function (clientTags) {
            var advancedModifier = this.getAdvancedModifier();
            if (!advancedModifier || !(advancedModifier instanceof CtagModifier)) {
                return true;
            }
            if (!clientTags) {
                return false;
            }
            var cTagsModifier = advancedModifier;
            return clientTags.every(function (x) { return cTagsModifier.match(x); });
        };
        /**
         * returns TRUE if the rule matches with the specified client
         *
         * @param clientName
         * @param clientIP
         */
        NetworkRule.prototype.matchClient = function (clientName, clientIP) {
            var advancedModifier = this.getAdvancedModifier();
            if (!advancedModifier || !(advancedModifier instanceof ClientModifier)) {
                return true;
            }
            if (!clientName && !clientIP) {
                return false;
            }
            var modifier = advancedModifier;
            return modifier.matchAny(clientName, clientIP);
        };
        /**
         * Return TRUE if this rule matches with the request dnstype
         *
         * @param dnstype
         */
        NetworkRule.prototype.matchDnsType = function (dnstype) {
            var advancedModifier = this.getAdvancedModifier();
            if (!advancedModifier || !(advancedModifier instanceof DnsTypeModifier)) {
                return true;
            }
            if (!dnstype) {
                return false;
            }
            var modifier = advancedModifier;
            return modifier.match(dnstype);
        };
        /**
         * Checks if rule has permitted domains
         */
        NetworkRule.prototype.hasPermittedDomains = function () {
            return this.permittedDomains != null && this.permittedDomains.length > 0;
        };
        /**
         * Checks if rule has restricted domains
         */
        NetworkRule.prototype.hasRestrictedDomains = function () {
            return this.restrictedDomains != null && this.restrictedDomains.length > 0;
        };
        /**
         * Checks if rule has permitted apps
         */
        NetworkRule.prototype.hasPermittedApps = function () {
            if (!this.appModifier) {
                return false;
            }
            return this.appModifier.permittedApps !== null && this.appModifier.permittedApps.length > 0;
        };
        /**
         * matchRequestType checks if the request's type matches the rule properties
         * @param requestType - request type to check.
         */
        NetworkRule.prototype.matchRequestType = function (requestType) {
            if (this.permittedRequestTypes !== 0) {
                if ((this.permittedRequestTypes & requestType) !== requestType) {
                    return false;
                }
            }
            if (this.restrictedRequestTypes !== 0) {
                if ((this.restrictedRequestTypes & requestType) === requestType) {
                    return false;
                }
            }
            return true;
        };
        /**
         * In case of $removeparam modifier,
         * we only allow it to target other content types if the rule has an explicit content-type modifier.
         */
        NetworkRule.prototype.matchRequestTypeExplicit = function (requestType) {
            if (this.permittedRequestTypes === 0
                && this.restrictedRequestTypes === 0
                && requestType !== exports.RequestType.Document
                && requestType !== exports.RequestType.Subdocument) {
                return false;
            }
            return this.matchRequestType(requestType);
        };
        /**
         * Checks if pattern has spaces
         * Used in order to do not create network rules from host rules
         * @param pattern
         * @private
         */
        NetworkRule.hasSpaces = function (pattern) {
            return pattern.indexOf(' ') > -1;
        };
        /**
         * Parses the options string and saves them.
         * More on the rule modifiers:
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules-modifiers
         *
         * @param options - string with the rule modifiers
         *
         * @throws an error if there is an unsupported modifier
         */
        NetworkRule.prototype.loadOptions = function (options) {
            var optionParts = splitByDelimiterWithEscapeCharacter(options, ',', '\\', false);
            for (var i = 0; i < optionParts.length; i += 1) {
                var option = optionParts[i];
                var valueIndex = option.indexOf('=');
                var optionName = option;
                var optionValue = '';
                if (valueIndex > 0) {
                    optionName = option.substring(0, valueIndex);
                    optionValue = option.substring(valueIndex + 1);
                }
                this.loadOption(optionName, optionValue);
            }
            // More specified rule has more priority
            this.priorityWeight = optionParts.length;
            this.validateOptions();
            // In the case of allowlist rules $document implicitly includes all other modifiers:
            // `$content`, `$elemhide`, `$jsinject`, `$urlblock`.
            if (this.isAllowlist() && this.isOptionEnabled(exports.NetworkRuleOption.Document)) {
                this.setOptionEnabled(exports.NetworkRuleOption.Elemhide, true, true);
                this.setOptionEnabled(exports.NetworkRuleOption.Jsinject, true, true);
                this.setOptionEnabled(exports.NetworkRuleOption.Urlblock, true, true);
                this.setOptionEnabled(exports.NetworkRuleOption.Content, true, true);
            }
            // Rules of these types can be applied to documents only
            // $jsinject, $elemhide, $urlblock, $genericblock, $generichide and $content for allowlist rules.
            // $popup - for url blocking
            if (this.isOptionEnabled(exports.NetworkRuleOption.Jsinject)
                || this.isOptionEnabled(exports.NetworkRuleOption.Elemhide)
                || this.isOptionEnabled(exports.NetworkRuleOption.Content)
                || this.isOptionEnabled(exports.NetworkRuleOption.Urlblock)
                || this.isOptionEnabled(exports.NetworkRuleOption.Genericblock)
                || this.isOptionEnabled(exports.NetworkRuleOption.Generichide)
                || this.isOptionEnabled(exports.NetworkRuleOption.Popup)) {
                this.permittedRequestTypes = exports.RequestType.Document;
            }
        };
        /**
         * Returns true if the specified option is enabled.
         * Please note, that options have three state: enabled, disabled, undefined.
         *
         * @param option - rule option to check.
         */
        NetworkRule.prototype.isOptionEnabled = function (option) {
            return (this.enabledOptions & option) === option;
        };
        /**
         * Returns true if one and only option is enabled
         *
         * @param option
         */
        NetworkRule.prototype.isSingleOptionEnabled = function (option) {
            return this.enabledOptions === option;
        };
        /**
         * Returns true if the specified option is disabled.
         * Please note, that options have three state: enabled, disabled, undefined.
         *
         * @param option - rule option to check.
         */
        NetworkRule.prototype.isOptionDisabled = function (option) {
            return (this.disabledOptions & option) === option;
        };
        /**
         * Checks if the rule has higher priority that the specified rule
         * allowlist + $important > $important > allowlist > basic rules
         */
        NetworkRule.prototype.isHigherPriority = function (r) {
            var important = this.isOptionEnabled(exports.NetworkRuleOption.Important);
            var rImportant = r.isOptionEnabled(exports.NetworkRuleOption.Important);
            if (this.isAllowlist() && important && !(r.isAllowlist() && rImportant)) {
                return true;
            }
            if (r.isAllowlist() && rImportant && !(this.isAllowlist() && important)) {
                return false;
            }
            if (important && !rImportant) {
                return true;
            }
            if (rImportant && !important) {
                return false;
            }
            if (this.isAllowlist() && !r.isAllowlist()) {
                return true;
            }
            if (r.isAllowlist() && !this.isAllowlist()) {
                return false;
            }
            var generic = this.isGeneric();
            var rGeneric = r.isGeneric();
            if (!generic && rGeneric) {
                // specific rules have priority over generic rules
                return true;
            }
            return this.priorityWeight > r.priorityWeight;
        };
        /**
         * Returns true if the rule is considered "generic"
         * "generic" means that the rule is not restricted to a limited set of domains
         * Please note that it might be forbidden on some domains, though.
         *
         * @return {boolean}
         */
        NetworkRule.prototype.isGeneric = function () {
            return !this.hasPermittedDomains();
        };
        /**
         * Returns true if this rule negates the specified rule
         * Only makes sense when this rule has a `badfilter` modifier
         */
        NetworkRule.prototype.negatesBadfilter = function (specifiedRule) {
            if (!this.isOptionEnabled(exports.NetworkRuleOption.Badfilter)) {
                return false;
            }
            if (this.allowlist !== specifiedRule.allowlist) {
                return false;
            }
            if (this.pattern.pattern !== specifiedRule.pattern.pattern) {
                return false;
            }
            if (this.permittedRequestTypes !== specifiedRule.permittedRequestTypes) {
                return false;
            }
            if (this.restrictedRequestTypes !== specifiedRule.restrictedRequestTypes) {
                return false;
            }
            if ((this.enabledOptions ^ exports.NetworkRuleOption.Badfilter) !== specifiedRule.enabledOptions) {
                return false;
            }
            if (this.disabledOptions !== specifiedRule.disabledOptions) {
                return false;
            }
            if (!stringArraysEquals(this.restrictedDomains, specifiedRule.restrictedDomains)) {
                return false;
            }
            if (!stringArraysHaveIntersection(this.permittedDomains, specifiedRule.permittedDomains)) {
                return false;
            }
            return true;
        };
        /**
         * Checks if this rule can be used for hosts-level blocking
         */
        NetworkRule.prototype.isHostLevelNetworkRule = function () {
            if (this.hasPermittedDomains() || this.hasRestrictedDomains()) {
                return false;
            }
            if (this.permittedRequestTypes !== 0 && this.restrictedRequestTypes !== 0) {
                return false;
            }
            if (this.disabledOptions !== 0) {
                return false;
            }
            if (this.enabledOptions !== 0) {
                return ((this.enabledOptions
                    & exports.NetworkRuleOption.OptionHostLevelRules)
                    | (this.enabledOptions
                        ^ exports.NetworkRuleOption.OptionHostLevelRules)) === exports.NetworkRuleOption.OptionHostLevelRules;
            }
            return true;
        };
        /**
         * Enables or disables the specified option.
         *
         * @param option - option to enable or disable.
         * @param enabled - true to enable, false to disable.
         * @param skipRestrictions - skip options allowlist/blacklist restrictions
         *
         * @throws an error if the option we're trying to enable cannot be.
         * For instance, you cannot enable $elemhide for blacklist rules.
         */
        NetworkRule.prototype.setOptionEnabled = function (option, enabled, skipRestrictions) {
            if (skipRestrictions === void 0) { skipRestrictions = false; }
            if (!skipRestrictions) {
                if (this.allowlist && (option & exports.NetworkRuleOption.BlacklistOnly) === option) {
                    throw new SyntaxError("Modifier ".concat(exports.NetworkRuleOption[option], " cannot be used in allowlist rule"));
                }
                if (!this.allowlist && (option & exports.NetworkRuleOption.AllowlistOnly) === option) {
                    throw new SyntaxError("Modifier ".concat(exports.NetworkRuleOption[option], " cannot be used in blacklist rule"));
                }
            }
            if (enabled) {
                this.enabledOptions |= option;
            }
            else {
                this.disabledOptions |= option;
            }
        };
        /**
         * Permits or forbids the specified request type.
         * "Permits" means that the rule will match **only** the types that are permitted.
         * "Restricts" means that the rule will match **all but restricted**.
         *
         * @param requestType - request type.
         * @param permitted - true if it's permitted (whic)
         */
        NetworkRule.prototype.setRequestType = function (requestType, permitted) {
            if (permitted) {
                this.permittedRequestTypes |= requestType;
            }
            else {
                this.restrictedRequestTypes |= requestType;
            }
        };
        /**
         * Sets and validates exceptionally allowed domains presented in $denyallow modifier
         *
         * @param optionValue
         */
        NetworkRule.prototype.setDenyAllowDomains = function (optionValue) {
            var domainModifier = new DomainModifier(optionValue, PIPE_SEPARATOR);
            if (domainModifier.restrictedDomains && domainModifier.restrictedDomains.length > 0) {
                throw new SyntaxError('Invalid modifier: $denyallow domains cannot be negated');
            }
            if (domainModifier.permittedDomains
                && domainModifier.permittedDomains.some(function (x) { return x.includes(SimpleRegex.MASK_ANY_CHARACTER); })) {
                throw new SyntaxError('Invalid modifier: $denyallow domains wildcards are not supported');
            }
            this.denyAllowDomains = domainModifier.permittedDomains;
        };
        /**
         * Loads the specified modifier:
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules-modifiers
         *
         * @param optionName - modifier name.
         * @param optionValue - modifier value.
         *
         * @throws an error if there is an unsupported modifier
         */
        NetworkRule.prototype.loadOption = function (optionName, optionValue) {
            var OPTIONS = NetworkRule.OPTIONS;
            if (optionName.startsWith(OPTIONS.NOOP)) {
                /**
                 * A noop modifier does nothing and can be used to increase some rules readability.
                 * It consists of the sequence of underscore characters (_) of any length
                 * and can appear in a rule as many times as it's needed.
                 */
                if (!optionName.split(OPTIONS.NOOP).some(function (s) { return !!s; })) {
                    return;
                }
            }
            switch (optionName) {
                // General options
                case OPTIONS.THIRD_PARTY:
                case NOT_MARK + OPTIONS.FIRST_PARTY:
                    this.setOptionEnabled(exports.NetworkRuleOption.ThirdParty, true);
                    break;
                case NOT_MARK + OPTIONS.THIRD_PARTY:
                case OPTIONS.FIRST_PARTY:
                    this.setOptionEnabled(exports.NetworkRuleOption.ThirdParty, false);
                    break;
                case OPTIONS.MATCH_CASE:
                    this.setOptionEnabled(exports.NetworkRuleOption.MatchCase, true);
                    break;
                case NOT_MARK + OPTIONS.MATCH_CASE:
                    this.setOptionEnabled(exports.NetworkRuleOption.MatchCase, false);
                    break;
                case OPTIONS.IMPORTANT:
                    this.setOptionEnabled(exports.NetworkRuleOption.Important, true);
                    break;
                // $domain modifier
                case OPTIONS.DOMAIN: {
                    var domainModifier = new DomainModifier(optionValue, PIPE_SEPARATOR);
                    this.permittedDomains = domainModifier.permittedDomains;
                    this.restrictedDomains = domainModifier.restrictedDomains;
                    break;
                }
                case OPTIONS.DENYALLOW: {
                    this.setDenyAllowDomains(optionValue);
                    break;
                }
                // Document-level allowlist rules
                case OPTIONS.ELEMHIDE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Elemhide, true);
                    break;
                case OPTIONS.GENERICHIDE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Generichide, true);
                    break;
                case OPTIONS.SPECIFICHIDE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Specifichide, true);
                    break;
                case OPTIONS.GENERICBLOCK:
                    this.setOptionEnabled(exports.NetworkRuleOption.Genericblock, true);
                    break;
                case OPTIONS.JSINJECT:
                    this.setOptionEnabled(exports.NetworkRuleOption.Jsinject, true);
                    break;
                case OPTIONS.URLBLOCK:
                    this.setOptionEnabled(exports.NetworkRuleOption.Urlblock, true);
                    break;
                case OPTIONS.CONTENT:
                    this.setOptionEnabled(exports.NetworkRuleOption.Content, true);
                    break;
                // $document
                case OPTIONS.DOCUMENT:
                case OPTIONS.DOC:
                    this.setOptionEnabled(exports.NetworkRuleOption.Document, true);
                    this.setRequestType(exports.RequestType.Document, true);
                    break;
                case NOT_MARK + OPTIONS.DOCUMENT:
                case NOT_MARK + OPTIONS.DOC:
                    this.setOptionEnabled(exports.NetworkRuleOption.Document, false);
                    this.setRequestType(exports.RequestType.Document, false);
                    break;
                // Stealth mode $stealth
                case OPTIONS.STEALTH:
                    this.setOptionEnabled(exports.NetworkRuleOption.Stealth, true);
                    break;
                // $popup blocking option
                case OPTIONS.POPUP:
                    this.setOptionEnabled(exports.NetworkRuleOption.Popup, true);
                    break;
                // $empty and $mp4
                // Deprecated in favor of $redirect
                case OPTIONS.EMPTY:
                    this.setOptionEnabled(exports.NetworkRuleOption.Empty, true);
                    break;
                case OPTIONS.MP4:
                    this.setOptionEnabled(exports.NetworkRuleOption.Mp4, true);
                    break;
                // Content type options
                case OPTIONS.SCRIPT:
                    this.setRequestType(exports.RequestType.Script, true);
                    break;
                case NOT_MARK + OPTIONS.SCRIPT:
                    this.setRequestType(exports.RequestType.Script, false);
                    break;
                case OPTIONS.STYLESHEET:
                    this.setRequestType(exports.RequestType.Stylesheet, true);
                    break;
                case NOT_MARK + OPTIONS.STYLESHEET:
                    this.setRequestType(exports.RequestType.Stylesheet, false);
                    break;
                case OPTIONS.SUBDOCUMENT:
                    this.setRequestType(exports.RequestType.Subdocument, true);
                    break;
                case NOT_MARK + OPTIONS.SUBDOCUMENT:
                    this.setRequestType(exports.RequestType.Subdocument, false);
                    break;
                case OPTIONS.OBJECT:
                    this.setRequestType(exports.RequestType.Object, true);
                    break;
                case NOT_MARK + OPTIONS.OBJECT:
                    this.setRequestType(exports.RequestType.Object, false);
                    break;
                case OPTIONS.IMAGE:
                    this.setRequestType(exports.RequestType.Image, true);
                    break;
                case NOT_MARK + OPTIONS.IMAGE:
                    this.setRequestType(exports.RequestType.Image, false);
                    break;
                case OPTIONS.XMLHTTPREQUEST:
                    this.setRequestType(exports.RequestType.XmlHttpRequest, true);
                    break;
                case NOT_MARK + OPTIONS.XMLHTTPREQUEST:
                    this.setRequestType(exports.RequestType.XmlHttpRequest, false);
                    break;
                case OPTIONS.MEDIA:
                    this.setRequestType(exports.RequestType.Media, true);
                    break;
                case NOT_MARK + OPTIONS.MEDIA:
                    this.setRequestType(exports.RequestType.Media, false);
                    break;
                case OPTIONS.FONT:
                    this.setRequestType(exports.RequestType.Font, true);
                    break;
                case NOT_MARK + OPTIONS.FONT:
                    this.setRequestType(exports.RequestType.Font, false);
                    break;
                case OPTIONS.WEBSOCKET:
                    this.setRequestType(exports.RequestType.Websocket, true);
                    break;
                case NOT_MARK + OPTIONS.WEBSOCKET:
                    this.setRequestType(exports.RequestType.Websocket, false);
                    break;
                case OPTIONS.OTHER:
                    this.setRequestType(exports.RequestType.Other, true);
                    break;
                case NOT_MARK + OPTIONS.OTHER:
                    this.setRequestType(exports.RequestType.Other, false);
                    break;
                case OPTIONS.PING:
                    this.setRequestType(exports.RequestType.Ping, true);
                    break;
                case NOT_MARK + OPTIONS.PING:
                    this.setRequestType(exports.RequestType.Ping, false);
                    break;
                case OPTIONS.WEBRTC:
                    this.setRequestType(exports.RequestType.Webrtc, true);
                    break;
                case NOT_MARK + OPTIONS.WEBRTC:
                    this.setRequestType(exports.RequestType.Webrtc, false);
                    break;
                // Special modifiers
                case OPTIONS.BADFILTER:
                    this.setOptionEnabled(exports.NetworkRuleOption.Badfilter, true);
                    break;
                case OPTIONS.CSP:
                    this.setOptionEnabled(exports.NetworkRuleOption.Csp, true);
                    this.advancedModifier = new CspModifier(optionValue, this.isAllowlist());
                    break;
                case OPTIONS.REPLACE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Replace, true);
                    this.advancedModifier = new ReplaceModifier(optionValue);
                    break;
                case OPTIONS.COOKIE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Cookie, true);
                    this.advancedModifier = new CookieModifier(optionValue);
                    break;
                case OPTIONS.REDIRECT:
                    this.setOptionEnabled(exports.NetworkRuleOption.Redirect, true);
                    this.advancedModifier = new RedirectModifier(optionValue, this.ruleText, this.isAllowlist());
                    break;
                case OPTIONS.REDIRECTRULE:
                    this.setOptionEnabled(exports.NetworkRuleOption.Redirect, true);
                    this.advancedModifier = new RedirectModifier(optionValue, this.ruleText, this.isAllowlist(), true);
                    break;
                case OPTIONS.REMOVEPARAM:
                    this.setOptionEnabled(exports.NetworkRuleOption.RemoveParam, true);
                    this.advancedModifier = new RemoveParamModifier(optionValue);
                    break;
                case OPTIONS.REMOVEHEADER:
                    this.setOptionEnabled(exports.NetworkRuleOption.RemoveHeader, true);
                    this.advancedModifier = new RemoveHeaderModifier(optionValue, this.isAllowlist());
                    break;
                // Dns modifiers
                case OPTIONS.CLIENT: {
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $client modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.Client, true);
                    this.advancedModifier = new ClientModifier(optionValue);
                    break;
                }
                case OPTIONS.DNSREWRITE: {
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $dnsrewrite modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.DnsRewrite, true);
                    this.advancedModifier = new DnsRewriteModifier(optionValue);
                    break;
                }
                case OPTIONS.DNSTYPE: {
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $dnstype modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.DnsType, true);
                    this.advancedModifier = new DnsTypeModifier(optionValue);
                    break;
                }
                case OPTIONS.CTAG: {
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $ctag modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.Ctag, true);
                    this.advancedModifier = new CtagModifier(optionValue);
                    break;
                }
                case OPTIONS.APP: {
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $app modifier');
                    }
                    this.appModifier = new AppModifier(optionValue);
                    break;
                }
                case OPTIONS.NETWORK:
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $network modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.Network, true);
                    break;
                case OPTIONS.EXTENSION:
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $extension modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.Extension, true);
                    break;
                case NOT_MARK + OPTIONS.EXTENSION:
                    if (isCompatibleWith(exports.CompatibilityTypes.extension)) {
                        throw new SyntaxError('Extension doesn\'t support $extension modifier');
                    }
                    this.setOptionEnabled(exports.NetworkRuleOption.Extension, false);
                    break;
                default: {
                    // clear empty values
                    var modifierView = [optionName, optionValue]
                        .filter(function (i) { return i; })
                        .join('=');
                    throw new SyntaxError("Unknown modifier: ".concat(modifierView));
                }
            }
        };
        /**
         * Validates rule options
         */
        NetworkRule.prototype.validateOptions = function () {
            if (this.advancedModifier instanceof RemoveParamModifier) {
                this.validateRemoveParamRule();
            }
            else if (this.advancedModifier instanceof RemoveHeaderModifier) {
                this.validateRemoveHeaderRule();
            }
        };
        /**
         * $removeparam rules are not compatible with any other modifiers except $domain,
         * $third-party, $app, $important, $match-case and permitted content type modifiers ($script, $stylesheet, etc).
         * The rules with any other modifiers are considered invalid and will be discarded.
         */
        NetworkRule.prototype.validateRemoveParamRule = function () {
            if ((this.enabledOptions | exports.NetworkRuleOption.RemoveParamCompatibleOptions)
                !== exports.NetworkRuleOption.RemoveParamCompatibleOptions) {
                throw new SyntaxError('$removeparam rules are not compatible with some other modifiers');
            }
        };
        /**
         * $removeheader rules are not compatible with any other modifiers except $domain,
         * $third-party, $app, $important, $match-case and permitted content type modifiers ($script, $stylesheet, etc).
         * The rules with any other modifiers are considered invalid and will be discarded.
         */
        NetworkRule.prototype.validateRemoveHeaderRule = function () {
            if ((this.enabledOptions | exports.NetworkRuleOption.RemoveHeaderCompatibleOptions)
                !== exports.NetworkRuleOption.RemoveHeaderCompatibleOptions) {
                throw new SyntaxError('$removeheader rules are not compatible with some other modifiers');
            }
        };
        /**
         * parseRuleText splits the rule text into multiple parts.
         * @param ruleText - original rule text
         * @returns basic rule parts
         *
         * @throws error if the rule is empty (for instance, empty string or `@@`)
         */
        NetworkRule.parseRuleText = function (ruleText) {
            var ruleParts = new BasicRuleParts();
            ruleParts.allowlist = false;
            var startIndex = 0;
            if (ruleText.startsWith(NetworkRule.MASK_ALLOWLIST)) {
                ruleParts.allowlist = true;
                startIndex = NetworkRule.MASK_ALLOWLIST.length;
            }
            if (ruleText.length <= startIndex) {
                throw new SyntaxError('Rule is too short');
            }
            // Setting pattern to rule text (for the case of empty options)
            ruleParts.pattern = ruleText.substring(startIndex);
            // Avoid parsing options inside of a regex rule
            if (ruleParts.pattern.startsWith(SimpleRegex.MASK_REGEX_RULE)
                && ruleParts.pattern.endsWith(SimpleRegex.MASK_REGEX_RULE)
                && !ruleParts.pattern.includes("".concat(NetworkRule.OPTIONS.REPLACE, "="))) {
                return ruleParts;
            }
            var removeParamIndex = ruleText.lastIndexOf("".concat(NetworkRule.OPTIONS.REMOVEPARAM, "="));
            var endIndex = removeParamIndex >= 0 ? removeParamIndex : ruleText.length - 2;
            var foundEscaped = false;
            for (var i = endIndex; i >= startIndex; i -= 1) {
                var c = ruleText.charAt(i);
                if (c === NetworkRule.OPTIONS_DELIMITER) {
                    if (i > startIndex && ruleText.charAt(i - 1) === NetworkRule.ESCAPE_CHARACTER) {
                        foundEscaped = true;
                    }
                    else {
                        ruleParts.pattern = ruleText.substring(startIndex, i);
                        ruleParts.options = ruleText.substring(i + 1);
                        if (foundEscaped) {
                            // Find and replace escaped options delimiter
                            ruleParts.options = ruleParts.options.replace(NetworkRule.RE_ESCAPED_OPTIONS_DELIMITER, NetworkRule.OPTIONS_DELIMITER);
                            // Reset the regexp state
                            NetworkRule.RE_ESCAPED_OPTIONS_DELIMITER.lastIndex = 0;
                        }
                        // Options delimiter was found, exiting loop
                        break;
                    }
                }
            }
            return ruleParts;
        };
        /**
         * Separates the rule pattern from the list of modifiers.
         *
         * ```
         * rule = ["@@"] pattern [ "$" modifiers ]
         * modifiers = [modifier0, modifier1[, ...[, modifierN]]]
         * ```
         */
        NetworkRule.OPTIONS_DELIMITER = OPTIONS_DELIMITER;
        /**
         * This character is used to escape special characters in modifiers values
         */
        NetworkRule.ESCAPE_CHARACTER = ESCAPE_CHARACTER;
        // eslint-disable-next-line max-len
        NetworkRule.RE_ESCAPED_OPTIONS_DELIMITER = new RegExp("".concat(NetworkRule.ESCAPE_CHARACTER).concat(NetworkRule.OPTIONS_DELIMITER), 'g');
        /**
         * A marker that is used in rules of exception.
         * To turn off filtering for a request, start your rule with this marker.
         */
        NetworkRule.MASK_ALLOWLIST = MASK_ALLOWLIST;
        /**
         * Mark that negates options
         */
        NetworkRule.NOT_MARK = NOT_MARK;
        /**
         * Rule options
         */
        NetworkRule.OPTIONS = NETWORK_RULE_OPTIONS;
        return NetworkRule;
    }());

    /**
     * Implements a host rule.
     *
     * HostRule is a structure for simple host-level rules (i.e. /etc/hosts syntax).
     * http://man7.org/linux/man-pages/man5/hosts.5.html
     * It also supports "just domain" syntax. In this case, the IP will be set to 0.0.0.0.
     *
     * Rules syntax looks like this:
     * ```
     * IP_address canonical_hostname [aliases...]
     * ```
     *
     * Examples:
     * * `192.168.1.13 bar.mydomain.org bar` -- ipv4
     * * `ff02::1 ip6-allnodes` -- ipv6
     * * `::1 localhost ip6-localhost ip6-loopback` -- ipv6 aliases
     * * `example.org` -- "just domain" syntax
     */
    var HostRule = /** @class */ (function () {
        /**
         * Constructor
         *
         * Parses the rule and creates a new HostRule instance
         *
         * @param ruleText - original rule text.
         * @param filterListId - ID of the filter list this rule belongs to.
         *
         * @throws error if it fails to parse the rule.
         */
        function HostRule(ruleText, filterListId) {
            this.hostnames = [];
            this.ip = '';
            this.invalid = false;
            this.ruleText = ruleText;
            this.filterListId = filterListId;
            var commentIndex = ruleText.indexOf('#');
            var stripped = commentIndex >= 0 ? ruleText.substring(0, commentIndex) : ruleText;
            var parts = stripped.trim().split(' ');
            if (parts.length >= 2) {
                if (!isIp_1(parts[0])) {
                    this.invalid = true;
                    return;
                }
                // eslint-disable-next-line prefer-destructuring
                this.ip = parts[0];
                this.hostnames = parts.slice(1).filter(function (x) { return !!x; });
            }
            else if (parts.length === 1 && isDomainName(parts[0])) {
                this.hostnames = [parts[0]];
                this.ip = '0.0.0.0';
            }
            else {
                this.invalid = true;
            }
        }
        /**
         * Match returns true if this rule can be used on the specified hostname.
         *
         * @param hostname - hostname to check
         */
        HostRule.prototype.match = function (hostname) {
            return this.hostnames.includes(hostname);
        };
        /**
         * Returns list id
         */
        HostRule.prototype.getFilterListId = function () {
            return this.filterListId;
        };
        /**
         * Return rule text
         */
        HostRule.prototype.getText = function () {
            return this.ruleText;
        };
        /**
         * Returns ip address
         */
        HostRule.prototype.getIp = function () {
            return this.ip;
        };
        /**
         * Returns hostnames
         */
        HostRule.prototype.getHostnames = function () {
            return this.hostnames;
        };
        /**
         * Is invalid rule
         */
        HostRule.prototype.isInvalid = function () {
            return this.invalid;
        };
        return HostRule;
    }());

    /**
     * MatchingResult contains all the rules matching a web request, and provides methods
     * that define how a web request should be processed
     */
    var MatchingResult = /** @class */ (function () {
        /**
         * Creates an instance of the MatchingResult struct and fills it with the rules.
         *
         * @param rules network rules
         * @param sourceRule source rule
         */
        function MatchingResult(rules, sourceRule) {
            this.basicRule = null;
            this.documentRule = null;
            this.cspRules = null;
            this.cookieRules = null;
            this.replaceRules = null;
            this.removeParamRules = null;
            this.removeHeaderRules = null;
            this.redirectRules = null;
            this.cspRules = null;
            this.stealthRule = null;
            // eslint-disable-next-line no-param-reassign
            rules = MatchingResult.removeBadfilterRules(rules);
            if (sourceRule) {
                this.documentRule = sourceRule;
            }
            // Second - check if blocking rules (generic or all of them) are allowed
            // generic blocking rules are allowed by default
            var genericAllowed = true;
            // basic blocking rules are allowed by default
            var basicAllowed = true;
            if (this.documentRule) {
                var documentRule = this.documentRule;
                if (documentRule.isOptionEnabled(exports.NetworkRuleOption.Urlblock)) {
                    basicAllowed = false;
                }
                else if (documentRule.isOptionEnabled(exports.NetworkRuleOption.Genericblock)) {
                    genericAllowed = false;
                }
            }
            // Iterate through the list of rules and fill the MatchingResult
            for (var _i = 0, rules_1 = rules; _i < rules_1.length; _i++) {
                var rule = rules_1[_i];
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Cookie)) {
                    if (!this.cookieRules) {
                        this.cookieRules = [];
                    }
                    this.cookieRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Replace)) {
                    if (!this.replaceRules) {
                        this.replaceRules = [];
                    }
                    this.replaceRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.RemoveParam)) {
                    if (!this.removeParamRules) {
                        this.removeParamRules = [];
                    }
                    this.removeParamRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.RemoveHeader)) {
                    if (!this.removeHeaderRules) {
                        this.removeHeaderRules = [];
                    }
                    this.removeHeaderRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Redirect)) {
                    if (!this.redirectRules) {
                        this.redirectRules = [];
                    }
                    this.redirectRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Csp)) {
                    if (!this.cspRules) {
                        this.cspRules = [];
                    }
                    this.cspRules.push(rule);
                    continue;
                }
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Stealth)) {
                    this.stealthRule = rule;
                    continue;
                }
                // Check blocking rules against $genericblock / $urlblock
                if (!rule.isAllowlist()) {
                    if (!basicAllowed) {
                        continue;
                    }
                    if (!genericAllowed && rule.isGeneric()) {
                        continue;
                    }
                }
                if (!this.basicRule || rule.isHigherPriority(this.basicRule)) {
                    this.basicRule = rule;
                }
            }
        }
        /**
         * GetBasicResult returns a rule that should be applied to the web request.
         * Possible outcomes are:
         * returns nil -- bypass the request.
         * returns a allowlist rule -- bypass the request.
         * returns a blocking rule -- block the request.
         *
         * @return {NetworkRule | null} basic result rule
         */
        MatchingResult.prototype.getBasicResult = function () {
            var basic = this.basicRule;
            if (!basic) {
                // Only document-level frame rule would be returned as a basic result,
                // cause only those rules could block or modify page subrequests.
                // Other frame rules (generichide, elemhide etc) will be used in getCosmeticOption function.
                if (this.documentRule && this.documentRule.isDocumentLevelAllowlistRule()) {
                    basic = this.documentRule;
                }
            }
            // https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#replace-modifier
            // 1. $replace rules have a higher priority than other basic rules (including exception rules).
            //  So if a request corresponds to two different rules one of which has the $replace modifier,
            //  this rule will be applied.
            // 2. $document exception rules and rules with $content or $replace modifiers do disable $replace rules
            //  for requests matching them.
            if (this.replaceRules) {
                if (basic && basic.isAllowlist()) {
                    if (basic.isDocumentAllowlistRule()) {
                        return basic;
                    }
                    if (basic.isOptionEnabled(exports.NetworkRuleOption.Replace)
                        || basic.isOptionEnabled(exports.NetworkRuleOption.Content)) {
                        return basic;
                    }
                }
                return null;
            }
            // https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#redirect-modifier
            // Redirect rules have a high priority
            var redirectRule = this.getRedirectRule();
            if (redirectRule) {
                if (!basic || redirectRule.isHigherPriority(basic)) {
                    return redirectRule;
                }
            }
            return basic;
        };
        /**
         * Returns a bit-flag with the list of cosmetic options
         *
         * @return {CosmeticOption} mask
         */
        MatchingResult.prototype.getCosmeticOption = function () {
            if (!this.basicRule || !this.basicRule.isAllowlist()) {
                return exports.CosmeticOption.CosmeticOptionAll;
            }
            if (this.basicRule.isDocumentAllowlistRule()) {
                return exports.CosmeticOption.CosmeticOptionNone;
            }
            var option = exports.CosmeticOption.CosmeticOptionAll;
            if (this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Elemhide)) {
                option ^= exports.CosmeticOption.CosmeticOptionGenericCSS;
                option ^= exports.CosmeticOption.CosmeticOptionSpecificCSS;
            }
            if (this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Generichide)) {
                option ^= exports.CosmeticOption.CosmeticOptionGenericCSS;
            }
            if (this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Specifichide)) {
                option ^= exports.CosmeticOption.CosmeticOptionSpecificCSS;
            }
            if (this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Jsinject)) {
                option ^= exports.CosmeticOption.CosmeticOptionJS;
            }
            if (this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Content)) {
                option ^= exports.CosmeticOption.CosmeticOptionHtml;
            }
            return option;
        };
        /**
         * Return an array of replace rules
         */
        MatchingResult.prototype.getReplaceRules = function () {
            if (!this.replaceRules) {
                return [];
            }
            // TODO: Look up for allowlist $content rule
            return MatchingResult.filterAdvancedModifierRules(this.replaceRules, function (rule) { return (function (x) { return x.getAdvancedModifierValue() === rule.getAdvancedModifierValue(); }); });
        };
        /**
         * Filters array of rules according to allowlist rules contained.
         * Empty advanced modifier allowlists everything.
         *
         * @param rules
         * @param allowlistPredicate allowlist criteria
         * This function result will be called for testing if rule `x` allowlists rule `r`
         */
        MatchingResult.filterAdvancedModifierRules = function (rules, allowlistPredicate) {
            var _this = this;
            var blockingRules = [];
            var allowlistRules = [];
            for (var _i = 0, rules_2 = rules; _i < rules_2.length; _i++) {
                var rule = rules_2[_i];
                if (rule.isAllowlist()) {
                    allowlistRules.push(rule);
                }
                else {
                    blockingRules.push(rule);
                }
            }
            if (blockingRules.length === 0) {
                return [];
            }
            if (allowlistRules.length === 0) {
                return blockingRules;
            }
            if (allowlistRules.length > 0) {
                var allowlistRuleWithEmptyOption_1 = allowlistRules
                    .find(function (allowlistRule) { return allowlistRule.getAdvancedModifierValue() === ''; });
                var result_1 = [];
                blockingRules.forEach(function (blockRule) {
                    if (allowlistRuleWithEmptyOption_1
                        && !blockRule.isHigherPriority(allowlistRuleWithEmptyOption_1)) {
                        result_1.push(allowlistRuleWithEmptyOption_1);
                        return;
                    }
                    var allowlistingRule = allowlistRules.find(function (a) {
                        return !blockRule.isHigherPriority(a) && allowlistPredicate.call(_this, blockRule)(a);
                    });
                    if (allowlistingRule) {
                        result_1.push(allowlistingRule);
                    }
                    else {
                        result_1.push(blockRule);
                    }
                });
                return result_1.filter(function (item, pos) { return result_1.indexOf(item) == pos; });
            }
            return blockingRules;
        };
        /**
         * Returns an array of csp rules
         */
        MatchingResult.prototype.getCspRules = function () {
            if (!this.cspRules) {
                return [];
            }
            var blockingRules = [];
            var allowlistedRulesByDirective = new Map();
            for (var _i = 0, _a = this.cspRules; _i < _a.length; _i++) {
                var rule = _a[_i];
                if (rule.isAllowlist()) {
                    if (!rule.getAdvancedModifierValue()) { // Global allowlist rule
                        return [rule];
                    }
                    MatchingResult.putWithPriority(rule, undefined, allowlistedRulesByDirective);
                }
                else {
                    blockingRules.push(rule);
                }
            }
            var rulesByDirective = new Map();
            // Collect allowlist and blocking CSP rules in one array
            blockingRules.forEach(function (rule) {
                if (rule.getAdvancedModifierValue()) {
                    var allowlistRule = allowlistedRulesByDirective.get(rule.getAdvancedModifierValue());
                    MatchingResult.putWithPriority(rule, allowlistRule, rulesByDirective);
                }
            });
            return Array.from(rulesByDirective.values());
        };
        /**
         * Returns a redirect rule
         */
        MatchingResult.prototype.getRedirectRule = function () {
            if (!this.redirectRules) {
                return null;
            }
            var result = MatchingResult.filterAdvancedModifierRules(this.redirectRules, function (rule) { return (function (x) { return x.getAdvancedModifierValue() === rule.getAdvancedModifierValue(); }); });
            result = result.filter(function (r) { return !r.isAllowlist(); });
            var conditionalRedirectRules = result.filter(function (x) {
                var redirectModifier = x.getAdvancedModifier();
                return redirectModifier.isRedirectingOnlyBlocked;
            });
            var allWeatherRedirectRules = result.filter(function (x) { return !conditionalRedirectRules.includes(x); });
            if (allWeatherRedirectRules.length > 0) {
                return allWeatherRedirectRules.sort(function (a, b) { return (b.isOptionEnabled(exports.NetworkRuleOption.Important)
                    && !a.isOptionEnabled(exports.NetworkRuleOption.Important) ? 1 : -1); })[0];
            }
            if (conditionalRedirectRules.length === 0) {
                return null;
            }
            var resultRule = conditionalRedirectRules.sort(function (a, b) { return (b.isOptionEnabled(exports.NetworkRuleOption.Important)
                && !a.isOptionEnabled(exports.NetworkRuleOption.Important) ? 1 : -1); })[0];
            var redirectModifier = resultRule.getAdvancedModifier();
            if (redirectModifier && redirectModifier.isRedirectingOnlyBlocked) {
                if (!(this.basicRule && !this.basicRule.isAllowlist())) {
                    return null;
                }
            }
            return resultRule;
        };
        /**
         * Returns an array of cookie rules
         */
        MatchingResult.prototype.getCookieRules = function () {
            if (!this.cookieRules) {
                return [];
            }
            var basic = this.getBasicResult();
            if (basic === null || basic === void 0 ? void 0 : basic.isDocumentAllowlistRule()) {
                return [];
            }
            var allowlistPredicate = function (rule) { return (function (allowlistRule) {
                var allowlistRuleCookieModifier = allowlistRule.getAdvancedModifier();
                var ruleCookieModifier = rule.getAdvancedModifier();
                if (allowlistRule.getAdvancedModifierValue() === rule.getAdvancedModifierValue()) {
                    return true;
                }
                // Matches by cookie name
                if (allowlistRuleCookieModifier.matches(ruleCookieModifier.getCookieName())) {
                    return true;
                }
                return false;
            }); };
            var filtered = MatchingResult.filterAdvancedModifierRules(this.cookieRules, allowlistPredicate);
            return filtered.concat(__spreadArray([], this.cookieRules.filter(function (r) { return r.isAllowlist(); }), true));
        };
        /**
         * Returns an array of removeparam rules
         */
        MatchingResult.prototype.getRemoveParamRules = function () {
            if (!this.removeParamRules) {
                return [];
            }
            return MatchingResult.filterAdvancedModifierRules(this.removeParamRules, 
            // eslint-disable-next-line arrow-body-style
            function (rule) { return (function (x) {
                return x.isHigherPriority(rule) && x.getAdvancedModifierValue() === rule.getAdvancedModifierValue();
            }); });
        };
        /**
         * Returns an array of removeheader rules
         */
        MatchingResult.prototype.getRemoveHeaderRules = function () {
            if (!this.removeHeaderRules) {
                return [];
            }
            if (this.basicRule
                && this.basicRule.isAllowlist()
                && this.basicRule.isOptionEnabled(exports.NetworkRuleOption.Urlblock)) {
                return [];
            }
            return MatchingResult.filterAdvancedModifierRules(this.removeHeaderRules, function (rule) { return (function (x) { return x.getAdvancedModifierValue() === rule.getAdvancedModifierValue(); }); });
        };
        /**
         * Decides which rule should be put into the given map.
         * Compares priorities of the two given rules with the equal CSP directive and the rule that may already in the map.
         *
         * @param rule CSP rule (not null)
         * @param allowlistRule CSP allowlist rule (may be null)
         * @param map Rules mapped by csp directive
         */
        // eslint-disable-next-line max-len
        MatchingResult.putWithPriority = function (rule, allowlistRule, map) {
            var cspDirective = rule.getAdvancedModifierValue();
            var currentRule = cspDirective ? map.get(cspDirective) : null;
            var newRule = rule;
            if (currentRule && !rule.isHigherPriority(currentRule)) {
                newRule = currentRule;
            }
            if (allowlistRule && allowlistRule.isHigherPriority(newRule)) {
                newRule = allowlistRule;
            }
            map.set(cspDirective, newRule);
        };
        /**
         * Looks if there are any matching $badfilter rules and removes
         * matching bad filters from the array (see the $badfilter description for more info)
         *
         * @param rules to filter
         * @return filtered rules
         */
        MatchingResult.removeBadfilterRules = function (rules) {
            var badfilterRules = [];
            for (var _i = 0, rules_3 = rules; _i < rules_3.length; _i++) {
                var rule = rules_3[_i];
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Badfilter)) {
                    badfilterRules.push(rule);
                }
            }
            if (badfilterRules.length > 0) {
                return rules.filter(function (rule) {
                    if (rule.isOptionEnabled(exports.NetworkRuleOption.Badfilter)) {
                        return false;
                    }
                    var isRuleNegated = badfilterRules.some(function (badfilter) { return badfilter.negatesBadfilter(rule); });
                    return !isRuleNegated;
                });
            }
            return rules;
        };
        return MatchingResult;
    }());

    /**
     * Scanner types enum
     */
    var ScannerType;
    (function (ScannerType) {
        /**
         * Scanning for network rules
         */
        ScannerType[ScannerType["NetworkRules"] = 0] = "NetworkRules";
        /**
         * Scanning for cosmetic rules
         */
        ScannerType[ScannerType["CosmeticRules"] = 2] = "CosmeticRules";
        /**
         * Scanning for host rules
         */
        ScannerType[ScannerType["HostRules"] = 4] = "HostRules";
        /**
         * All
         */
        ScannerType[ScannerType["All"] = 6] = "All";
    })(ScannerType || (ScannerType = {}));

    /**
     * Prefix tree implementation
     */
    var TrieNode = /** @class */ (function () {
        /**
         * Creates an instance of a TrieNode with the specified char code.
         *
         * @param code
         */
        function TrieNode(code) {
            this.code = code;
        }
        /**
         * Attaches data to this TrieNode.
         *
         * @param data
         */
        TrieNode.prototype.attach = function (data) {
            if (!this.data) {
                this.data = [];
            }
            this.data.push(data);
        };
        /**
         * Adds the specified string to the Trie and attaches data to it.
         *
         * @param str string to add.
         * @param data data to attach to the leaf node.
         */
        TrieNode.prototype.add = function (str, data) {
            // eslint-disable-next-line @typescript-eslint/no-this-alias
            var root = this;
            for (var i = 0; i < str.length; i += 1) {
                var c = str.charCodeAt(i);
                var next = root.getChild(c);
                if (!next) {
                    next = root.addChild(c);
                }
                root = next;
            }
            root.attach(data);
        };
        /**
         * Traverses this TrieNode and it's children using the specified search string.
         * This method collects all the data that's attached on the way and returns as
         * a result.
         *
         * @param str string to check.
         * @param start index in str where to start traversing from.
         */
        TrieNode.prototype.traverse = function (str, start) {
            var result = [];
            // eslint-disable-next-line @typescript-eslint/no-this-alias
            var current = this;
            for (var i = start; i < str.length; i += 1) {
                var c = str.charCodeAt(i);
                var next = current.getChild(c);
                if (!next) {
                    break;
                }
                if (next.data) {
                    result.push.apply(result, next.data);
                }
                current = next;
            }
            return result;
        };
        /**
         * Traverses this TrieNode and it's children using the specified search string and all substrings.
         *
         * @param str string to check
         * @param len max length to check
         */
        TrieNode.prototype.traverseAll = function (str, len) {
            var data = [];
            for (var i = 0; i <= len; i += 1) {
                var result = this.traverse(str, i);
                if (result) {
                    data.push.apply(data, result);
                }
            }
            return data;
        };
        /**
         * Returns a child node with the specified character code or
         * undefined if not found.
         *
         * @param code character code
         * @returns child node or undefined.
         */
        TrieNode.prototype.getChild = function (code) {
            var children = this.children;
            if (!children) {
                return undefined;
            }
            if (children instanceof TrieNode) {
                if (children.code === code) {
                    return children;
                }
                return undefined;
            }
            return children.get(code);
        };
        /**
         * Adds a new child node with the specified character code.
         *
         * @param code character code.
         * @returns the newly created TrieNode.
         */
        TrieNode.prototype.addChild = function (code) {
            var node = new TrieNode(code);
            if (!this.children) {
                this.children = node;
            }
            else if (this.children instanceof TrieNode) {
                var oldNode = this.children;
                this.children = new Map();
                this.children.set(oldNode.code, oldNode);
                this.children.set(code, node);
            }
            else {
                this.children.set(code, node);
            }
            return node;
        };
        return TrieNode;
    }());

    /**
     * Look up table with underlying prefix tree
     */
    var TrieLookupTable = /** @class */ (function () {
        /**
         * Creates a new instance of the TrieLookupTable.
         *
         * @param storage rules storage. We store "rule indexes" in the lookup table which
         * can be used to retrieve the full rules from the storage.
         */
        function TrieLookupTable(storage) {
            /**
             * Count of rules added to this lookup table.
             */
            this.rulesCount = 0;
            this.ruleStorage = storage;
            this.trie = new TrieNode(0);
        }
        /**
         * Finds all matching rules from the shortcuts lookup table
         *
         * @param request to check
         * @return array of matching rules
         */
        TrieLookupTable.prototype.matchAll = function (request) {
            var rulesIndexes = this.traverse(request);
            return this.matchRules(request, rulesIndexes);
        };
        /**
         * Tries to add the rule to the lookup table.
         * returns true if it was added
         *
         * @param rule to add
         * @param storageIdx index
         * @return {boolean} true if the rule been added
         */
        TrieLookupTable.prototype.addRule = function (rule, storageIdx) {
            var shortcut = rule.getShortcut();
            if (!shortcut || TrieLookupTable.isAnyURLShortcut(shortcut)
                || shortcut.length < SimpleRegex.MIN_SHORTCUT_LENGTH) {
                return false;
            }
            this.trie.add(shortcut, storageIdx);
            this.rulesCount += 1;
            return true;
        };
        /**
         * @return total rules count
         */
        TrieLookupTable.prototype.getRulesCount = function () {
            return this.rulesCount;
        };
        /**
         * For specified request finds matching rules from rules indexes array
         *
         * @param request
         * @param rulesIndexes
         */
        TrieLookupTable.prototype.matchRules = function (request, rulesIndexes) {
            if (!rulesIndexes) {
                return [];
            }
            var result = [];
            for (var j = 0; j < rulesIndexes.length; j += 1) {
                var idx = rulesIndexes[j];
                var rule = this.ruleStorage.retrieveNetworkRule(idx);
                if (rule && rule.match(request, false)) {
                    result.push(rule);
                }
            }
            return result;
        };
        /**
         * Traverses trie
         *
         * @param request
         */
        TrieLookupTable.prototype.traverse = function (request) {
            return this.trie.traverseAll(request.urlLowercase, request.urlLowercase.length);
        };
        /**
         * Checks if the rule potentially matches too many URLs.
         * We'd better use another type of lookup table for this kind of rules.
         *
         * @param shortcut to check
         * @return check result
         */
        TrieLookupTable.isAnyURLShortcut = function (shortcut) {
            // The numbers are basically ("PROTO://".length + 1)
            if (shortcut.length < 6 && shortcut.indexOf('ws:') === 0) {
                return true;
            }
            if (shortcut.length < 7 && shortcut.indexOf('|ws') === 0) {
                return true;
            }
            if (shortcut.length < 9 && shortcut.indexOf('http') === 0) {
                return true;
            }
            return !!(shortcut.length < 10 && shortcut.indexOf('|http') === 0);
        };
        return TrieLookupTable;
    }());

    /**
     * Domain lookup table. Key is the domain name hash.
     */
    var DomainsLookupTable = /** @class */ (function () {
        /**
         * Creates a new instance
         *
         * @param storage rules storage. We store "rule indexes" in the lookup table which
         * can be used to retrieve the full rules from the storage.
         */
        function DomainsLookupTable(storage) {
            /**
             * Count of rules added to this lookup table.
             */
            this.rulesCount = 0;
            /**
             * Domain lookup table. Key is the domain name hash.
             */
            this.domainsLookupTable = new Map();
            this.ruleStorage = storage;
        }
        /**
         * addRule implements the ILookupTable interface for DomainsLookupTable.
         * @param rule
         * @param storageIdx
         */
        DomainsLookupTable.prototype.addRule = function (rule, storageIdx) {
            var _this = this;
            var permittedDomains = rule.getPermittedDomains();
            if (!permittedDomains || permittedDomains.length === 0) {
                return false;
            }
            var hasWildcardDomain = permittedDomains.some(function (d) { return DomainModifier.isWildcardDomain(d); });
            if (hasWildcardDomain) {
                return false;
            }
            permittedDomains.forEach(function (domain) {
                var hash = fastHash(domain);
                // Add the rule to the lookup table
                var rulesIndexes = _this.domainsLookupTable.get(hash);
                if (!rulesIndexes) {
                    rulesIndexes = [];
                }
                rulesIndexes.push(storageIdx);
                _this.domainsLookupTable.set(hash, rulesIndexes);
            });
            this.rulesCount += 1;
            return true;
        };
        /**
         * Implements the ILookupTable interface method.
         */
        DomainsLookupTable.prototype.getRulesCount = function () {
            return this.rulesCount;
        };
        /**
         * Implements the ILookupTable interface method.
         * @param request
         */
        DomainsLookupTable.prototype.matchAll = function (request) {
            var result = [];
            if (!request.sourceHostname) {
                return result;
            }
            var domains = request.subdomains;
            if (request.hostname !== request.sourceHostname) {
                domains.push.apply(domains, request.sourceSubdomains);
            }
            for (var i = 0; i < domains.length; i += 1) {
                var hash = fastHash(domains[i]);
                var rulesIndexes = this.domainsLookupTable.get(hash);
                if (rulesIndexes) {
                    for (var j = 0; j < rulesIndexes.length; j += 1) {
                        var rule = this.ruleStorage.retrieveNetworkRule(rulesIndexes[j]);
                        if (rule && rule.match(request)) {
                            result.push(rule);
                        }
                    }
                }
            }
            return result;
        };
        return DomainsLookupTable;
    }());

    /**
     * Hostname lookup table.
     * For specific kind of rules like '||hostname^' and '||hostname/path' more simple algorithm with hashes is faster.
     */
    var HostnameLookupTable = /** @class */ (function () {
        /**
         * Creates a new instance
         *
         * @param storage rules storage. We store "rule indexes" in the lookup table which
         * can be used to retrieve the full rules from the storage.
         */
        function HostnameLookupTable(storage) {
            /**
             * Count of rules added to this lookup table.
             */
            this.rulesCount = 0;
            /**
             * Domain lookup table. Key is the domain name hash.
             */
            this.hostnameLookupTable = new Map();
            this.ruleStorage = storage;
        }
        /**
         * addRule implements the ILookupTable interface for DomainsLookupTable.
         * @param rule
         * @param storageIdx
         */
        HostnameLookupTable.prototype.addRule = function (rule, storageIdx) {
            var pattern = rule.getPattern();
            var hostname = '';
            // Pattern: '||example.org^'
            if (pattern.startsWith(SimpleRegex.MASK_START_URL) && pattern.endsWith(SimpleRegex.MASK_SEPARATOR)) {
                hostname = pattern.slice(SimpleRegex.MASK_START_URL.length, pattern.length - SimpleRegex.MASK_SEPARATOR.length);
            }
            // Pattern: '||example.org/path'
            if (pattern.startsWith(SimpleRegex.MASK_START_URL) && pattern.indexOf(SimpleRegex.MASK_BACKSLASH) !== -1) {
                var end = pattern.indexOf(SimpleRegex.MASK_BACKSLASH);
                hostname = pattern.slice(SimpleRegex.MASK_START_URL.length, end);
            }
            if (!HostnameLookupTable.isValidHostname(hostname)) {
                return false;
            }
            var hash = fastHash(hostname);
            var rulesIndexes = this.hostnameLookupTable.get(hash);
            if (!rulesIndexes) {
                rulesIndexes = new Array();
                this.hostnameLookupTable.set(hash, rulesIndexes);
            }
            rulesIndexes.push(storageIdx);
            this.rulesCount += 1;
            return true;
        };
        /**
         * Implements the ILookupTable interface method.
         */
        HostnameLookupTable.prototype.getRulesCount = function () {
            return this.rulesCount;
        };
        /**
         * Implements the ILookupTable interface method.
         * @param request
         */
        HostnameLookupTable.prototype.matchAll = function (request) {
            var result = [];
            var domains = request.subdomains;
            for (var i = 0; i < domains.length; i += 1) {
                var hash = fastHash(domains[i]);
                var rulesIndexes = this.hostnameLookupTable.get(hash);
                if (rulesIndexes) {
                    for (var j = 0; j < rulesIndexes.length; j += 1) {
                        var rule = this.ruleStorage.retrieveNetworkRule(rulesIndexes[j]);
                        if (rule && rule.match(request)) {
                            result.push(rule);
                        }
                    }
                }
            }
            return result;
        };
        /**
         * Checks if this hostname string is valid
         *
         * @param hostname
         */
        HostnameLookupTable.isValidHostname = function (hostname) {
            if (!hostname) {
                return false;
            }
            if (hostname.indexOf(SimpleRegex.MASK_ANY_CHARACTER) !== -1) {
                return false;
            }
            if (hostname.indexOf('.') < 0 || hostname.endsWith('.')) {
                return false;
            }
            return true;
        };
        return HostnameLookupTable;
    }());

    /**
     * Sequence scan lookup table of rules for which we could not find a shortcut
     * and could not place it to the shortcuts lookup table.
     * In common case of rule there is always a way to just check a rule.match().
     */
    var SeqScanLookupTable = /** @class */ (function () {
        function SeqScanLookupTable() {
            /**
             * Count of rules added to this lookup table.
             */
            this.rulesCount = 0;
            /**
             * Rules for which we could not find a shortcut and could not place it to the shortcuts lookup table.
             */
            this.rules = [];
        }
        /**
         * addRule implements the ILookupTable interface for SeqScanLookupTable.
         * @param rule
         */
        SeqScanLookupTable.prototype.addRule = function (rule) {
            if (!this.rules.includes(rule)) {
                this.rules.push(rule);
                this.rulesCount += 1;
                return true;
            }
            return false;
        };
        /**
         * Implements the ILookupTable interface method.
         */
        SeqScanLookupTable.prototype.getRulesCount = function () {
            return this.rulesCount;
        };
        /**
         * Implements the ILookupTable interface method.
         * @param request
         */
        SeqScanLookupTable.prototype.matchAll = function (request) {
            var result = [];
            for (var i = 0; i < this.rules.length; i += 1) {
                var r = this.rules[i];
                if (r.match(request)) {
                    result.push(r);
                }
            }
            return result;
        };
        return SeqScanLookupTable;
    }());

    /**
     * NetworkEngine is the engine that supports quick search over network rules
     */
    var NetworkEngine = /** @class */ (function () {
        /**
         * Builds an instance of the network engine
         *
         * @param storage an object for a rules storage.
         * @param skipStorageScan create an instance without storage scanning.
         */
        function NetworkEngine(storage, skipStorageScan) {
            if (skipStorageScan === void 0) { skipStorageScan = false; }
            this.ruleStorage = storage;
            this.rulesCount = 0;
            this.domainsLookupTable = new DomainsLookupTable(storage);
            this.hostnameLookupTable = new HostnameLookupTable(storage);
            this.shortcutsLookupTable = new TrieLookupTable(storage);
            this.seqScanLookupTable = new SeqScanLookupTable();
            if (skipStorageScan) {
                return;
            }
            var scanner = this.ruleStorage.createRuleStorageScanner(ScannerType.NetworkRules);
            while (scanner.scan()) {
                var indexedRule = scanner.getRule();
                if (indexedRule
                    && indexedRule.rule instanceof NetworkRule) {
                    this.addRule(indexedRule.rule, indexedRule.index);
                }
            }
        }
        /**
         * Match searches over all filtering rules loaded to the engine
         * It returns rule if a match was found alongside the matching rule
         *
         * @param request to check
         * @return rule matching request or null
         */
        NetworkEngine.prototype.match = function (request) {
            var networkRules = this.matchAll(request);
            if (networkRules.length === 0) {
                return null;
            }
            var result = new MatchingResult(networkRules, null);
            return result.getBasicResult();
        };
        /**
         * Finds all rules matching the specified request regardless of the rule types
         * It will find both allowlist and blacklist rules
         *
         * @param request to check
         * @return array of matching rules
         */
        NetworkEngine.prototype.matchAll = function (request) {
            // First check by shortcuts
            var result = this.hostnameLookupTable.matchAll(request);
            result.push.apply(result, (this.shortcutsLookupTable.matchAll(request)));
            result.push.apply(result, (this.domainsLookupTable.matchAll(request)));
            result.push.apply(result, (this.seqScanLookupTable.matchAll(request)));
            return result;
        };
        /**
         * Adds rule to the network engine
         *
         * @param rule
         * @param storageIdx
         */
        NetworkEngine.prototype.addRule = function (rule, storageIdx) {
            if (!this.hostnameLookupTable.addRule(rule, storageIdx)) {
                if (!this.shortcutsLookupTable.addRule(rule, storageIdx)) {
                    if (!this.domainsLookupTable.addRule(rule, storageIdx)) {
                        this.seqScanLookupTable.addRule(rule, storageIdx);
                    }
                }
            }
            this.rulesCount += 1;
        };
        return NetworkEngine;
    }());

    /**
     * Request represents a web request with all it's necessary properties
     */
    var Request$1 = /** @class */ (function () {
        /**
         * Creates an instance of a Request
         *
         * @param url - request URL
         * @param sourceUrl - source URL
         * @param requestType - request type
         *
         * @throws
         */
        function Request(url, sourceUrl, requestType) {
            /**
             * the request is for a given Hostname, and not for a URL, and we don't really know what protocol it is.
             * This can be true for DNS requests, or for HTTP CONNECT, or SNI matching.
             */
            this.isHostnameRequest = false;
            /**
            * Splits subdomains and returns all subdomains (including the hostname itself)
            *
            * @param tldResult
            * @returns array of subdomains
            */
            this.getSubdomains = function (tldResult) {
                var domain = tldResult.domain, hostname = tldResult.hostname, subdomain = tldResult.subdomain, publicSuffix = tldResult.publicSuffix;
                var subdomainsResult = [];
                if (!domain) {
                    if (hostname) {
                        subdomainsResult.push(hostname);
                        return subdomainsResult;
                    }
                    return [];
                }
                if (publicSuffix) {
                    subdomainsResult.push(publicSuffix);
                }
                subdomainsResult.push(domain);
                if (!subdomain) {
                    return subdomainsResult;
                }
                var parts = subdomain.split('.');
                var incrementDomain = domain;
                for (var i = parts.length - 1; i >= 0; i -= 1) {
                    incrementDomain = "".concat(parts[i], ".").concat(incrementDomain);
                    subdomainsResult.push(incrementDomain);
                }
                return subdomainsResult;
            };
            this.url = url;
            this.requestType = requestType;
            this.urlLowercase = Request.compactUrl(url).toLowerCase();
            this.sourceUrl = Request.compactUrl(sourceUrl);
            var tldResult = parse(url);
            this.hostname = tldResult.hostname;
            this.domain = tldResult.domain;
            this.subdomains = this.getSubdomains(tldResult);
            if (sourceUrl) {
                var sourceTldResult = parse(sourceUrl);
                this.sourceHostname = sourceTldResult.hostname;
                this.sourceDomain = sourceTldResult.domain;
                this.sourceSubdomains = this.getSubdomains(sourceTldResult);
            }
            else {
                this.sourceHostname = null;
                this.sourceDomain = null;
                this.sourceSubdomains = [];
            }
            if (this.sourceDomain) {
                this.thirdParty = this.domain !== this.sourceDomain;
            }
            else {
                this.thirdParty = null;
            }
        }
        /**
         * We cut the url in performance purposes
         * @param url
         */
        Request.compactUrl = function (url) {
            var compacted = url;
            if (compacted && compacted.length > Request.MAX_URL_MATCH_LENGTH) {
                compacted = compacted.substring(0, Request.MAX_URL_MATCH_LENGTH);
            }
            return compacted;
        };
        /**
         * Max url length for matching
         * Some urls are really long and slow down matching, so we cut them to this length.
         */
        Request.MAX_URL_MATCH_LENGTH = 2000;
        return Request;
    }());

    /**
     * DnsResult contains a network rule and host rules matching request
     */
    var DnsResult = /** @class */ (function () {
        function DnsResult() {
            /**
             * BasicRule - a network rule matching the request.
             */
            this.basicRule = null;
            /**
             * Host rules
             */
            this.hostRules = [];
        }
        return DnsResult;
    }());

    /**
     * DNSEngine combines host rules and network rules and is supposed to quickly find
     * matching rules for hostnames.
     * First, it looks over network rules and returns first rule found.
     * Then, if nothing found, it looks up the host rules.
     */
    var DnsEngine = /** @class */ (function () {
        /**
         * Builds an instance of dns engine
         *
         * @param storage
         */
        function DnsEngine(storage) {
            this.ruleStorage = storage;
            this.rulesCount = 0;
            this.lookupTable = new Map();
            this.networkEngine = new NetworkEngine(storage, true);
            var scanner = this.ruleStorage.createRuleStorageScanner(ScannerType.HostRules);
            while (scanner.scan()) {
                var indexedRule = scanner.getRule();
                if (indexedRule) {
                    if (indexedRule.rule instanceof HostRule) {
                        this.addRule(indexedRule.rule, indexedRule.index);
                    }
                    else if (indexedRule.rule instanceof NetworkRule
                        && indexedRule.rule.isHostLevelNetworkRule()) {
                        this.networkEngine.addRule(indexedRule.rule, indexedRule.index);
                    }
                }
            }
        }
        /**
         * Match searches over all filtering and host rules loaded to the engine
         *
         * @param hostname to check
         * @return dns result object
         */
        DnsEngine.prototype.match = function (hostname) {
            var result = new DnsResult();
            if (!hostname) {
                return result;
            }
            var url = "http://".concat(hostname, "/");
            var request = new Request$1(url, url, exports.RequestType.Document);
            request.isHostnameRequest = true;
            var networkRule = this.networkEngine.match(request);
            if (networkRule) {
                // Network rules always have higher priority
                result.basicRule = networkRule;
                return result;
            }
            var hash = fastHash(hostname);
            var rulesIndexes = this.lookupTable.get(hash);
            if (rulesIndexes) {
                for (var j = 0; j < rulesIndexes.length; j += 1) {
                    var rule = this.ruleStorage.retrieveHostRule(rulesIndexes[j]);
                    if (rule && rule.match(hostname)) {
                        result.hostRules.push(rule);
                    }
                }
            }
            return result;
        };
        /**
         * Adds rule to engine
         *
         * @param rule
         * @param storageIdx
         */
        DnsEngine.prototype.addRule = function (rule, storageIdx) {
            var _this = this;
            rule.getHostnames().forEach(function (hostname) {
                var hash = fastHash(hostname);
                // Add the rule to the lookup table
                var rulesIndexes = _this.lookupTable.get(hash);
                if (!rulesIndexes) {
                    rulesIndexes = [];
                }
                rulesIndexes.push(storageIdx);
                _this.lookupTable.set(hash, rulesIndexes);
            });
            this.rulesCount += 1;
        };
        return DnsEngine;
    }());

    var lru = {exports: {}};

    (function (module, exports) {
    !function(g,c){c(exports);}(commonjsGlobal,function(g){const c=Symbol("newer"),e=Symbol("older");class n{constructor(a,b){typeof a!=="number"&&(b=a,a=0),this.size=0,this.limit=a,this.oldest=this.newest=void 0,this._keymap=new Map(),b&&(this.assign(b),a<1&&(this.limit=this.size));}_markEntryAsUsed(a){if(a===this.newest)return;a[c]&&(a===this.oldest&&(this.oldest=a[c]),a[c][e]=a[e]),a[e]&&(a[e][c]=a[c]),a[c]=void 0,a[e]=this.newest,this.newest&&(this.newest[c]=a),this.newest=a;}assign(a){let b,d=this.limit||Number.MAX_VALUE;this._keymap.clear();let m=a[Symbol.iterator]();for(let h=m.next();!h.done;h=m.next()){let f=new l(h.value[0],h.value[1]);this._keymap.set(f.key,f),b?(b[c]=f,f[e]=b):this.oldest=f,b=f;if(d--==0)throw new Error("overflow")}this.newest=b,this.size=this._keymap.size;}get(a){var b=this._keymap.get(a);return b?(this._markEntryAsUsed(b),b.value):void 0}set(a,b){var d=this._keymap.get(a);return d?(d.value=b,this._markEntryAsUsed(d),this):(this._keymap.set(a,d=new l(a,b)),this.newest?(this.newest[c]=d,d[e]=this.newest):this.oldest=d,this.newest=d,++this.size,this.size>this.limit&&this.shift(),this)}shift(){var a=this.oldest;if(a)return this.oldest[c]?(this.oldest=this.oldest[c],this.oldest[e]=void 0):(this.oldest=void 0,this.newest=void 0),a[c]=a[e]=void 0,this._keymap.delete(a.key),--this.size,[a.key,a.value]}find(a){let b=this._keymap.get(a);return b?b.value:void 0}has(a){return this._keymap.has(a)}delete(a){var b=this._keymap.get(a);return b?(this._keymap.delete(b.key),b[c]&&b[e]?(b[e][c]=b[c],b[c][e]=b[e]):b[c]?(b[c][e]=void 0,this.oldest=b[c]):b[e]?(b[e][c]=void 0,this.newest=b[e]):this.oldest=this.newest=void 0,this.size--,b.value):void 0}clear(){this.oldest=this.newest=void 0,this.size=0,this._keymap.clear();}keys(){return new j(this.oldest)}values(){return new k(this.oldest)}entries(){return this}[Symbol.iterator](){return new i(this.oldest)}forEach(a,b){typeof b!=="object"&&(b=this);let d=this.oldest;for(;d;)a.call(b,d.value,d.key,this),d=d[c];}toJSON(){for(var a=new Array(this.size),b=0,d=this.oldest;d;)a[b++]={key:d.key,value:d.value},d=d[c];return a}toString(){for(var a="",b=this.oldest;b;)a+=String(b.key)+":"+b.value,b=b[c],b&&(a+=" < ");return a}}g.LRUMap=n;function l(a,b){this.key=a,this.value=b,this[c]=void 0,this[e]=void 0;}function i(a){this.entry=a;}i.prototype[Symbol.iterator]=function(){return this},i.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:[a.key,a.value]}):{done:!0,value:void 0}};function j(a){this.entry=a;}j.prototype[Symbol.iterator]=function(){return this},j.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:a.key}):{done:!0,value:void 0}};function k(a){this.entry=a;}k.prototype[Symbol.iterator]=function(){return this},k.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:a.value}):{done:!0,value:void 0}};});

    }(lru, lru.exports));

    /**
     * CosmeticLookupTable lets quickly lookup cosmetic rules for the specified hostname.
     * It is primarily used by the {@see CosmeticEngine}.
     */
    var CosmeticLookupTable = /** @class */ (function () {
        /**
         * Creates a new instance
         *
         * @param storage rules storage. We store "rule indexes" in the lookup table which
         * can be used to retrieve the full rules from the storage.
         */
        function CosmeticLookupTable(storage) {
            this.byHostname = new Map();
            this.wildcardRules = [];
            this.genericRules = [];
            this.allowlist = new Map();
            this.ruleStorage = storage;
        }
        /**
         * Adds rule to the appropriate collection
         * @param rule
         * @param storageIdx
         */
        CosmeticLookupTable.prototype.addRule = function (rule, storageIdx) {
            if (rule.isAllowlist()) {
                var key = rule.getContent();
                var existingRules = this.allowlist.get(key) || [];
                existingRules.push(storageIdx);
                this.allowlist.set(key, existingRules);
                return;
            }
            if (rule.isGeneric()) {
                this.genericRules.push(rule);
                return;
            }
            var domains = rule.getPermittedDomains();
            if (domains) {
                var hasWildcardDomain = domains.some(function (d) { return DomainModifier.isWildcardDomain(d); });
                if (hasWildcardDomain) {
                    this.wildcardRules.push(rule);
                    return;
                }
                for (var _i = 0, domains_1 = domains; _i < domains_1.length; _i++) {
                    var domain = domains_1[_i];
                    var tldResult = parse(domain);
                    // tldResult.domain equals to eTLD domain,
                    // e.g. sub.example.uk.org would result in example.uk.org
                    var parsedDomain = tldResult.domain || domain;
                    var key = fastHash(parsedDomain);
                    var rules = this.byHostname.get(key) || [];
                    rules.push(storageIdx);
                    this.byHostname.set(key, rules);
                }
            }
        };
        /**
         * Finds rules by hostname
         * @param request
         * @param subdomains
         */
        CosmeticLookupTable.prototype.findByHostname = function (request) {
            var result = [];
            var subdomains = request.subdomains;
            var _loop_1 = function (i) {
                var subdomain = subdomains[i];
                var rulesIndexes = this_1.byHostname.get(fastHash(subdomain));
                if (rulesIndexes) {
                    // Filtering out duplicates
                    rulesIndexes = rulesIndexes.filter(function (v, index) { return rulesIndexes.indexOf(v) === index; });
                    for (var j = 0; j < rulesIndexes.length; j += 1) {
                        var rule = this_1.ruleStorage.retrieveRule(rulesIndexes[j]);
                        if (rule && rule.match(request)) {
                            result.push(rule);
                        }
                    }
                }
            };
            var this_1 = this;
            // Iterate over all sub-domains
            for (var i = 0; i < subdomains.length; i += 1) {
                _loop_1(i);
            }
            result.push.apply(result, this.wildcardRules.filter(function (r) { return r.match(request); }));
            return result.filter(function (rule) { return !rule.isAllowlist(); });
        };
        /**
         * Checks if the rule is disabled on the specified hostname.
         * @param request
         * @param rule
         */
        CosmeticLookupTable.prototype.isAllowlisted = function (request, rule) {
            var rulesIndexes = this.allowlist.get(rule.getContent());
            if (!rulesIndexes) {
                return false;
            }
            for (var j = 0; j < rulesIndexes.length; j += 1) {
                var r = this.ruleStorage.retrieveRule(rulesIndexes[j]);
                if (r && r.match(request)) {
                    return true;
                }
            }
            return false;
        };
        return CosmeticLookupTable;
    }());

    var CosmeticRuleModifiers;
    (function (CosmeticRuleModifiers) {
        CosmeticRuleModifiers["PATH"] = "path";
        CosmeticRuleModifiers["DOMAIN"] = "domain";
    })(CosmeticRuleModifiers || (CosmeticRuleModifiers = {}));
    var CosmeticRuleModifiersSyntax = {
        OPEN_BRACKET: '[',
        CLOSE_BRACKET: ']',
        SPECIAL_SYMBOL: '$',
        DELIMITER: ',',
        ASSIGNER: '=',
        ESCAPE_CHARACTER: '\\',
    };

    var cosmeticRuleModifiersList = Object.values(CosmeticRuleModifiers);
    /**
     * Helper class for parsing text of cosmetic rules
     * used by CosmeticRule and [Filter compiler](https://github.com/AdguardTeam/FiltersCompiler)
     *
     *
     * The cosmetic rule contains of the following parts:
     *
     * `pattern##content`
     *
     * `pattern` contains the list of the rule modifiers and domains.
     *
     * `##` is a marker (might be a different marker depending on the rule type).
     * You can find the list of markers in the CosmeticRuleMarker enumeration.
     *
     * `content` might be a CSS selector, a scriptlet or something else, depending on the rule type.
     */
    var CosmeticRuleParser = /** @class */ (function () {
        function CosmeticRuleParser() {
        }
        /**
         * Parse the rule's pattern, cosmetic marker and the content parts from the rule text.
         * If the content is empty, throws a SyntaxError.
         *
         * @param ruleText
         * @returns Object with pattern, marker and content text parts
         */
        CosmeticRuleParser.parseRuleTextByMarker = function (ruleText) {
            var _a = findCosmeticRuleMarker(ruleText), markerIndex = _a[0], marker = _a[1];
            if (marker === null) {
                throw new SyntaxError('Not a cosmetic rule');
            }
            var content = ruleText.substring(markerIndex + marker.length).trim();
            if (!content) {
                throw new SyntaxError('Rule content is empty');
            }
            var pattern;
            if (markerIndex > 0) {
                pattern = ruleText.substring(0, markerIndex);
            }
            return {
                pattern: pattern,
                marker: marker,
                content: content,
            };
        };
        /**
         * Extracts the rule modifiers and domains from the rule pattern.
         * @param rulePattern
         * @returns Object with modifiers and domains text parts
         */
        CosmeticRuleParser.parseRulePatternText = function (rulePattern) {
            var OPEN_BRACKET = CosmeticRuleModifiersSyntax.OPEN_BRACKET, CLOSE_BRACKET = CosmeticRuleModifiersSyntax.CLOSE_BRACKET, SPECIAL_SYMBOL = CosmeticRuleModifiersSyntax.SPECIAL_SYMBOL, ESCAPE_CHARACTER = CosmeticRuleModifiersSyntax.ESCAPE_CHARACTER;
            if (!rulePattern.startsWith("".concat(OPEN_BRACKET + SPECIAL_SYMBOL))) {
                return { domainsText: rulePattern };
            }
            var closeBracketIndex;
            // The first two characters cannot be closing brackets
            for (var i = 2; i < rulePattern.length; i += 1) {
                if (rulePattern[i] === CLOSE_BRACKET && rulePattern[i - 1] !== ESCAPE_CHARACTER) {
                    closeBracketIndex = i;
                    break;
                }
            }
            if (!closeBracketIndex) {
                throw new SyntaxError('Can\'t parse modifiers list');
            }
            // Handle this case: `[$]`
            if (closeBracketIndex === 2) {
                throw new SyntaxError('Modifiers list can\'t be empty');
            }
            var modifiersText = rulePattern.slice(2, closeBracketIndex);
            var domainsText;
            if (closeBracketIndex < rulePattern.length - 1) {
                domainsText = rulePattern.slice(closeBracketIndex + 1);
            }
            return {
                modifiersText: modifiersText,
                domainsText: domainsText,
            };
        };
        /**
         * Parses the list of modifiers. Parsing is done in the same way as it's done in the NetworkRule, i.e.
         * we have a comma-separated list of modifier-value pairs.
         * If we encounter an invalid modifier, this method throws a SyntaxError.
         *
         * @param modifiersText - list of modifiers splited by comma
         * @returns - modifiers collection object
         */
        CosmeticRuleParser.parseRuleModifiers = function (modifiersText) {
            if (!modifiersText) {
                return null;
            }
            var ESCAPE_CHARACTER = CosmeticRuleModifiersSyntax.ESCAPE_CHARACTER, DELIMITER = CosmeticRuleModifiersSyntax.DELIMITER, ASSIGNER = CosmeticRuleModifiersSyntax.ASSIGNER;
            var modifiersTextArray = splitByDelimiterWithEscapeCharacter(modifiersText, DELIMITER, ESCAPE_CHARACTER, false, false);
            var modifiers = Object.create(null);
            for (var i = 0; i < modifiersTextArray.length; i += 1) {
                var modifierText = modifiersTextArray[i];
                var assignerIndex = modifierText.indexOf(ASSIGNER);
                if (assignerIndex === -1) {
                    throw new SyntaxError('Modifier must have assigned value');
                }
                var modifierKey = modifierText.substring(0, assignerIndex);
                if (cosmeticRuleModifiersList.includes(modifierKey)) {
                    var modifierValue = modifierText.substring(assignerIndex + 1);
                    modifiers[modifierKey] = modifierValue;
                }
                else {
                    throw new SyntaxError("'".concat(modifierKey, "' is not valid modifier"));
                }
            }
            return modifiers;
        };
        /**
         * Parses the rule pattern and extracts the permitted/restricted domains and the unescaped path modifier value,
         * If domains are declared through $domain modifier and pattern domain list, this method throws a SyntaxError.
         * @param rulePattern - rule pattern text
         *
         * @returns Object with permitted/restricted domains list and the path modifier string value
         */
        CosmeticRuleParser.parseRulePattern = function (rulePattern) {
            var _a = CosmeticRuleParser.parseRulePatternText(rulePattern), domainsText = _a.domainsText, modifiersText = _a.modifiersText;
            var domains = domainsText;
            var path;
            var modifiers = CosmeticRuleParser.parseRuleModifiers(modifiersText);
            if (modifiers) {
                if (modifiers.path) {
                    path = modifiers.path;
                    if (SimpleRegex.isRegexPattern(path)) {
                        path = SimpleRegex.unescapeRegexSpecials(path, SimpleRegex.reModifierPatternEscapedSpecialCharacters);
                    }
                }
                if (modifiers.domain) {
                    if (domains) {
                        throw new SyntaxError('The $domain modifier is not allowed in a domain-specific rule');
                    }
                    else {
                        domains = modifiers.domain;
                    }
                }
            }
            var permittedDomains;
            var restrictedDomains;
            // Skip wildcard domain
            if (domains && domains !== SimpleRegex.MASK_ANY_CHARACTER) {
                var separator = (modifiers === null || modifiers === void 0 ? void 0 : modifiers.domain) ? PIPE_SEPARATOR : COMMA_SEPARATOR;
                var domainModifier = new DomainModifier(domains, separator);
                if (domainModifier.permittedDomains) {
                    permittedDomains = domainModifier.permittedDomains;
                }
                if (domainModifier.restrictedDomains) {
                    restrictedDomains = domainModifier.restrictedDomains;
                }
            }
            return {
                path: path,
                permittedDomains: permittedDomains,
                restrictedDomains: restrictedDomains,
            };
        };
        return CosmeticRuleParser;
    }());

    /**
     * CosmeticRuleType is an enumeration of the possible
     * cosmetic rule types.
     * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#cosmetic-rules
     */
    exports.CosmeticRuleType = void 0;
    (function (CosmeticRuleType) {
        /**
         * Cosmetic rules that just hide page elements.
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#element-hiding-rules
         */
        CosmeticRuleType[CosmeticRuleType["ElementHiding"] = 0] = "ElementHiding";
        /**
         * Cosmetic rules that allow adding custom CSS styles.
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#cosmetic-css-rules
         */
        CosmeticRuleType[CosmeticRuleType["Css"] = 1] = "Css";
        /**
         * Cosmetic rules that allow executing custom JS scripts.
         * Some restrictions are applied to this type of rules by default.
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#javascript-rules
         */
        CosmeticRuleType[CosmeticRuleType["Js"] = 2] = "Js";
        /**
         * Special type of rules that allows filtering HTML code of web pages.
         * https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#html-filtering-rules
         */
        CosmeticRuleType[CosmeticRuleType["Html"] = 3] = "Html";
    })(exports.CosmeticRuleType || (exports.CosmeticRuleType = {}));
    /**
     * Pseudo class indicators. They are used to detect if rule is extended or not even if rule does not
     * have extended css marker
     */
    var EXT_CSS_PSEUDO_INDICATORS = ['[-ext-has=', '[-ext-contains=', '[-ext-has-text=',
        '[-ext-matches-css=', '[-ext-matches-css-before=', '[-ext-matches-css-after=', ':has(', ':has-text(',
        ':contains(', ':matches-css(', ':matches-css-before(', ':matches-css-after(', ':-abp-has(', ':-abp-contains(',
        ':if(', ':if-not(', ':xpath(', ':nth-ancestor(', ':upward(', ':remove(',
        ':matches-attr(', ':matches-property(', ':is('];
    /**
     * Implements a basic cosmetic rule.
     *
     * Cosmetic rules syntax are almost similar and looks like this:
     * ```
     * rule = [domains] "marker" content
     * domains = [domain0, domain1[, ...[, domainN]]]
     * ```
     *
     * The rule type is defined by the `marker` value, you can find the list of them
     * in the {@see CosmeticRuleMarker} enumeration.
     *
     * What matters, though, is what's in the `content` part of it.
     *
     * Examples:
     * * `example.org##.banner` -- element hiding rule
     * * `example.org#$#.banner { display: block; }` -- CSS rule
     * * `example.org#%#window.x=1;` -- JS rule
     * * `example.org#%#//scriptlet('scriptlet-name')` -- Scriptlet rule
     * * `example.org$$div[id="test"]` -- HTML filtering rule
     */
    var CosmeticRule = /** @class */ (function () {
        /**
         * Creates an instance of the {@link CosmeticRule}.
         * It parses the rule and extracts the permitted/restricted domains,
         * and also the cosmetic rule's content.
         *
         * Depending on the rule type, the content might be transformed in
         * one of the helper classes, or kept as string when it's appropriate.
         *
         * @param ruleText - original rule text.
         * @param filterListId - ID of the filter list this rule belongs to.
         *
         * @throws error if it fails to parse the rule.
         */
        function CosmeticRule(ruleText, filterListId) {
            this.allowlist = false;
            this.extendedCss = false;
            this.permittedDomains = undefined;
            this.restrictedDomains = undefined;
            /**
             * Js script to execute
             */
            this.script = undefined;
            /**
             * Js script to execute - debug
             */
            this.scriptVerbose = undefined;
            /**
             * Needed to avoid reinvoking scriptVerbose for scriptlets rules
             */
            this.verboseInvokedForDomain = undefined;
            /**
             * If the rule contains scriptlet content
             */
            this.isScriptlet = false;
            this.ruleText = ruleText;
            this.filterListId = filterListId;
            var _a = CosmeticRuleParser.parseRuleTextByMarker(ruleText), pattern = _a.pattern, marker = _a.marker, content = _a.content;
            this.content = content;
            this.type = CosmeticRule.parseType(marker);
            this.extendedCss = isExtCssMarker(marker);
            if (!this.extendedCss
                && (this.type === exports.CosmeticRuleType.ElementHiding
                    || this.type === exports.CosmeticRuleType.Css)) {
                // additional check if rule is extended css rule by pseudo class indicators
                for (var i = 0; i < EXT_CSS_PSEUDO_INDICATORS.length; i += 1) {
                    if (this.content.indexOf(EXT_CSS_PSEUDO_INDICATORS[i]) !== -1) {
                        this.extendedCss = true;
                        break;
                    }
                }
            }
            CosmeticRule.validate(ruleText, this.type, content, this.extendedCss);
            if (pattern) {
                // This means that the marker is preceded by the list of domains and modifiers
                // Now it's a good time to parse them.
                var _b = CosmeticRuleParser.parseRulePattern(pattern), path = _b.path, permittedDomains = _b.permittedDomains, restrictedDomains = _b.restrictedDomains;
                if (path) {
                    this.pathModifier = new Pattern(path);
                }
                if (permittedDomains) {
                    this.permittedDomains = permittedDomains;
                }
                if (restrictedDomains) {
                    this.restrictedDomains = restrictedDomains;
                }
            }
            this.allowlist = CosmeticRule.parseAllowlist(marker);
            this.isScriptlet = this.content.startsWith(ADG_SCRIPTLET_MASK);
        }
        /**
         * Parses first pseudo class from the specified CSS selector
         *
         * @param selector
         * @returns pseudo class name if found or null
         */
        CosmeticRule.parsePseudoClass = function (selector) {
            var beginIndex = 0;
            var nameStartIndex = -1;
            var squareBracketIndex = 0;
            while (squareBracketIndex >= 0) {
                nameStartIndex = selector.indexOf(':', beginIndex);
                if (nameStartIndex < 0) {
                    return null;
                }
                if (nameStartIndex > 0 && selector.charAt(nameStartIndex - 1) === '\\') {
                    // Escaped colon character
                    return null;
                }
                squareBracketIndex = selector.indexOf('[', beginIndex);
                while (squareBracketIndex >= 0) {
                    if (nameStartIndex > squareBracketIndex) {
                        var squareEndBracketIndex = selector.indexOf(']', squareBracketIndex + 1);
                        beginIndex = squareEndBracketIndex + 1;
                        if (nameStartIndex < squareEndBracketIndex) {
                            // Means that colon character is somewhere inside attribute selector
                            // Something like a[src^="http://domain.com"]
                            break;
                        }
                        if (squareEndBracketIndex > 0) {
                            squareBracketIndex = selector.indexOf('[', beginIndex);
                        }
                        else {
                            // bad rule, example: a[src="http:
                            return null;
                        }
                    }
                    else {
                        squareBracketIndex = -1;
                        break;
                    }
                }
            }
            var nameEndIndex = indexOfAny(selector, [' ', ',', '\t', '>', '(', '[', '.', '#', ':', '+', '~', '"', '\''], nameStartIndex + 1);
            if (nameEndIndex < 0) {
                nameEndIndex = selector.length;
            }
            var name = selector.substring(nameStartIndex, nameEndIndex);
            if (name.length <= 1) {
                // Either empty name or a pseudo element (like ::content)
                return null;
            }
            return name;
        };
        CosmeticRule.prototype.getText = function () {
            return this.ruleText;
        };
        CosmeticRule.prototype.getFilterListId = function () {
            return this.filterListId;
        };
        /**
         * Cosmetic rule type (always present)
         */
        CosmeticRule.prototype.getType = function () {
            return this.type;
        };
        /**
         * Allowlist means that this rule is meant to disable other rules.
         * For instance, https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#elemhide-exceptions
         */
        CosmeticRule.prototype.isAllowlist = function () {
            return this.allowlist;
        };
        /**
         * Gets the rule content. The meaning of this field depends on the rule type.
         * For instance, for an element hiding rule, this is just a CSS selector.
         * While, for a CSS rule, this is a CSS selector + style.
         */
        CosmeticRule.prototype.getContent = function () {
            return this.content;
        };
        /**
         * Get rule script string
         * @param debug
         */
        CosmeticRule.prototype.getScript = function (debug) {
            if (debug === void 0) { debug = false; }
            return debug ? this.scriptVerbose : this.script;
        };
        /**
         * Gets list of permitted domains.
         */
        CosmeticRule.prototype.getPermittedDomains = function () {
            return this.permittedDomains;
        };
        /**
         * Returns true if the rule is considered "generic"
         * "generic" means that the rule is not restricted to a limited set of domains
         * Please note that it might be forbidden on some domains, though.
         *
         * @return {boolean}
         */
        CosmeticRule.prototype.isGeneric = function () {
            return !this.permittedDomains || this.permittedDomains.length === 0;
        };
        /**
         * Gets list of restricted domains.
         */
        CosmeticRule.prototype.getRestrictedDomains = function () {
            return this.restrictedDomains;
        };
        CosmeticRule.prototype.isExtendedCss = function () {
            return this.extendedCss;
        };
        /**
         * Match returns true if this rule can be used on the specified request.
         *
         * @param request - request to check
         */
        CosmeticRule.prototype.match = function (request) {
            if (!this.permittedDomains && !this.restrictedDomains && !this.pathModifier) {
                return true;
            }
            if (this.matchesRestrictedDomains(request.hostname)) {
                /**
                 * Domain or host is restricted
                 * i.e. ~example.org##rule
                 */
                return false;
            }
            if (this.hasPermittedDomains()) {
                if (!DomainModifier.isDomainOrSubdomainOfAny(request.hostname, this.permittedDomains)) {
                    /**
                     * Domain is not among permitted
                     * i.e. example.org##rule and we're checking example.org
                     */
                    return false;
                }
            }
            if (this.pathModifier) {
                var path = getRelativeUrl(request.urlLowercase);
                if (path) {
                    return this.pathModifier.matchPathPattern(path);
                }
                return false;
            }
            return true;
        };
        CosmeticRule.parseType = function (marker) {
            switch (marker) {
                case exports.CosmeticRuleMarker.ElementHiding:
                case exports.CosmeticRuleMarker.ElementHidingExtCSS:
                    return exports.CosmeticRuleType.ElementHiding;
                case exports.CosmeticRuleMarker.ElementHidingException:
                case exports.CosmeticRuleMarker.ElementHidingExtCSSException:
                    return exports.CosmeticRuleType.ElementHiding;
                case exports.CosmeticRuleMarker.Css:
                case exports.CosmeticRuleMarker.CssExtCSS:
                    return exports.CosmeticRuleType.Css;
                case exports.CosmeticRuleMarker.CssException:
                case exports.CosmeticRuleMarker.CssExtCSSException:
                    return exports.CosmeticRuleType.Css;
                case exports.CosmeticRuleMarker.Js:
                    return exports.CosmeticRuleType.Js;
                case exports.CosmeticRuleMarker.JsException:
                    return exports.CosmeticRuleType.Js;
                case exports.CosmeticRuleMarker.Html:
                    return exports.CosmeticRuleType.Html;
                case exports.CosmeticRuleMarker.HtmlException:
                    return exports.CosmeticRuleType.Html;
                default:
                    throw new SyntaxError('Unsupported rule type');
            }
        };
        /**
         * Determines if rule is allowlist rule
         * @param marker
         * @private
         */
        CosmeticRule.parseAllowlist = function (marker) {
            switch (marker) {
                case exports.CosmeticRuleMarker.ElementHidingException:
                case exports.CosmeticRuleMarker.ElementHidingExtCSSException:
                case exports.CosmeticRuleMarker.CssException:
                case exports.CosmeticRuleMarker.CssExtCSSException:
                case exports.CosmeticRuleMarker.JsException:
                case exports.CosmeticRuleMarker.HtmlException:
                    return true;
                default:
                    return false;
            }
        };
        /**
         * Validate pseudo-classes
         *
         * @param ruleText
         * @param ruleContent
         * @throws SyntaxError
         */
        CosmeticRule.validatePseudoClasses = function (ruleText, ruleContent) {
            var pseudoClass = CosmeticRule.parsePseudoClass(ruleContent);
            if (pseudoClass !== null) {
                if (CosmeticRule.SUPPORTED_PSEUDO_CLASSES.indexOf(pseudoClass) < 0) {
                    throw new SyntaxError("Unknown pseudo class: ".concat(ruleContent));
                }
            }
        };
        /**
         * Simple validation for elemhide rules
         *
         * @param ruleText
         * @param ruleContent
         * @throws SyntaxError
         */
        CosmeticRule.validateElemhideRule = function (ruleText, ruleContent) {
            if (ruleText.startsWith(SimpleRegex.MASK_START_URL)) {
                throw new SyntaxError('Element hiding rule shouldn\'t start with "||"');
            }
            if (CosmeticRule.ELEMHIDE_VALIDATION_REGEX.test(ruleContent)) {
                throw new SyntaxError('Invalid elemhide rule, style presented');
            }
        };
        CosmeticRule.validateJsRules = function (ruleText, ruleContent) {
            if (ruleContent.startsWith(ADG_SCRIPTLET_MASK)) {
                if (!scriptlets.isValidScriptletRule(ruleText)) {
                    throw new SyntaxError('Invalid scriptlet');
                }
            }
        };
        /**
         * Validates css injection rules
         *
         * @param ruleText
         * @param ruleContent
         * @throws SyntaxError
         */
        CosmeticRule.validateCssRules = function (ruleText, ruleContent) {
            // Simple validation for css injection rules
            if (!/{.+}/.test(ruleContent)) {
                throw new SyntaxError('Invalid CSS modifying rule, no style presented');
            }
            // discard css inject rules containing "url"
            // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1196
            if (/{.*url\(.*\)/gi.test(ruleContent)) {
                throw new SyntaxError('CSS modifying rule with \'url\' was omitted');
            }
            // discard css inject rules containing other unsafe selectors
            // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1920
            if (/{.*image-set\(.*\)/gi.test(ruleContent) ||
                /{.*image\(.*\)/gi.test(ruleContent) ||
                /{.*cross-fade\(.*\)/gi.test(ruleContent)) {
                throw new SyntaxError('CSS modifying rule with unsafe style was omitted');
            }
            // Prohibit "\" character in style of CSS injection rules
            // Check slash character only after the index of last opening curly brackets
            if (ruleContent.indexOf('\\', ruleContent.lastIndexOf('{')) > -1) {
                throw new SyntaxError('CSS injection rule with \'\\\' was omitted');
            }
        };
        /**
         * Checks if the rule has permitted domains
         */
        CosmeticRule.prototype.hasPermittedDomains = function () {
            return this.permittedDomains != null && this.permittedDomains.length > 0;
        };
        /**
         * Checks if the rule has restricted domains
         */
        CosmeticRule.prototype.hasRestrictedDomains = function () {
            return this.restrictedDomains != null && this.restrictedDomains.length > 0;
        };
        /**
         * Checks if the hostname matches permitted domains
         * @param hostname
         */
        CosmeticRule.prototype.matchesPermittedDomains = function (hostname) {
            return this.hasPermittedDomains() && DomainModifier.isDomainOrSubdomainOfAny(hostname, this.permittedDomains);
        };
        /**
         * Checks if the hostname matches the restricted domains.
         * @param hostname
         */
        CosmeticRule.prototype.matchesRestrictedDomains = function (hostname) {
            return this.hasRestrictedDomains()
                && DomainModifier.isDomainOrSubdomainOfAny(hostname, this.restrictedDomains);
        };
        /**
         * Validates cosmetic rule text
         * @param ruleText
         * @param type
         * @param content
         * @param isExtCss
         * @private
         */
        CosmeticRule.validate = function (ruleText, type, content, isExtCss) {
            if (type !== exports.CosmeticRuleType.Css
                && type !== exports.CosmeticRuleType.Js
                && type !== exports.CosmeticRuleType.Html) {
                CosmeticRule.validatePseudoClasses(ruleText, content);
                if (hasUnquotedSubstring(content, '{')) {
                    throw new SyntaxError('Invalid cosmetic rule, wrong brackets');
                }
            }
            if (type === exports.CosmeticRuleType.ElementHiding) {
                CosmeticRule.validateElemhideRule(ruleText, content);
            }
            if (type === exports.CosmeticRuleType.Css) {
                CosmeticRule.validateCssRules(ruleText, content);
            }
            if (type === exports.CosmeticRuleType.Js) {
                CosmeticRule.validateJsRules(ruleText, content);
            }
            if ((!isExtCss && hasUnquotedSubstring(content, '/*')) ||
                hasUnquotedSubstring(content, ' /*') ||
                hasUnquotedSubstring(content, ' //')) {
                throw new SyntaxError('Cosmetic rule should not contain comments');
            }
        };
        /**
         * The problem with pseudo-classes is that any unknown pseudo-class makes browser ignore the whole CSS rule,
         * which contains a lot more selectors. So, if CSS selector contains a pseudo-class, we should try to validate it.
         * <p>
         * One more problem with pseudo-classes is that they are actively used in uBlock, hence it may mess AG styles.
         */
        CosmeticRule.SUPPORTED_PSEUDO_CLASSES = [':active',
            ':checked', ':contains', ':disabled', ':empty', ':enabled', ':first-child', ':first-of-type',
            ':focus', ':has', ':has-text', ':hover', ':if', ':if-not', ':in-range', ':invalid', ':lang',
            ':last-child', ':last-of-type', ':link', ':matches-css', ':matches-css-before', ':matches-css-after',
            ':not', ':nth-child', ':nth-last-child', ':nth-last-of-type', ':nth-of-type',
            ':only-child', ':only-of-type', ':optional', ':out-of-range', ':read-only',
            ':read-write', ':required', ':root', ':target', ':valid', ':visited',
            ':-abp-has', ':-abp-contains', ':xpath', ':nth-ancestor', ':upward', ':remove',
            ':matches-attr', ':matches-property', ':is', ':where'];
        CosmeticRule.ELEMHIDE_VALIDATION_REGEX = / {.+}/;
        return CosmeticRule;
    }());

    /**
     * CosmeticEngine combines all the cosmetic rules and allows to quickly
     * find all rules matching this or that hostname
     * It is primarily used by the {@see Engine}
     */
    var CosmeticEngine = /** @class */ (function () {
        /**
         * Builds instance of cosmetic engine
         *
         * @param ruleStorage
         * @param skipStorageScan create an instance without storage scanning
         */
        function CosmeticEngine(ruleStorage, skipStorageScan) {
            if (skipStorageScan === void 0) { skipStorageScan = false; }
            this.ruleStorage = ruleStorage;
            this.rulesCount = 0;
            this.elementHidingLookupTable = new CosmeticLookupTable(ruleStorage);
            this.cssLookupTable = new CosmeticLookupTable(ruleStorage);
            this.jsLookupTable = new CosmeticLookupTable(ruleStorage);
            this.htmlLookupTable = new CosmeticLookupTable(ruleStorage);
            if (skipStorageScan) {
                return;
            }
            var scanner = this.ruleStorage.createRuleStorageScanner(ScannerType.CosmeticRules);
            while (scanner.scan()) {
                var indexedRule = scanner.getRule();
                if (indexedRule
                    && indexedRule.rule instanceof CosmeticRule) {
                    this.addRule(indexedRule.rule, indexedRule.index);
                }
            }
        }
        /**
         * Adds rules into appropriate tables
         * @param rule
         * @param storageIdx
         */
        CosmeticEngine.prototype.addRule = function (rule, storageIdx) {
            switch (rule.getType()) {
                case exports.CosmeticRuleType.ElementHiding: {
                    this.elementHidingLookupTable.addRule(rule, storageIdx);
                    break;
                }
                case exports.CosmeticRuleType.Css: {
                    this.cssLookupTable.addRule(rule, storageIdx);
                    break;
                }
                case exports.CosmeticRuleType.Js: {
                    this.jsLookupTable.addRule(rule, storageIdx);
                    break;
                }
                case exports.CosmeticRuleType.Html: {
                    this.htmlLookupTable.addRule(rule, storageIdx);
                    break;
                }
            }
            this.rulesCount += 1;
        };
        /**
         * Checks if bitwise mask matches option
         * @param option
         * @param targetOption
         */
        CosmeticEngine.matchOption = function (option, targetOption) {
            return (option & targetOption) === targetOption;
        };
        /**
         * Prepares cosmetic result by request
         *
         * @param request - request to match
         * @param option mask of enabled cosmetic types
         * @return CosmeticResult
         */
        CosmeticEngine.prototype.match = function (request, option) {
            var includeGeneric = CosmeticEngine.matchOption(option, exports.CosmeticOption.CosmeticOptionGenericCSS);
            var includeSpecific = CosmeticEngine.matchOption(option, exports.CosmeticOption.CosmeticOptionSpecificCSS);
            var includeJs = CosmeticEngine.matchOption(option, exports.CosmeticOption.CosmeticOptionJS);
            var includeHtml = CosmeticEngine.matchOption(option, exports.CosmeticOption.CosmeticOptionHtml);
            var cosmeticResult = new CosmeticResult();
            if (includeGeneric) {
                CosmeticEngine.appendGenericRules(cosmeticResult.elementHiding, this.elementHidingLookupTable, request);
                CosmeticEngine.appendGenericRules(cosmeticResult.CSS, this.cssLookupTable, request);
            }
            if (includeSpecific) {
                CosmeticEngine.appendSpecificRules(cosmeticResult.elementHiding, this.elementHidingLookupTable, request);
                CosmeticEngine.appendSpecificRules(cosmeticResult.CSS, this.cssLookupTable, request);
            }
            if (includeJs) {
                CosmeticEngine.appendGenericRules(cosmeticResult.JS, this.jsLookupTable, request);
                CosmeticEngine.appendSpecificRules(cosmeticResult.JS, this.jsLookupTable, request);
            }
            if (includeHtml) {
                if (includeGeneric) {
                    CosmeticEngine.appendGenericRules(cosmeticResult.Html, this.htmlLookupTable, request);
                }
                CosmeticEngine.appendSpecificRules(cosmeticResult.Html, this.htmlLookupTable, request);
            }
            return cosmeticResult;
        };
        /**
         * Selects generic rules and appends rules content to cosmetic result
         * @param cosmeticResult
         * @param lookupTable
         * @param request
         */
        CosmeticEngine.appendGenericRules = function (cosmeticResult, lookupTable, request) {
            for (var _i = 0, _a = lookupTable.genericRules; _i < _a.length; _i++) {
                var genericRule = _a[_i];
                if (!lookupTable.isAllowlisted(request, genericRule)
                    && genericRule.match(request)) {
                    cosmeticResult.append(genericRule, request);
                }
            }
        };
        /**
         * Selects specific rules and appends rules content to cosmetic result
         * @param cosmeticResult
         * @param lookupTable
         * @param request
         */
        CosmeticEngine.appendSpecificRules = function (cosmeticResult, lookupTable, request) {
            var hostnameRules = lookupTable.findByHostname(request);
            if (hostnameRules.length > 0) {
                for (var _i = 0, hostnameRules_1 = hostnameRules; _i < hostnameRules_1.length; _i++) {
                    var rule = hostnameRules_1[_i];
                    if (!lookupTable.isAllowlisted(request, rule)) {
                        cosmeticResult.append(rule, request);
                    }
                }
            }
        };
        return CosmeticEngine;
    }());

    /**
     * Engine represents the filtering engine with all the loaded rules
     */
    var Engine = /** @class */ (function () {
        /**
         * Creates an instance of an Engine
         * Parses the filtering rules and creates a filtering engine of them
         *
         * @param ruleStorage storage
         * @param skipStorageScan create an instance without storage scanning
         * @throws
         */
        function Engine(ruleStorage, skipStorageScan) {
            if (skipStorageScan === void 0) { skipStorageScan = false; }
            this.ruleStorage = ruleStorage;
            this.networkEngine = new NetworkEngine(ruleStorage, skipStorageScan);
            this.cosmeticEngine = new CosmeticEngine(ruleStorage, skipStorageScan);
            this.resultCache = new lru.exports.LRUMap(Engine.REQUEST_CACHE_SIZE);
        }
        /**
         * Loads rules to engine
         */
        Engine.prototype.loadRules = function () {
            var scanner = this.ruleStorage.createRuleStorageScanner(ScannerType.NetworkRules | ScannerType.CosmeticRules);
            while (scanner.scan()) {
                this.addRule(scanner.getRule());
            }
        };
        /**
         * Async loads rules to engine
         *
         * @param chunkSize size of rules chunk to load at a time
         */
        Engine.prototype.loadRulesAsync = function (chunkSize) {
            return __awaiter(this, void 0, void 0, function () {
                var scanner, counter;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            scanner = this.ruleStorage.createRuleStorageScanner(ScannerType.NetworkRules | ScannerType.CosmeticRules);
                            counter = 0;
                            _a.label = 1;
                        case 1:
                            if (!scanner.scan()) return [3 /*break*/, 4];
                            counter += 1;
                            if (!(counter >= chunkSize)) return [3 /*break*/, 3];
                            counter = 0;
                            /**
                             * In some cases UI thread becomes blocked while adding rules to engine,
                             * that't why we create filter rules using chunks of the specified length
                             * Rules creation is rather slow operation so we should
                             * use setTimeout calls to give UI thread some time.
                             */
                            // eslint-disable-next-line @typescript-eslint/no-loop-func
                            return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 1); })];
                        case 2:
                            /**
                             * In some cases UI thread becomes blocked while adding rules to engine,
                             * that't why we create filter rules using chunks of the specified length
                             * Rules creation is rather slow operation so we should
                             * use setTimeout calls to give UI thread some time.
                             */
                            // eslint-disable-next-line @typescript-eslint/no-loop-func
                            _a.sent();
                            _a.label = 3;
                        case 3:
                            this.addRule(scanner.getRule());
                            return [3 /*break*/, 1];
                        case 4: return [2 /*return*/];
                    }
                });
            });
        };
        /**
         * Matches the specified request against the filtering engine and returns the matching result.
         *
         * @param request - request to check
         * @param frameRule - source document rule or null
         * @return matching result
         */
        Engine.prototype.matchRequest = function (request, frameRule) {
            if (frameRule === void 0) { frameRule = null; }
            var cacheKey = "".concat(request.url, "#").concat(request.sourceHostname, "#").concat(request.requestType);
            /**
             * Add frame url text to the key to avoid caching,
             * because allowlist rules are not stored in the engine
             * AG-12694
             */
            if (frameRule) {
                cacheKey += "#".concat(frameRule.getText());
            }
            var res = this.resultCache.get(cacheKey);
            if (res) {
                return res;
            }
            var networkRules = this.networkEngine.matchAll(request);
            var result = new MatchingResult(networkRules, frameRule);
            this.resultCache.set(cacheKey, result);
            return result;
        };
        /**
         * Matches current frame and returns document-level allowlist rule if found.
         *
         * @param frameUrl
         */
        Engine.prototype.matchFrame = function (frameUrl) {
            var sourceRequest = new Request$1(frameUrl, '', exports.RequestType.Document);
            var sourceRules = this.networkEngine.matchAll(sourceRequest);
            sourceRules = MatchingResult.removeBadfilterRules(sourceRules);
            var result = null;
            sourceRules.forEach(function (r) {
                if (r.isDocumentLevelAllowlistRule()) {
                    if (!result || r.isHigherPriority(result)) {
                        result = r;
                    }
                }
            });
            return result;
        };
        /**
         * Gets cosmetic result for the specified hostname and cosmetic options
         *
         * @param request host to check
         * @param option mask of enabled cosmetic types
         * @return cosmetic result
         */
        Engine.prototype.getCosmeticResult = function (request, option) {
            return this.cosmeticEngine.match(request, option);
        };
        /**
         * Gets rules count
         */
        Engine.prototype.getRulesCount = function () {
            return this.networkEngine.rulesCount + this.cosmeticEngine.rulesCount;
        };
        /**
         * Adds rules to engines
         *
         * @param indexedRule
         */
        Engine.prototype.addRule = function (indexedRule) {
            if (indexedRule) {
                if (indexedRule.rule instanceof NetworkRule) {
                    this.networkEngine.addRule(indexedRule.rule, indexedRule.index);
                }
                else if (indexedRule.rule instanceof CosmeticRule) {
                    this.cosmeticEngine.addRule(indexedRule.rule, indexedRule.index);
                }
            }
        };
        /**
         * Request's cache size
         * Used as both source rules and others limit.
         * The value is based on benchmark runs.
         */
        Engine.REQUEST_CACHE_SIZE = 500;
        return Engine;
    }());

    /**
     * Rule with index
     */
    var IndexedRule = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param rule
         * @param index
         */
        function IndexedRule(rule, index) {
            this.rule = rule;
            this.index = index;
        }
        return IndexedRule;
    }());
    /**
     * Rule with storage index
     */
    var IndexedStorageRule = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param rule
         * @param index
         */
        function IndexedStorageRule(rule, index) {
            this.rule = rule;
            this.index = index;
        }
        return IndexedStorageRule;
    }());

    /**
     * Rule builder class
     */
    var RuleFactory = /** @class */ (function () {
        function RuleFactory() {
        }
        /**
         * Creates rule of suitable class from text string
         * It returns null if the line is empty or if it is a comment
         *
         * @param text rule string
         * @param filterListId list id
         * @param ignoreNetwork do not create network rules
         * @param ignoreCosmetic do not create cosmetic rules
         * @param ignoreHost do not create host rules
         * @return IRule object or null
         */
        RuleFactory.createRule = function (text, filterListId, ignoreNetwork, ignoreCosmetic, ignoreHost) {
            if (ignoreNetwork === void 0) { ignoreNetwork = false; }
            if (ignoreCosmetic === void 0) { ignoreCosmetic = false; }
            if (ignoreHost === void 0) { ignoreHost = true; }
            if (!text || RuleFactory.isComment(text)) {
                return null;
            }
            if (RuleFactory.isShort(text)) {
                exports.logger.info("The rule is too short: ".concat(text));
            }
            var line = text.trim();
            try {
                if (RuleFactory.isCosmetic(line)) {
                    if (ignoreCosmetic) {
                        return null;
                    }
                    return new CosmeticRule(line, filterListId);
                }
                if (!ignoreHost) {
                    var hostRule = RuleFactory.createHostRule(line, filterListId);
                    if (hostRule) {
                        return hostRule;
                    }
                }
                if (!ignoreNetwork) {
                    return new NetworkRule(line, filterListId);
                }
            }
            catch (e) {
                exports.logger.info("Error: \"".concat(e.message, "\" in the rule: \"").concat(line, "\""));
            }
            return null;
        };
        /**
         * Creates host rule from text
         *
         * @param ruleText
         * @param filterListId
         */
        RuleFactory.createHostRule = function (ruleText, filterListId) {
            var rule = new HostRule(ruleText, filterListId);
            return rule.isInvalid() ? null : rule;
        };
        /**
         * Checks if rule is short
         */
        RuleFactory.isShort = function (rule) {
            if (!rule) {
                return true;
            }
            return !!(rule && rule.length <= 3);
        };
        /**
         * Checks if the rule is cosmetic or not.
         * @param ruleText - rule text to check.
         */
        RuleFactory.isCosmetic = function (ruleText) {
            var marker = findCosmeticRuleMarker(ruleText);
            return marker[0] !== -1;
        };
        /**
         * If text is comment
         *
         * @param text
         */
        RuleFactory.isComment = function (text) {
            if (text.charAt(0) === '!') {
                return true;
            }
            if (text.charAt(0) === '#') {
                if (text.length === 1) {
                    return true;
                }
                // Now we should check that this is not a cosmetic rule
                return !RuleFactory.isCosmetic(text);
            }
            return false;
        };
        return RuleFactory;
    }());

    /**
     * Rule scanner implements an interface for reading filtering rules.
     */
    var RuleScanner = /** @class */ (function () {
        /**
         * NewRuleScanner returns a new RuleScanner to read from r.
         *
         * @param reader source of the filtering rules
         * @param listId filter list ID
         * @param configuration config object
         */
        function RuleScanner(reader, listId, configuration) {
            /**
             *  Current rule
             */
            this.currentRule = null;
            /**
             * Index of the beginning of the current rule
             */
            this.currentRuleIndex = 0;
            /**
             * Current position in the reader
             */
            this.currentPos = 0;
            this.reader = reader;
            this.listId = listId;
            this.ignoreCosmetic = !!configuration.ignoreCosmetic
                || ((configuration.scannerType & ScannerType.CosmeticRules) !== ScannerType.CosmeticRules);
            this.ignoreNetwork = (configuration.scannerType & ScannerType.NetworkRules) !== ScannerType.NetworkRules;
            this.ignoreHost = (configuration.scannerType & ScannerType.HostRules) !== ScannerType.HostRules;
            this.ignoreJS = !!configuration.ignoreJS;
            this.ignoreUnsafe = !!configuration.ignoreUnsafe;
        }
        /**
         * Scan advances the RuleScanner to the next rule, which will then be available
         * through the Rule method.
         *
         * @return false when the scan stops, either by
         * reaching the end of the input or an error.
        */
        RuleScanner.prototype.scan = function () {
            while (true) {
                var lineIndex = this.currentPos;
                var line = this.readNextLine();
                if (line === null) {
                    return false;
                }
                if (line) {
                    var rule = RuleFactory.createRule(line, this.listId, this.ignoreNetwork, this.ignoreCosmetic, this.ignoreHost);
                    if (rule && !this.isIgnored(rule)) {
                        this.currentRule = rule;
                        this.currentRuleIndex = lineIndex;
                        return true;
                    }
                }
            }
        };
        /**
         * @return the most recent rule generated by a call to Scan, and the index of this rule's text.
         */
        RuleScanner.prototype.getRule = function () {
            if (this.currentRule) {
                return new IndexedRule(this.currentRule, this.currentRuleIndex);
            }
            return null;
        };
        /**
         * Reads the next line and returns it
         *
         * @return next line string or null
         */
        RuleScanner.prototype.readNextLine = function () {
            var line = this.reader.readLine();
            if (line != null) {
                this.currentPos += line.length + 1;
                return line.trim();
            }
            return null;
        };
        /**
         * Checks if the rule should be ignored by this scanner
         *
         * @param rule to check
         * @return is rule ignored
         */
        RuleScanner.prototype.isIgnored = function (rule) {
            if (!this.ignoreCosmetic && !this.ignoreJS && !this.ignoreUnsafe) {
                return false;
            }
            if (rule instanceof CosmeticRule) {
                if (this.ignoreCosmetic) {
                    return true;
                }
                // Ignore JS type rules
                return (this.ignoreJS && rule.getType() === exports.CosmeticRuleType.Js);
            }
            if (this.ignoreUnsafe) {
                if (rule instanceof NetworkRule) {
                    if (rule.getAdvancedModifier() && (rule.getAdvancedModifier() instanceof RemoveHeaderModifier)) {
                        return true;
                    }
                }
            }
            return false;
        };
        return RuleScanner;
    }());

    /**
     * Reads string line by line
     */
    var StringLineReader = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param text
         */
        function StringLineReader(text) {
            /**
             * Current position
             */
            this.currentIndex = 0;
            this.text = text;
        }
        /**
         * Reads next line
         *
         * @return text or null on end
         */
        StringLineReader.prototype.readLine = function () {
            if (this.currentIndex === -1) {
                return null;
            }
            var startIndex = this.currentIndex;
            this.currentIndex = this.text.indexOf('\n', startIndex);
            if (this.currentIndex === -1) {
                return this.text.substring(startIndex);
            }
            this.currentIndex += 1;
            // - 1 in order to exclude EOL
            return this.text.substring(startIndex, this.currentIndex - 1);
        };
        return StringLineReader;
    }());

    /**
     * List identifier max value.
     * We use "number" type for storage indexes, so we have some limits for list identifiers,
     * We line number for rule index, so if we save 11 ranks for rules, then we have 6 ranks left for list ids.
     * Check RuleStorageScanner class for more info.
     */
    var LIST_ID_MAX_VALUE = Math.pow(10, 6);
    /**
     * StringRuleList represents a string-based rule list
     */
    var StringRuleList = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param listId
         * @param ruleText
         * @param ignoreCosmetic (Optional) default false
         * @param ignoreJS (Optional) default false
         * @param ignoreUnsafe (Optional) default false
         */
        function StringRuleList(listId, ruleText, ignoreCosmetic, ignoreJS, ignoreUnsafe) {
            if (listId >= LIST_ID_MAX_VALUE) {
                throw new Error("Invalid list identifier, it must be less than ".concat(LIST_ID_MAX_VALUE));
            }
            this.id = listId;
            this.rulesText = ruleText;
            this.ignoreCosmetic = !!ignoreCosmetic;
            this.ignoreJS = !!ignoreJS;
            this.ignoreUnsafe = !!ignoreUnsafe;
        }
        /**
         * Close does nothing as here's nothing to close in the StringRuleList
         */
        // eslint-disable-next-line class-methods-use-this
        StringRuleList.prototype.close = function () {
            // Empty
        };
        /**
         * @return the rule list identifier
         */
        StringRuleList.prototype.getId = function () {
            return this.id;
        };
        /**
         * Creates a new rules scanner that reads the list contents
         * @return scanner object
         */
        StringRuleList.prototype.newScanner = function (scannerType) {
            var reader = new StringLineReader(this.rulesText);
            return new RuleScanner(reader, this.id, {
                scannerType: scannerType,
                ignoreCosmetic: this.ignoreCosmetic,
                ignoreJS: this.ignoreJS,
                ignoreUnsafe: this.ignoreUnsafe,
            });
        };
        /**
         * Finds rule text by its index.
         * If there's no rule by that index or rule is invalid, it will return null
         *
         * @param ruleIdx
         * @return rule text or null
         */
        StringRuleList.prototype.retrieveRuleText = function (ruleIdx) {
            if (ruleIdx < 0 || ruleIdx >= this.rulesText.length) {
                return null;
            }
            var endOfLine = this.rulesText.indexOf('\n', ruleIdx);
            if (endOfLine === -1) {
                endOfLine = this.rulesText.length;
            }
            var line = this.rulesText.substring(ruleIdx, endOfLine).trim();
            if (!line) {
                return null;
            }
            return line;
        };
        return StringRuleList;
    }());

    /**
     * RuleStorageScanner scans multiple RuleScanner instances
     * The rule index is built from the rule index in the list + the list ID
     * In the index number we consider decimal part as listId and integer part as ruleId
    */
    var RuleStorageScanner = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param scanners
         */
        function RuleStorageScanner(scanners) {
            /**
             * Current scanner
             */
            this.currentScanner = null;
            /**
             * Index of the current scanner
             */
            this.currentScannerIdx = -1;
            this.scanners = scanners;
        }
        /**
         * Scan advances the RuleStorageScanner to the next rule, which will then be available
         * through the Rule method. It returns false when the scan stops, either by
         * reaching the end of the input or an error.
         *
         * @return true if there is some result
        */
        RuleStorageScanner.prototype.scan = function () {
            if (this.scanners.length === 0) {
                return false;
            }
            if (!this.currentScanner) {
                this.currentScannerIdx = 0;
                this.currentScanner = this.scanners[this.currentScannerIdx];
            }
            while (true) {
                if (this.currentScanner.scan()) {
                    return true;
                }
                // Take the next scanner or just return false if there's nothing more
                if (this.currentScannerIdx === (this.scanners.length - 1)) {
                    return false;
                }
                this.currentScannerIdx += 1;
                this.currentScanner = this.scanners[this.currentScannerIdx];
            }
        };
        /**
         * Rule returns the most recent rule generated by a call to Scan, and the index of this rule.
         * See ruleListIdxToStorageIdx for more information on what this index is.
        */
        RuleStorageScanner.prototype.getRule = function () {
            if (!this.currentScanner) {
                return null;
            }
            var rule = this.currentScanner.getRule();
            if (!rule) {
                return null;
            }
            var index = RuleStorageScanner.ruleListIdxToStorageIdx(rule.rule.getFilterListId(), rule.index);
            return new IndexedStorageRule(rule.rule, index);
        };
        /**
         * ruleListIdxToStorageIdx converts pair of listID and rule list index
         * to "storage index" number
         *
         * @param listId
         * @param ruleIdx
         */
        RuleStorageScanner.ruleListIdxToStorageIdx = function (listId, ruleIdx) {
            return listId / LIST_ID_MAX_VALUE + ruleIdx;
        };
        /**
         * Converts the "storage index" to two integers:
         * listID -- rule list identifier
         * ruleIdx -- index of the rule in the list
         *
         * @param storageIdx
         * @return [listId, ruleIdx]
         */
        RuleStorageScanner.storageIdxToRuleListIdx = function (storageIdx) {
            var listId = Math.round((storageIdx % 1) * LIST_ID_MAX_VALUE);
            var ruleIdx = Math.trunc(storageIdx);
            return [listId, ruleIdx];
        };
        return RuleStorageScanner;
    }());

    /**
     * Rule list's cache
     */
    var ListCache = /** @class */ (function () {
        /**
         * Constructor
         */
        function ListCache() {
            this.cache = new Map();
        }
        /**
         * @param key
         * @return rule for specified key
         */
        ListCache.prototype.get = function (key) {
            return this.cache.get(key);
        };
        /**
         * Sets rule for specified key
         *
         * @param key
         * @param rule
         */
        ListCache.prototype.set = function (key, rule) {
            this.cache.set(key, rule);
        };
        return ListCache;
    }());

    /**
     * RuleStorage is an abstraction that combines several rule lists
     * It can be scanned using RuleStorageScanner, and also it allows
     * retrieving rules by its index

     * The idea is to keep rules in a serialized format (even original format in the case of FileRuleList)
     * and create them in a lazy manner only when we really need them. When the filtering engine is
     * being initialized, we need to scan the rule lists once in order to fill up the lookup tables.
     * We use rule indexes as a unique rule identifier instead of the rule itself.
     * The rule is created (see RetrieveRule) only when there's a chance that it's needed.

     * Rule index is an int64 value that actually consists of two int32 values:
     * One is the rule list identifier, and the second is the index of the rule inside of that list.
    */
    var RuleStorage = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param lists rule lists array
         *
         * @throws on duplicate lists
         */
        function RuleStorage(lists) {
            var _this = this;
            this.lists = lists;
            this.listsMap = new Map();
            this.cache = new Map();
            this.lists.forEach(function (list) {
                var filterListId = list.getId();
                if (_this.listsMap.get(filterListId)) {
                    throw new Error("Duplicate list ID: ".concat(filterListId));
                }
                _this.listsMap.set(filterListId, list);
            });
        }
        /**
         * Creates a new instance of RuleStorageScanner.
         * It can be used to read and parse all the storage contents.
         *
         * @return scanner instance
         */
        RuleStorage.prototype.createRuleStorageScanner = function (scannerType) {
            var scanners = this.lists.map(function (list) { return list.newScanner(scannerType); });
            return new RuleStorageScanner(scanners);
        };
        /**
         * Looks for the filtering rule in this storage
         *
         * @param storageIdx the lookup index that you can get from the rule storage scanner
         * @param ignoreHost rules could be retrieved as host rules
         */
        RuleStorage.prototype.retrieveRule = function (storageIdx, ignoreHost) {
            if (ignoreHost === void 0) { ignoreHost = true; }
            var _a = RuleStorageScanner.storageIdxToRuleListIdx(storageIdx), listId = _a[0], ruleIdx = _a[1];
            var rule = this.getFromCache(listId, ruleIdx);
            if (rule) {
                return rule;
            }
            var list = this.listsMap.get(listId);
            if (!list) {
                // List doesn't exist
                return null;
            }
            var ruleText = list.retrieveRuleText(ruleIdx);
            if (!ruleText) {
                return null;
            }
            var result = RuleFactory.createRule(ruleText, listId, false, false, ignoreHost);
            if (result) {
                this.saveToCache(listId, ruleIdx, result);
            }
            return result;
        };
        /**
         * RetrieveNetworkRule is a helper method that retrieves a network rule from the storage
         *
         * @param storageIdx
         * @return the rule or nil in any other case (not found or error)
         */
        RuleStorage.prototype.retrieveNetworkRule = function (storageIdx) {
            var rule = this.retrieveRule(storageIdx);
            if (!rule) {
                return null;
            }
            if (rule instanceof NetworkRule) {
                return rule;
            }
            return null;
        };
        /**
         * RetrieveHostRule is a helper method that retrieves a host rule from the storage
         *
         * @param storageIdx
         * @return the rule or nil in any other case (not found or error)
         */
        RuleStorage.prototype.retrieveHostRule = function (storageIdx) {
            var rule = this.retrieveRule(storageIdx, false);
            if (!rule) {
                return null;
            }
            if (rule instanceof HostRule) {
                return rule;
            }
            return null;
        };
        /**
         * Saves rule to cache
         *
         * @param listId
         * @param ruleIdx
         * @param rule
         */
        RuleStorage.prototype.saveToCache = function (listId, ruleIdx, rule) {
            var listCache = this.cache.get(listId);
            if (!listCache) {
                listCache = new ListCache();
                this.cache.set(listId, listCache);
            }
            listCache.set(ruleIdx, rule);
        };
        /**
         * Retrieves rule form cache
         *
         * @param listId
         * @param ruleIdx
         */
        RuleStorage.prototype.getFromCache = function (listId, ruleIdx) {
            var listCache = this.cache.get(listId);
            if (!listCache) {
                return undefined;
            }
            return listCache.get(ruleIdx);
        };
        return RuleStorage;
    }());

    /**
     * Rule converter class
     */
    var RuleConverter = /** @class */ (function () {
        function RuleConverter() {
        }
        /**
         * Converts rules text
         *
         * @param rulesText
         * @param conversionOptions
         */
        RuleConverter.convertRules = function (rulesText, conversionOptions) {
            if (conversionOptions === void 0) { conversionOptions = {}; }
            var result = [];
            var lines = rulesText.split(/\r?\n/);
            for (var _i = 0, lines_1 = lines; _i < lines_1.length; _i++) {
                var line = lines_1[_i];
                try {
                    result.push.apply(result, RuleConverter.convertRule(line, conversionOptions));
                }
                catch (e) {
                    exports.logger.warn(e.message);
                }
            }
            return result.join('\n');
        };
        /**
         * Convert external scriptlet rule to AdGuard scriptlet syntax
         *
         * @param rule
         * @param conversionOptions
         */
        RuleConverter.convertRule = function (rule, conversionOptions) {
            if (conversionOptions === void 0) { conversionOptions = {}; }
            if (rule.startsWith(SimpleRegex.MASK_COMMENT)
                || rule.trim() === '') {
                return [rule.trim()];
            }
            var comment = RuleConverter.convertUboComments(rule);
            if (comment) {
                return [comment];
            }
            var converted = RuleConverter.convertCssInjection(rule);
            converted = RuleConverter.convertPseudoElements(converted);
            converted = RuleConverter.convertRemoveRule(converted);
            converted = RuleConverter.replaceOptions(converted);
            converted = RuleConverter.convertScriptHasTextToScriptTagContent(converted);
            converted = RuleConverter.convertUboMatchesPathRule(converted);
            var removeHeaderRule = RuleConverter.convertUboResponseHeaderRule(converted);
            if (removeHeaderRule) {
                return [removeHeaderRule];
            }
            var scriptletRules = scriptlets.convertScriptletToAdg(converted);
            if (scriptletRules && scriptletRules.every(function (x) { return RuleConverter.isValidScriptletRule(x); })) {
                return scriptletRules;
            }
            var adgRedirectRule = RuleConverter.convertUboAndAbpRedirectsToAdg(converted);
            if (adgRedirectRule) {
                return [adgRedirectRule];
            }
            var ruleWithConvertedOptions = RuleConverter.convertOptions(converted, conversionOptions);
            if (ruleWithConvertedOptions) {
                return ruleWithConvertedOptions;
            }
            return [converted];
        };
        /**
         * Validates scriptlet rule
         *
         * @param ruleText
         */
        RuleConverter.isValidScriptletRule = function (ruleText) {
            try {
                return scriptlets.isValidScriptletRule(ruleText);
            }
            catch (e) {
                return false;
            }
        };
        /**
         * Converts UBO Script rule
         *
         * @param {string} ruleText rule text
         * @returns {string} converted rule
         */
        RuleConverter.convertScriptHasTextToScriptTagContent = function (ruleText) {
            if (!ruleText.startsWith(SimpleRegex.MASK_COMMENT) && RuleConverter.SCRIPT_HAS_TEXT_REGEX.test(ruleText)) {
                return "".concat(ruleText.replace(RuleConverter.SCRIPT_HAS_TEXT_REGEX, RuleConverter.SCRIPT_HAS_TEXT_REPLACEMENT)
                    .slice(0, -1), "\"][max-length=\"262144\"]");
            }
            return ruleText;
        };
        /**
         * Converts UBO and ABP redirect rules to AdGuard redirect rules
         * @param rule
         * @return {string} convertedRule
         */
        RuleConverter.convertUboAndAbpRedirectsToAdg = function (rule) {
            var redirects = scriptlets.redirects;
            if (redirects.isUboRedirectCompatibleWithAdg(rule) || redirects.isAbpRedirectCompatibleWithAdg(rule)) {
                return redirects.convertRedirectToAdg(rule);
            }
            return null;
        };
        /**
         * Converts rule options
         * @param rule
         * @param conversionOptions
         * @private
         */
        RuleConverter.convertOptions = function (rule, conversionOptions) {
            if (conversionOptions === void 0) { conversionOptions = {}; }
            var OPTIONS_DELIMITER = '$';
            var ESCAPE_CHARACTER = '\\';
            var NAME_VALUE_SPLITTER = '=';
            /* eslint-disable max-len */
            var conversionMap = new Map([
                ['empty', 'redirect=nooptext'],
                ['mp4', 'redirect=noopmp4-1s'],
                ['inline-script', 'csp=script-src \'self\' \'unsafe-eval\' http: https: data: blob: mediastream: filesystem:'],
                ['inline-font', 'csp=font-src \'self\' \'unsafe-eval\' http: https: data: blob: mediastream: filesystem:'],
            ]);
            /* eslint-enable max-len */
            var options;
            var domainPart = '';
            // Start looking from the prev to the last symbol
            // If dollar sign is the last symbol - we simply ignore it.
            for (var i = (rule.length - 2); i >= 0; i -= 1) {
                var currChar = rule.charAt(i);
                if (currChar !== OPTIONS_DELIMITER) {
                    continue;
                }
                if (i > 0 && rule.charAt(i - 1) !== ESCAPE_CHARACTER) {
                    domainPart = rule.substring(0, i);
                    options = rule.substring(i + 1);
                    // Options delimiter was found, doing nothing
                    break;
                }
            }
            if (!options) {
                return null;
            }
            var optionsParts = options.split(',');
            var optionsConverted = false;
            var updatedOptionsParts = optionsParts.map(function (optionsPart) {
                var convertedOptionsPart = conversionMap.get(optionsPart);
                // if option is $mp4, than it should go with $media option together
                if (optionsPart === 'mp4') {
                    // check if media is not already among options
                    if (!optionsParts.some(function (option) { return option === 'media'; })) {
                        convertedOptionsPart = "".concat(convertedOptionsPart, ",media");
                    }
                }
                if (convertedOptionsPart) {
                    optionsConverted = true;
                    return convertedOptionsPart;
                }
                return optionsPart;
            });
            // if has more than one csp modifiers, we merge them into one;
            var cspParts = updatedOptionsParts.filter(function (optionsPart) { return optionsPart.startsWith('csp'); });
            if (cspParts.length > 1) {
                var allButCsp = updatedOptionsParts
                    .filter(function (optionsPart) { return !optionsPart.startsWith('csp'); });
                var cspValues = cspParts.map(function (cspPart) { return cspPart.split(NAME_VALUE_SPLITTER)[1]; });
                var updatedCspOption = "csp".concat(NAME_VALUE_SPLITTER).concat(cspValues.join('; '));
                updatedOptionsParts = allButCsp.concat(updatedCspOption);
            }
            // options without all modifier
            var hasAllOption = updatedOptionsParts.indexOf('all') > -1;
            if (hasAllOption && !conversionOptions.ignoreAllModifier) {
                // $all modifier should be converted in 4 rules
                // ||example.org^$document,popup
                // ||example.org^
                // ||example.org^$inline-font
                // ||example.org^$inline-script
                var allOptionReplacers = [
                    ['document', 'popup'],
                    ['inline-script'],
                    ['inline-font'],
                    [''], //
                ];
                return allOptionReplacers.map(function (replacers) {
                    // remove replacer and all option from the list
                    var optionsButAllAndReplacer = updatedOptionsParts
                        .filter(function (option) { return !(replacers.includes(option) || option === 'all'); });
                    // try get converted values, used for INLINE_SCRIPT_OPTION, INLINE_FONT_OPTION
                    var convertedReplacers = replacers.map(function (replacer) { return conversionMap.get(replacer) || replacer; });
                    // add replacer to the list of options
                    var updatedOptionsString = __spreadArray(__spreadArray([], convertedReplacers, true), optionsButAllAndReplacer, true).filter(function (entity) { return entity; })
                        .join(',');
                    // create a new rule
                    return updatedOptionsString.length < 1 ? domainPart : "".concat(domainPart, "$").concat(updatedOptionsString);
                });
            }
            if (optionsConverted) {
                var updatedOptions = updatedOptionsParts.join(',');
                return ["".concat(domainPart, "$").concat(updatedOptions)];
            }
            return null;
        };
        /**
         * Converts ubo syntax comments (rules starting with #)
         * Note: It's not possible to detect 100% cause rules starting with ## are valid elemhide rules
         *
         * @param rule
         * @return {string}
         */
        RuleConverter.convertUboComments = function (rule) {
            if (rule.startsWith('# ') || rule.startsWith('####')) {
                return "! ".concat(rule);
            }
            return null;
        };
        /**
         * Executes rule css conversion
         *
         * @param rule
         * @param parts
         * @param ruleMark
         */
        RuleConverter.executeConversion = function (rule, parts, ruleMark) {
            var result = rule;
            var domain = parts[0];
            if (domain) {
                var rulePart = parts[1];
                if (rulePart.match(RuleConverter.CSS_RULE_REPLACE_PATTERN)) {
                    var groups = RuleConverter.CSS_RULE_REPLACE_PATTERN.exec(rulePart);
                    if (groups != null) {
                        if (groups.length === 3) {
                            result = domain + ruleMark;
                            result += "".concat(groups[1], " { ").concat(groups[2], " }");
                        }
                    }
                }
            }
            return result;
        };
        /**
         * Adds colon to the pseudo elements written with one colon (:before, :after);
         * e.g.
         *  "hotline.ua##.reset-scroll:before" -> "hotline.ua##.reset-scroll::before"
         * @param rule
         * @private
         */
        RuleConverter.convertPseudoElements = function (rule) {
            var BEFORE = 'before';
            var AFTER = 'after';
            var SINGLE_COLON = ':';
            // does not have parts to convert
            if (!(rule.includes(SINGLE_COLON + BEFORE) || rule.includes(SINGLE_COLON + AFTER))) {
                return rule;
            }
            // not an css rule
            if (!(rule.includes(RuleConverter.MASK_ELEMENT_HIDING)
                || rule.includes(RuleConverter.MASK_ELEMENT_HIDING_EXCEPTION)
                || rule.includes(RuleConverter.MASK_CSS)
                || rule.includes(RuleConverter.MASK_CSS_EXCEPTION))) {
                return rule;
            }
            var modifiedRule = '';
            for (var i = 0; i < rule.length; i += 1) {
                if (rule[i] !== SINGLE_COLON) {
                    modifiedRule += rule[i];
                    continue;
                }
                if ((rule.indexOf(BEFORE, i) === i + 1 || rule.indexOf(AFTER, i) === i + 1)
                    && rule[i - 1] !== SINGLE_COLON) {
                    modifiedRule += SINGLE_COLON;
                    modifiedRule += rule[i];
                    continue;
                }
                modifiedRule += rule[i];
            }
            return modifiedRule;
        };
        /**
         * Converts CSS injection
         * example.com##h1:style(background-color: blue !important)
         * into
         * example.com#$#h1 { background-color: blue !important }
         * <p>
         * OR (for exceptions):
         * example.com#@#h1:style(background-color: blue !important)
         * into
         * example.com#@$#h1 { background-color: blue !important }
         *
         * @param {string} rule
         * @return {string} convertedRule
         */
        RuleConverter.convertCssInjection = function (rule) {
            if (rule.includes(':style')) {
                var parts = void 0;
                var resultMask = void 0;
                var resultRule = rule;
                var isExtendedCss = false;
                for (var i = 0; i < EXT_CSS_PSEUDO_INDICATORS.length; i += 1) {
                    isExtendedCss = rule.indexOf(EXT_CSS_PSEUDO_INDICATORS[i]) !== -1;
                    if (isExtendedCss) {
                        break;
                    }
                }
                if (rule.includes(RuleConverter.MASK_CSS_EXTENDED_CSS_RULE)) {
                    parts = rule.split(RuleConverter.MASK_CSS_EXTENDED_CSS_RULE, 2);
                    resultMask = RuleConverter.MASK_CSS_INJECT_EXTENDED_CSS_RULE;
                }
                else if (rule.includes(RuleConverter.MASK_CSS_EXCEPTION_EXTENDED_CSS_RULE)) {
                    parts = rule.split(RuleConverter.MASK_CSS_EXCEPTION_EXTENDED_CSS_RULE, 2);
                    resultMask = RuleConverter.MASK_CSS_EXCEPTION_INJECT_EXTENDED_CSS_RULE;
                    // firstly we check for exception rule in order not to confuse with id selectors
                    // e.g. yourconroenews.com#@##siteNav:style(transform: none !important;)
                }
                else if (rule.includes(RuleConverter.MASK_ELEMENT_HIDING_EXCEPTION)) {
                    parts = rule.split(RuleConverter.MASK_ELEMENT_HIDING_EXCEPTION, 2);
                    if (isExtendedCss) {
                        resultMask = RuleConverter.MASK_CSS_EXCEPTION_INJECT_EXTENDED_CSS_RULE;
                    }
                    else {
                        resultMask = RuleConverter.MASK_CSS_EXCEPTION;
                    }
                }
                else if (rule.includes(RuleConverter.MASK_ELEMENT_HIDING)) {
                    parts = rule.split(RuleConverter.MASK_ELEMENT_HIDING, 2);
                    if (isExtendedCss) {
                        resultMask = RuleConverter.MASK_CSS_INJECT_EXTENDED_CSS_RULE;
                    }
                    else {
                        resultMask = RuleConverter.MASK_CSS;
                    }
                }
                if (parts && resultMask) {
                    resultRule = RuleConverter.executeConversion(rule, parts, resultMask);
                }
                return resultRule;
            }
            return rule;
        };
        /**
         * Converts ':remove()' rule to AdGuard extended css rule
         * example.com###banner:remove() -> example.com#$?##banner { remove: true; }
         * @param {string} rule
         * @return {string} rule or converted rule
         */
        RuleConverter.convertRemoveRule = function (rule) {
            // if rule is already extended css, do not convert it
            if (rule.includes(RuleConverter.MASK_CSS_EXTENDED_CSS_RULE)) {
                return rule;
            }
            if (rule.includes(RuleConverter.MASK_ELEMENT_HIDING) && rule.endsWith(RuleConverter.REMOVE_RULE_PATTERN)) {
                return rule
                    .replace(RuleConverter.MASK_ELEMENT_HIDING, RuleConverter.MASK_CSS_INJECT_EXTENDED_CSS_RULE)
                    .replace(RuleConverter.REMOVE_RULE_PATTERN, RuleConverter.REMOVE_RULE_REPLACER);
            }
            return rule;
        };
        /**
         * Converts '^responseheader()' rule to AdGuard's $removeheader modifier
         * "ya.ru##^responseheader(header-name)" -> "||ya.ru^$removeheader=header-name"
         *
         * @param {string} ruleText
         * @return {string} ruleText or converted rule
         */
        RuleConverter.convertUboResponseHeaderRule = function (ruleText) {
            if (ruleText.startsWith(SimpleRegex.MASK_COMMENT) || !ruleText.includes(RuleConverter.UBO_RESPONSE_HEADER)) {
                return null;
            }
            if (RuleConverter.UBO_RESPONSE_HEADER_REGEX.test(ruleText)) {
                return "||".concat(ruleText.replace(RuleConverter.UBO_RESPONSE_HEADER_REGEX, RuleConverter.UBO_RESPONSE_HEADER_REPLACEMENT)
                    .slice(0, -1));
            }
            if (RuleConverter.UBO_RESPONSE_HEADER_EXCEPTION_REGEX.test(ruleText)) {
                return "@@||".concat(ruleText.replace(RuleConverter.UBO_RESPONSE_HEADER_EXCEPTION_REGEX, RuleConverter.UBO_RESPONSE_HEADER_REPLACEMENT).slice(0, -1));
            }
            return ruleText;
        };
        /**
         * Converts cosmetic 'matches-path()' rule to AdGuard's $path modifier
         * "ya.ru##:matches-path(/page) p" -> "[$path=/page]ya.ru##p"
         *
         * @param {string} ruleText
         * @return {string} ruleText or converted rule
         */
        RuleConverter.convertUboMatchesPathRule = function (ruleText) {
            if (ruleText.startsWith(SimpleRegex.MASK_COMMENT)) {
                return ruleText;
            }
            var _a = findCosmeticRuleMarker(ruleText), markerIndex = _a[0], marker = _a[1];
            if (!marker) {
                return ruleText;
            }
            var expressionStartIndex = markerIndex + marker.length;
            var matchesPathStartIndex = ruleText.indexOf(RuleConverter.UBO_MATCHES_PATH, expressionStartIndex);
            if (matchesPathStartIndex === -1) {
                return ruleText;
            }
            var reversedMatchesPathStartIndex = ruleText.indexOf(RuleConverter.UBO_REVERSED_MATCHES_PATH, expressionStartIndex);
            var isReversed = reversedMatchesPathStartIndex !== -1;
            var pathStartIndex = isReversed
                ? reversedMatchesPathStartIndex + RuleConverter.UBO_REVERSED_MATCHES_PATH.length
                : matchesPathStartIndex + RuleConverter.UBO_MATCHES_PATH.length;
            var matchPathOperatorCloseBracketIndex;
            var openBracketCounter = 1;
            var closeBracketCounter = 0;
            for (var i = pathStartIndex; i < ruleText.length; i += 1) {
                if (ruleText[i - 1] !== '\\') {
                    if (ruleText[i] === '(') {
                        openBracketCounter += 1;
                    }
                    else if (ruleText[i] === ')') {
                        closeBracketCounter += 1;
                        if (openBracketCounter === closeBracketCounter) {
                            matchPathOperatorCloseBracketIndex = i;
                            break;
                        }
                    }
                }
            }
            if (!matchPathOperatorCloseBracketIndex) {
                return ruleText;
            }
            var domains = ruleText.slice(0, markerIndex);
            var expressionMiddle = ruleText.slice(expressionStartIndex, isReversed ? reversedMatchesPathStartIndex : matchesPathStartIndex);
            var expressionTail = ruleText.slice(matchPathOperatorCloseBracketIndex + (isReversed ? 2 : 1));
            var path = ruleText.slice(pathStartIndex, matchPathOperatorCloseBracketIndex);
            var isRegex = SimpleRegex.isRegexPattern(path);
            if (isReversed) {
                path = "/^((?!".concat(isRegex ? path.slice(1, path.length - 1) : SimpleRegex.patternToRegexp(path), ").)*$/");
            }
            if (isRegex) {
                path = SimpleRegex.escapeRegexSpecials(path, SimpleRegex.reModifierPatternSpecialCharacters);
            }
            return "[$path=".concat(path, "]").concat(domains).concat(marker).concat(expressionMiddle).concat(expressionTail);
        };
        /**
         * Replaces the options in aliases array
         *
         * @param {string} rule
         * @return {string} convertedRule
         */
        RuleConverter.replaceOptions = function (rule) {
            if (rule.startsWith(SimpleRegex.MASK_COMMENT) || RuleFactory.isCosmetic(rule)) {
                return rule;
            }
            var result = rule;
            RuleConverter.OPTIONS_ALIASES.forEach(function (x) {
                if (result.includes(x.alias) && x.regex.test(result)) {
                    result = result.replace(x.regex, x.replacement);
                }
            });
            return result;
        };
        RuleConverter.CSS_RULE_REPLACE_PATTERN = /(.*):style\((.*)\)/g;
        RuleConverter.FIRST_PARTY_REGEX = /([$,])first-party/i;
        RuleConverter.FIRST_PARTY_REPLACEMENT = '$1~third-party';
        RuleConverter.XHR_REGEX = /([$,]~?)xhr/i;
        RuleConverter.XHR_REPLACEMENT = '$1xmlhttprequest';
        RuleConverter.CSS_REGEX = /([$,]~?)(css)(,|\W|$)/i;
        RuleConverter.CSS_REPLACEMENT = '$1stylesheet$3';
        RuleConverter.FRAME_REGEX = /([$,])frame/i;
        RuleConverter.FRAME_REPLACEMENT = '$1subdocument';
        RuleConverter.SCRIPT_HAS_TEXT_REGEX = /(##\^script:(has-text|contains))\((?!\/.+\/\))/i;
        RuleConverter.SCRIPT_HAS_TEXT_REPLACEMENT = '$$$$script[tag-content="';
        RuleConverter.THIRD_PARTY_1P_3P_REGEX = /([$,])(1p|3p)/;
        RuleConverter.THIRD_PARTY_1P_REPLACEMENT = '$1~third-party';
        RuleConverter.THIRD_PARTY_3P_REPLACEMENT = '$1third-party';
        RuleConverter.GHIDE_REGEX = /(.+[^#]\$.*)(ghide)($|,.+)/i;
        RuleConverter.GENERICHIDE = 'generichide';
        RuleConverter.SHIDE_REGEX = /(.+[^#]\$.*)(shide)($|,.+)/i;
        RuleConverter.SPECIFICHIDE = 'specifichide';
        RuleConverter.EHIDE_REGEX = /(.+[^#]\$.*)(ehide)($|,.+)/i;
        RuleConverter.ELEMHIDE = 'elemhide';
        RuleConverter.QUERY_PRUNE_REGEX = /(.+[^#]\$.*)(queryprune)($|,|=.+)/i;
        RuleConverter.REMOVE_PARAM_REPLACEMENT = '$1removeparam$3';
        RuleConverter.DOC_REGEX = /(.+[^#]\$.*)(doc)($|,.+)/i;
        RuleConverter.DOC_REPLACEMENT = '$1document$3';
        RuleConverter.UBO_RESPONSE_HEADER = '#^responseheader(';
        RuleConverter.UBO_RESPONSE_HEADER_REGEX = /##\^responseheader\((?!\/.+\/\))/i;
        RuleConverter.UBO_RESPONSE_HEADER_EXCEPTION_REGEX = /#@#\^responseheader\((?!\/.+\/\))/i;
        RuleConverter.UBO_RESPONSE_HEADER_REPLACEMENT = '^$removeheader=';
        RuleConverter.UBO_MATCHES_PATH = ':matches-path(';
        RuleConverter.UBO_REVERSED_MATCHES_PATH = ':not(:matches-path(';
        /**
         * Rule masks
         */
        RuleConverter.MASK_ELEMENT_HIDING = '##';
        RuleConverter.MASK_ELEMENT_HIDING_EXCEPTION = '#@#';
        RuleConverter.MASK_CSS = '#$#';
        RuleConverter.MASK_CSS_EXCEPTION = '#@$#';
        RuleConverter.MASK_CSS_EXTENDED_CSS_RULE = '#?#';
        RuleConverter.MASK_CSS_EXCEPTION_EXTENDED_CSS_RULE = '#@?#';
        RuleConverter.MASK_CSS_INJECT_EXTENDED_CSS_RULE = '#$?#';
        RuleConverter.MASK_CSS_EXCEPTION_INJECT_EXTENDED_CSS_RULE = '#@$?#';
        RuleConverter.REMOVE_RULE_PATTERN = ':remove()';
        RuleConverter.REMOVE_RULE_REPLACER = ' { remove: true; }';
        /**
         * Some options have aliases and will be replaced:
         *
         * $first-party -> $~third-party
         * $xhr -> $xmlhttprequest
         * $css -> $stylesheet
         * $frame -> $subdocument
         * $1p -> $~third-party
         * $3p -> $third-party
         * ghide -> generichide
         * ehide -> elemhide
         * doc -> document
         * queryprune -> removeparam
         */
        RuleConverter.OPTIONS_ALIASES = [
            {
                alias: 'first-party',
                regex: RuleConverter.FIRST_PARTY_REGEX,
                replacement: RuleConverter.FIRST_PARTY_REPLACEMENT,
            },
            {
                alias: 'xhr',
                regex: RuleConverter.XHR_REGEX,
                replacement: RuleConverter.XHR_REPLACEMENT,
            },
            {
                alias: 'css',
                regex: RuleConverter.CSS_REGEX,
                replacement: RuleConverter.CSS_REPLACEMENT,
            },
            {
                alias: 'frame',
                regex: RuleConverter.FRAME_REGEX,
                replacement: RuleConverter.FRAME_REPLACEMENT,
            },
            {
                alias: 'queryprune',
                regex: RuleConverter.QUERY_PRUNE_REGEX,
                replacement: RuleConverter.REMOVE_PARAM_REPLACEMENT,
            },
            {
                alias: 'doc',
                regex: RuleConverter.DOC_REGEX,
                replacement: RuleConverter.DOC_REPLACEMENT,
            },
            {
                alias: '1p',
                regex: RuleConverter.THIRD_PARTY_1P_3P_REGEX,
                replacement: RuleConverter.THIRD_PARTY_1P_REPLACEMENT,
            },
            {
                alias: '3p',
                regex: RuleConverter.THIRD_PARTY_1P_3P_REGEX,
                replacement: RuleConverter.THIRD_PARTY_3P_REPLACEMENT,
            },
            {
                alias: 'ghide',
                regex: RuleConverter.GHIDE_REGEX,
                replacement: "$1".concat(RuleConverter.GENERICHIDE, "$3"),
            },
            {
                alias: 'ehide',
                regex: RuleConverter.EHIDE_REGEX,
                replacement: "$1".concat(RuleConverter.ELEMHIDE, "$3"),
            },
            {
                alias: 'shide',
                regex: RuleConverter.SHIDE_REGEX,
                replacement: "$1".concat(RuleConverter.SPECIFICHIDE, "$3"),
            },
        ];
        return RuleConverter;
    }());

    var ERROR_STATUS_CODES = {
        COMPLEX_REGEX: 1001,
        RULE_LIMIT: 1002,
        REGEXP_RULE_LIMIT: 1003,
    };

    /*! https://mths.be/punycode v1.4.1 by @mathias */


    /** Highest positive signed 32-bit float value */
    var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

    /** Bootstring parameters */
    var base = 36;
    var tMin = 1;
    var tMax = 26;
    var skew = 38;
    var damp = 700;
    var initialBias = 72;
    var initialN = 128; // 0x80
    var delimiter = '-'; // '\x2D'

    /** Regular expressions */
    var regexPunycode = /^xn--/;
    var regexNonASCII = /[^\x20-\x7E]/; // unprintable ASCII chars + non-ASCII chars
    var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

    /** Error messages */
    var errors = {
      'overflow': 'Overflow: input needs wider integers to process',
      'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
      'invalid-input': 'Invalid input'
    };

    /** Convenience shortcuts */
    var baseMinusTMin = base - tMin;
    var floor = Math.floor;
    var stringFromCharCode = String.fromCharCode;

    /*--------------------------------------------------------------------------*/

    /**
     * A generic error utility function.
     * @private
     * @param {String} type The error type.
     * @returns {Error} Throws a `RangeError` with the applicable error message.
     */
    function error(type) {
      throw new RangeError(errors[type]);
    }

    /**
     * A generic `Array#map` utility function.
     * @private
     * @param {Array} array The array to iterate over.
     * @param {Function} callback The function that gets called for every array
     * item.
     * @returns {Array} A new array of values returned by the callback function.
     */
    function map(array, fn) {
      var length = array.length;
      var result = [];
      while (length--) {
        result[length] = fn(array[length]);
      }
      return result;
    }

    /**
     * A simple `Array#map`-like wrapper to work with domain name strings or email
     * addresses.
     * @private
     * @param {String} domain The domain name or email address.
     * @param {Function} callback The function that gets called for every
     * character.
     * @returns {Array} A new string of characters returned by the callback
     * function.
     */
    function mapDomain(string, fn) {
      var parts = string.split('@');
      var result = '';
      if (parts.length > 1) {
        // In email addresses, only the domain name should be punycoded. Leave
        // the local part (i.e. everything up to `@`) intact.
        result = parts[0] + '@';
        string = parts[1];
      }
      // Avoid `split(regex)` for IE8 compatibility. See #17.
      string = string.replace(regexSeparators, '\x2E');
      var labels = string.split('.');
      var encoded = map(labels, fn).join('.');
      return result + encoded;
    }

    /**
     * Creates an array containing the numeric code points of each Unicode
     * character in the string. While JavaScript uses UCS-2 internally,
     * this function will convert a pair of surrogate halves (each of which
     * UCS-2 exposes as separate characters) into a single code point,
     * matching UTF-16.
     * @see `punycode.ucs2.encode`
     * @see <https://mathiasbynens.be/notes/javascript-encoding>
     * @memberOf punycode.ucs2
     * @name decode
     * @param {String} string The Unicode input string (UCS-2).
     * @returns {Array} The new array of code points.
     */
    function ucs2decode(string) {
      var output = [],
        counter = 0,
        length = string.length,
        value,
        extra;
      while (counter < length) {
        value = string.charCodeAt(counter++);
        if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
          // high surrogate, and there is a next character
          extra = string.charCodeAt(counter++);
          if ((extra & 0xFC00) == 0xDC00) { // low surrogate
            output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
          } else {
            // unmatched surrogate; only append this code unit, in case the next
            // code unit is the high surrogate of a surrogate pair
            output.push(value);
            counter--;
          }
        } else {
          output.push(value);
        }
      }
      return output;
    }

    /**
     * Creates a string based on an array of numeric code points.
     * @see `punycode.ucs2.decode`
     * @memberOf punycode.ucs2
     * @name encode
     * @param {Array} codePoints The array of numeric code points.
     * @returns {String} The new Unicode string (UCS-2).
     */
    function ucs2encode(array) {
      return map(array, function(value) {
        var output = '';
        if (value > 0xFFFF) {
          value -= 0x10000;
          output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
          value = 0xDC00 | value & 0x3FF;
        }
        output += stringFromCharCode(value);
        return output;
      }).join('');
    }

    /**
     * Converts a basic code point into a digit/integer.
     * @see `digitToBasic()`
     * @private
     * @param {Number} codePoint The basic numeric code point value.
     * @returns {Number} The numeric value of a basic code point (for use in
     * representing integers) in the range `0` to `base - 1`, or `base` if
     * the code point does not represent a value.
     */
    function basicToDigit(codePoint) {
      if (codePoint - 48 < 10) {
        return codePoint - 22;
      }
      if (codePoint - 65 < 26) {
        return codePoint - 65;
      }
      if (codePoint - 97 < 26) {
        return codePoint - 97;
      }
      return base;
    }

    /**
     * Converts a digit/integer into a basic code point.
     * @see `basicToDigit()`
     * @private
     * @param {Number} digit The numeric value of a basic code point.
     * @returns {Number} The basic code point whose value (when used for
     * representing integers) is `digit`, which needs to be in the range
     * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
     * used; else, the lowercase form is used. The behavior is undefined
     * if `flag` is non-zero and `digit` has no uppercase form.
     */
    function digitToBasic(digit, flag) {
      //  0..25 map to ASCII a..z or A..Z
      // 26..35 map to ASCII 0..9
      return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
    }

    /**
     * Bias adaptation function as per section 3.4 of RFC 3492.
     * https://tools.ietf.org/html/rfc3492#section-3.4
     * @private
     */
    function adapt(delta, numPoints, firstTime) {
      var k = 0;
      delta = firstTime ? floor(delta / damp) : delta >> 1;
      delta += floor(delta / numPoints);
      for ( /* no initialization */ ; delta > baseMinusTMin * tMax >> 1; k += base) {
        delta = floor(delta / baseMinusTMin);
      }
      return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
    }

    /**
     * Converts a Punycode string of ASCII-only symbols to a string of Unicode
     * symbols.
     * @memberOf punycode
     * @param {String} input The Punycode string of ASCII-only symbols.
     * @returns {String} The resulting string of Unicode symbols.
     */
    function decode(input) {
      // Don't use UCS-2
      var output = [],
        inputLength = input.length,
        out,
        i = 0,
        n = initialN,
        bias = initialBias,
        basic,
        j,
        index,
        oldi,
        w,
        k,
        digit,
        t,
        /** Cached calculation results */
        baseMinusT;

      // Handle the basic code points: let `basic` be the number of input code
      // points before the last delimiter, or `0` if there is none, then copy
      // the first basic code points to the output.

      basic = input.lastIndexOf(delimiter);
      if (basic < 0) {
        basic = 0;
      }

      for (j = 0; j < basic; ++j) {
        // if it's not a basic code point
        if (input.charCodeAt(j) >= 0x80) {
          error('not-basic');
        }
        output.push(input.charCodeAt(j));
      }

      // Main decoding loop: start just after the last delimiter if any basic code
      // points were copied; start at the beginning otherwise.

      for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */ ) {

        // `index` is the index of the next character to be consumed.
        // Decode a generalized variable-length integer into `delta`,
        // which gets added to `i`. The overflow checking is easier
        // if we increase `i` as we go, then subtract off its starting
        // value at the end to obtain `delta`.
        for (oldi = i, w = 1, k = base; /* no condition */ ; k += base) {

          if (index >= inputLength) {
            error('invalid-input');
          }

          digit = basicToDigit(input.charCodeAt(index++));

          if (digit >= base || digit > floor((maxInt - i) / w)) {
            error('overflow');
          }

          i += digit * w;
          t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);

          if (digit < t) {
            break;
          }

          baseMinusT = base - t;
          if (w > floor(maxInt / baseMinusT)) {
            error('overflow');
          }

          w *= baseMinusT;

        }

        out = output.length + 1;
        bias = adapt(i - oldi, out, oldi == 0);

        // `i` was supposed to wrap around from `out` to `0`,
        // incrementing `n` each time, so we'll fix that now:
        if (floor(i / out) > maxInt - n) {
          error('overflow');
        }

        n += floor(i / out);
        i %= out;

        // Insert `n` at position `i` of the output
        output.splice(i++, 0, n);

      }

      return ucs2encode(output);
    }

    /**
     * Converts a string of Unicode symbols (e.g. a domain name label) to a
     * Punycode string of ASCII-only symbols.
     * @memberOf punycode
     * @param {String} input The string of Unicode symbols.
     * @returns {String} The resulting Punycode string of ASCII-only symbols.
     */
    function encode(input) {
      var n,
        delta,
        handledCPCount,
        basicLength,
        bias,
        j,
        m,
        q,
        k,
        t,
        currentValue,
        output = [],
        /** `inputLength` will hold the number of code points in `input`. */
        inputLength,
        /** Cached calculation results */
        handledCPCountPlusOne,
        baseMinusT,
        qMinusT;

      // Convert the input in UCS-2 to Unicode
      input = ucs2decode(input);

      // Cache the length
      inputLength = input.length;

      // Initialize the state
      n = initialN;
      delta = 0;
      bias = initialBias;

      // Handle the basic code points
      for (j = 0; j < inputLength; ++j) {
        currentValue = input[j];
        if (currentValue < 0x80) {
          output.push(stringFromCharCode(currentValue));
        }
      }

      handledCPCount = basicLength = output.length;

      // `handledCPCount` is the number of code points that have been handled;
      // `basicLength` is the number of basic code points.

      // Finish the basic string - if it is not empty - with a delimiter
      if (basicLength) {
        output.push(delimiter);
      }

      // Main encoding loop:
      while (handledCPCount < inputLength) {

        // All non-basic code points < n have been handled already. Find the next
        // larger one:
        for (m = maxInt, j = 0; j < inputLength; ++j) {
          currentValue = input[j];
          if (currentValue >= n && currentValue < m) {
            m = currentValue;
          }
        }

        // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
        // but guard against overflow
        handledCPCountPlusOne = handledCPCount + 1;
        if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
          error('overflow');
        }

        delta += (m - n) * handledCPCountPlusOne;
        n = m;

        for (j = 0; j < inputLength; ++j) {
          currentValue = input[j];

          if (currentValue < n && ++delta > maxInt) {
            error('overflow');
          }

          if (currentValue == n) {
            // Represent delta as a generalized variable-length integer
            for (q = delta, k = base; /* no condition */ ; k += base) {
              t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
              if (q < t) {
                break;
              }
              qMinusT = q - t;
              baseMinusT = base - t;
              output.push(
                stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
              );
              q = floor(qMinusT / baseMinusT);
            }

            output.push(stringFromCharCode(digitToBasic(q, 0)));
            bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
            delta = 0;
            ++handledCPCount;
          }
        }

        ++delta;
        ++n;

      }
      return output.join('');
    }

    /**
     * Converts a Punycode string representing a domain name or an email address
     * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
     * it doesn't matter if you call it on a string that has already been
     * converted to Unicode.
     * @memberOf punycode
     * @param {String} input The Punycoded domain name or email address to
     * convert to Unicode.
     * @returns {String} The Unicode representation of the given Punycode
     * string.
     */
    function toUnicode(input) {
      return mapDomain(input, function(string) {
        return regexPunycode.test(string) ?
          decode(string.slice(4).toLowerCase()) :
          string;
      });
    }

    /**
     * Converts a Unicode string representing a domain name or an email address to
     * Punycode. Only the non-ASCII parts of the domain name will be converted,
     * i.e. it doesn't matter if you call it with a domain that's already in
     * ASCII.
     * @memberOf punycode
     * @param {String} input The domain name or email address to convert, as a
     * Unicode string.
     * @returns {String} The Punycode representation of the given domain name or
     * email address.
     */
    function toASCII(input) {
      return mapDomain(input, function(string) {
        return regexNonASCII.test(string) ?
          'xn--' + encode(string) :
          string;
      });
    }
    var version = '1.4.1';
    /**
     * An object of methods to convert from JavaScript's internal character
     * representation (UCS-2) to Unicode code points, and back.
     * @see <https://mathiasbynens.be/notes/javascript-encoding>
     * @memberOf punycode
     * @type Object
     */

    var ucs2 = {
      decode: ucs2decode,
      encode: ucs2encode
    };
    var punycode = {
      version: version,
      ucs2: ucs2,
      toASCII: toASCII,
      toUnicode: toUnicode,
      encode: encode,
      decode: decode
    };

    /**
     * https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-DomainType
     */
    var DomainType;
    (function (DomainType) {
        DomainType["FIRST_PARTY"] = "firstParty";
        DomainType["THIRD_PARTY"] = "thirdParty";
    })(DomainType || (DomainType = {}));
    /**
     * https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-ResourceType
     */
    var ResourceType;
    (function (ResourceType) {
        ResourceType["MAIN_FRAME"] = "main_frame";
        ResourceType["SUB_FRAME"] = "sub_frame";
        ResourceType["STYLESHEET"] = "stylesheet";
        ResourceType["SCRIPT"] = "script";
        ResourceType["IMAGE"] = "image";
        ResourceType["FONT"] = "font";
        ResourceType["OBJECT"] = "object";
        ResourceType["XMLHTTPREQUEST"] = "xmlhttprequest";
        ResourceType["PING"] = "ping";
        ResourceType["CSP_REPORT"] = "csp_report";
        ResourceType["MEDIA"] = "media";
        ResourceType["WEBSOCKET"] = "websocket";
        ResourceType["OTHER"] = "other";
    })(ResourceType || (ResourceType = {}));
    /**
     * https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-HeaderOperation
     */
    var HeaderOperation;
    (function (HeaderOperation) {
        HeaderOperation["APPEND"] = "append";
        HeaderOperation["SET"] = "set";
        HeaderOperation["REMOVE"] = "remove";
    })(HeaderOperation || (HeaderOperation = {}));
    /**
     * https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-RuleActionType
     */
    var RuleActionType;
    (function (RuleActionType) {
        RuleActionType["BLOCK"] = "block";
        RuleActionType["REDIRECT"] = "redirect";
        RuleActionType["ALLOW"] = "allow";
        RuleActionType["UPGRADE_SCHEME"] = "upgradeScheme";
        RuleActionType["MODIFY_HEADERS"] = "modifyHeaders";
        RuleActionType["ALLOW_ALL_REQUESTS"] = "allowAllRequests";
    })(RuleActionType || (RuleActionType = {}));

    var _a;
    /**
     * Map request types to declarative types
     */
    var DECLARATIVE_RESOURCE_TYPES_MAP = (_a = {},
        _a[ResourceType.MAIN_FRAME] = exports.RequestType.Document,
        _a[ResourceType.SUB_FRAME] = exports.RequestType.Subdocument,
        _a[ResourceType.STYLESHEET] = exports.RequestType.Stylesheet,
        _a[ResourceType.SCRIPT] = exports.RequestType.Script,
        _a[ResourceType.IMAGE] = exports.RequestType.Image,
        _a[ResourceType.FONT] = exports.RequestType.Font,
        _a[ResourceType.OBJECT] = exports.RequestType.Object,
        _a[ResourceType.XMLHTTPREQUEST] = exports.RequestType.XmlHttpRequest,
        _a[ResourceType.PING] = exports.RequestType.Ping,
        // [ResourceType.CSP_REPORT]: RequestType.Document, // TODO what should match this resource type?
        _a[ResourceType.MEDIA] = exports.RequestType.Media,
        _a[ResourceType.WEBSOCKET] = exports.RequestType.Websocket,
        _a[ResourceType.OTHER] = exports.RequestType.Other,
        _a);
    /**
     * Rule priority. Defaults to 1. When specified, should be >= 1.
     */
    var DeclarativeRulePriority;
    (function (DeclarativeRulePriority) {
        DeclarativeRulePriority[DeclarativeRulePriority["DocumentException"] = 4] = "DocumentException";
        DeclarativeRulePriority[DeclarativeRulePriority["ImportantException"] = 3] = "ImportantException";
        DeclarativeRulePriority[DeclarativeRulePriority["Important"] = 2] = "Important";
        DeclarativeRulePriority[DeclarativeRulePriority["Exception"] = 1] = "Exception";
    })(DeclarativeRulePriority || (DeclarativeRulePriority = {}));
    /**
     * Rule Converter class
     * Converts an instance of NetworkRule to DeclarativeRule
     *
     * https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-Rule
     */
    var DeclarativeRuleConverter = /** @class */ (function () {
        function DeclarativeRuleConverter() {
        }
        /**
         * Gets resource type matching request type
         *
         * @param requestTypes
         */
        DeclarativeRuleConverter.getResourceTypes = function (requestTypes) {
            return Object.entries(DECLARATIVE_RESOURCE_TYPES_MAP)
                // eslint-disable-next-line @typescript-eslint/no-unused-vars
                .filter(function (_a) {
                var requestType = _a[1];
                return (requestTypes & requestType) === requestType;
            })
                .map(function (_a) {
                var resourceTypeKey = _a[0];
                return resourceTypeKey;
            });
        };
        DeclarativeRuleConverter.isASCII = function (str) {
            // eslint-disable-next-line no-control-regex
            return /^[\x00-\x7F]+$/.test(str);
        };
        /**
         * Converts to punycode non if string contains non ASCII characters
         * @param str
         * @private
         */
        DeclarativeRuleConverter.prepareASCII = function (str) {
            if (DeclarativeRuleConverter.isASCII(str)) {
                return str;
            }
            return punycode.toASCII(str);
        };
        /**
         * The entries must consist of only ascii characters
         *
         * @param domains
         */
        DeclarativeRuleConverter.prepareDomains = function (domains) {
            return domains.map(function (domain) {
                return DeclarativeRuleConverter.prepareASCII(domain);
            });
        };
        /**
         * Rule priority. Defaults to 1. When specified, should be >= 1.
         *
         * document exceptions > allowlist + $important > $important > allowlist > basic rules
         *
         * @param rule
         */
        DeclarativeRuleConverter.getPriority = function (rule) {
            if (rule.isDocumentAllowlistRule()) {
                return DeclarativeRulePriority.DocumentException;
            }
            var isImportant = rule.isOptionEnabled(exports.NetworkRuleOption.Important);
            var isAllowlist = rule.isAllowlist();
            if (isImportant) {
                return isAllowlist ? DeclarativeRulePriority.ImportantException : DeclarativeRulePriority.Important;
            }
            if (isAllowlist) {
                return DeclarativeRulePriority.Exception;
            }
            return null;
        };
        /**
         * Rule action
         *
         * @param rule
         */
        DeclarativeRuleConverter.getAction = function (rule) {
            var action = {};
            // TODO RuleAction
            //  - redirect?: Redirect;
            //  - requestHeaders?: ModifyHeaderInfo[];
            //  - responseHeaders?: ModifyHeaderInfo[];
            //  - type: RuleActionType;
            // TODO RuleActionType
            //  - 'redirect' = 'redirect',
            //  - 'upgradeScheme' = 'upgradeScheme',
            //  - 'modifyHeaders' = 'modifyHeaders',
            //  - 'allowAllRequests' = 'allowAllRequests',
            if (rule.isAllowlist()) {
                action.type = RuleActionType.ALLOW;
            }
            else {
                action.type = RuleActionType.BLOCK;
            }
            return action;
        };
        /**
         * Rule condition
         *
         * @param rule
         */
        DeclarativeRuleConverter.getCondition = function (rule) {
            var condition = {};
            var pattern = rule.getPattern();
            if (pattern) {
                // set regexFilter
                if (rule.isRegexRule()) {
                    // TODO consider MAX_NUMBER_OF_REGEX_RULES
                    // eslint-disable-next-line max-len
                    //  https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#property-MAX_NUMBER_OF_REGEX_RULES
                    condition.regexFilter = DeclarativeRuleConverter.prepareASCII(pattern);
                }
                else {
                    // A pattern beginning with ||* is not allowed. Use * instead.
                    var patternWithoutVerticals = pattern.startsWith('||*') ? pattern.substring(2) : pattern;
                    condition.urlFilter = DeclarativeRuleConverter.prepareASCII(patternWithoutVerticals);
                }
            }
            // set domainType
            if (rule.isOptionEnabled(exports.NetworkRuleOption.ThirdParty)) {
                condition.domainType = DomainType.THIRD_PARTY;
            }
            else if (rule.isOptionDisabled(exports.NetworkRuleOption.ThirdParty)) {
                condition.domainType = DomainType.FIRST_PARTY;
            }
            // set domains
            var permittedDomains = rule.getPermittedDomains();
            if (permittedDomains && permittedDomains.length > 0) {
                condition.domains = this.prepareDomains(permittedDomains);
            }
            // set excludedDomains
            var excludedDomains = rule.getRestrictedDomains();
            if (excludedDomains && excludedDomains.length > 0) {
                condition.excludedDomains = this.prepareDomains(excludedDomains);
            }
            // set excludedResourceTypes
            var restrictedRequestTypes = rule.getRestrictedRequestTypes();
            var hasExcludedResourceTypes = restrictedRequestTypes !== 0;
            if (hasExcludedResourceTypes) {
                condition.excludedResourceTypes = this.getResourceTypes(restrictedRequestTypes);
            }
            // set resourceTypes
            var permittedRequestTypes = rule.getPermittedRequestTypes();
            if (!hasExcludedResourceTypes && permittedRequestTypes !== 0) {
                condition.resourceTypes = this.getResourceTypes(permittedRequestTypes);
            }
            // set isUrlFilterCaseSensitive
            condition.isUrlFilterCaseSensitive = rule.isOptionEnabled(exports.NetworkRuleOption.MatchCase);
            // eslint-disable-next-line no-param-reassign
            return condition;
        };
        /**
         * Converts a rule to declarative rule
         *
         * @param rule - network rule
         * @param id - rule identifier
         */
        DeclarativeRuleConverter.convert = function (rule, id) {
            if (rule.getAdvancedModifier() instanceof CookieModifier) {
                exports.logger.info("Error: cookies rules are not supported: \"".concat(rule.getText(), "\""));
                return null;
            }
            var declarativeRule = {};
            var priority = this.getPriority(rule);
            if (priority) {
                declarativeRule.priority = priority;
            }
            declarativeRule.id = id;
            declarativeRule.action = this.getAction(rule);
            declarativeRule.condition = this.getCondition(rule);
            var _a = declarativeRule.condition, regexFilter = _a.regexFilter, resourceTypes = _a.resourceTypes;
            // https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#type-ResourceType
            if ((resourceTypes === null || resourceTypes === void 0 ? void 0 : resourceTypes.length) === 0) {
                exports.logger.info("Error: resourceTypes cannot be empty: \"".concat(rule.getText(), "\""));
                return null;
            }
            // More complex regex than allowed as part of the "regexFilter" key.
            if (regexFilter === null || regexFilter === void 0 ? void 0 : regexFilter.match(/\|/g)) {
                var regexArr = regexFilter.split('|');
                // TODO Find how exactly the complexity of a rule is calculated.
                // The values maxGroups & maxGroupLength are obtained by testing.
                var maxGroups = 15;
                var maxGroupLength_1 = 31;
                if (regexArr.length > maxGroups || regexArr.some(function (i) { return i.length > maxGroupLength_1; })) {
                    // eslint-disable-next-line max-len
                    throw new Error("Status: ".concat(ERROR_STATUS_CODES.COMPLEX_REGEX, " Message: More complex regex than allowed: \"").concat(rule.getText(), "\""));
                }
            }
            // backreference; possessive; negative lookahead not supported;
            // https://github.com/google/re2/wiki/Syntax
            if (regexFilter === null || regexFilter === void 0 ? void 0 : regexFilter.match(/\\[1-9]|(?<!\\)\?|{\S+}/g)) {
                exports.logger.info("Error: invalid regex in the: \"".concat(rule.getText(), "\""));
                return null;
            }
            return declarativeRule;
        };
        return DeclarativeRuleConverter;
    }());

    /**
     * Converter class
     * Provides a functionality of conversion AG rules to declarative rules.
     */
    var DeclarativeConverter = /** @class */ (function () {
        function DeclarativeConverter() {
        }
        /**
         * Converts a set of rules to declarative rules array
         *
         * @param ruleList
         * @param maxLimit - max allowed number of rules in the list
         * @param maxRegexLimit - max allowed number of regular expression rules in the list
         */
        // eslint-disable-next-line class-methods-use-this
        DeclarativeConverter.prototype.convert = function (ruleList, maxLimit, maxRegexLimit) {
            if (maxLimit === void 0) { maxLimit = Number.MAX_SAFE_INTEGER; }
            if (maxRegexLimit === void 0) { maxRegexLimit = Number.MAX_SAFE_INTEGER; }
            var indexedRules = [];
            var badfilterRules = [];
            var scanner = ruleList.newScanner(ScannerType.NetworkRules);
            while (scanner.scan()) {
                var iRule = scanner.getRule();
                if (!iRule) {
                    continue;
                }
                var rule = iRule.rule;
                if (rule.isOptionEnabled(exports.NetworkRuleOption.Badfilter)) {
                    badfilterRules.push(rule);
                }
                else if (DeclarativeConverter.isRuleApplicable(rule)) {
                    indexedRules.push(iRule);
                }
            }
            var result = [];
            indexedRules.forEach(function (iRule) {
                var rule = iRule.rule;
                for (var _i = 0, badfilterRules_1 = badfilterRules; _i < badfilterRules_1.length; _i++) {
                    var badfilter = badfilterRules_1[_i];
                    if (badfilter.negatesBadfilter(rule)) {
                        return;
                    }
                }
                var dRule = DeclarativeRuleConverter.convert(rule, DeclarativeConverter.createDeclarativeRuleId(iRule.index));
                if (dRule) {
                    result.push(dRule);
                }
                if (result.length > maxLimit) {
                    // eslint-disable-next-line max-len
                    throw new Error("Status: ".concat(ERROR_STATUS_CODES.RULE_LIMIT, " Message: Maximum allowed rules count reached: ").concat(maxLimit));
                }
                var regexpRules = result.filter(function (i) { return i.condition.regexFilter; });
                if (regexpRules.length > maxRegexLimit) {
                    // eslint-disable-next-line max-len
                    throw new Error("Status: ".concat(ERROR_STATUS_CODES.REGEXP_RULE_LIMIT, " Message: Maximum allowed regex rules count reached: ").concat(maxRegexLimit));
                }
            });
            return result;
        };
        /**
         * A lot of rules don't make any sense in declarative context.
         * So here we check if rule is suitable for declarative syntax or not.
         *
         * We skip some single option rules like ($elemhide, $jsinject, $generichide etc)
         * @param rule
         */
        DeclarativeConverter.isRuleApplicable = function (rule) {
            if (!rule.isAllowlist()) {
                return true;
            }
            if (rule.isSingleOptionEnabled(exports.NetworkRuleOption.Elemhide)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Jsinject)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Cookie)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Csp)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Replace)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Generichide)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Stealth)
                || rule.isSingleOptionEnabled(exports.NetworkRuleOption.Mp4)) {
                return false;
            }
            return true;
        };
        /**
         * Creates declarative rule identifier
         * An id which uniquely identifies a rule. Mandatory and should be >= 1.
         *
         * @param index rule list index
         */
        DeclarativeConverter.createDeclarativeRuleId = function (index) {
            return index + 1;
        };
        return DeclarativeConverter;
    }());

    /**
     * Module, which can be used to validate filter rules in other libraries
     */
    var RuleValidator = /** @class */ (function () {
        function RuleValidator() {
        }
        /**
         * Creates validation result
         * @param valid
         * @param error
         * @private
         */
        RuleValidator.createValidationResult = function (valid, error) {
            if (error) {
                return { valid: valid, error: error };
            }
            return { valid: valid, error: null };
        };
        RuleValidator.validateRegexp = function (pattern, ruleText) {
            if (pattern.startsWith(SimpleRegex.MASK_REGEX_RULE)
                && pattern.endsWith(SimpleRegex.MASK_REGEX_RULE)) {
                try {
                    new RegExp(pattern.slice(1, -1));
                }
                catch (e) {
                    throw new SyntaxError("Rule has invalid regex pattern: \"".concat(ruleText, "\""));
                }
            }
        };
        /**
         * Validates raw rule string
         * @param rawRule
         */
        RuleValidator.validate = function (rawRule) {
            var ruleText = rawRule.trim();
            if (!ruleText || RuleFactory.isComment(ruleText)) {
                return RuleValidator.createValidationResult(true);
            }
            if (RuleFactory.isShort(ruleText)) {
                return RuleValidator.createValidationResult(false, "Rule is too short: ".concat(ruleText));
            }
            try {
                // Validate cosmetic rules
                if (RuleFactory.isCosmetic(ruleText)) {
                    new CosmeticRule(ruleText, 0);
                    return RuleValidator.createValidationResult(true);
                }
                // Validate network rules
                var rule = new NetworkRule(ruleText, 0);
                RuleValidator.validateRegexp(rule.getPattern(), rule.getText());
            }
            catch (e) {
                var errorMessage = "Error: \"".concat(e.message, "\" in the rule: \"").concat(ruleText, "\"");
                return RuleValidator.createValidationResult(false, errorMessage);
            }
            return RuleValidator.createValidationResult(true);
            // TODO validate host rules
        };
        return RuleValidator;
    }());

    /**
     * Module with miscellaneous syntax utils exposed in API
     */
    var RuleSyntaxUtils = /** @class */ (function () {
        function RuleSyntaxUtils() {
        }
        /**
         * Checks if rule can be matched by domain
         * @param ruleText
         * @param domain
         */
        RuleSyntaxUtils.isRuleForDomain = function (ruleText, domain) {
            var rule = RuleFactory.createRule(ruleText, this.DUMMY_FILTER_ID);
            if (!rule) {
                return false;
            }
            return rule.matchesPermittedDomains(domain);
        };
        /**
         * Checks if rule can be matched by url
         * @param ruleText
         * @param url
         */
        RuleSyntaxUtils.isRuleForUrl = function (ruleText, url) {
            var domain = getHostname(url);
            if (!domain) {
                return false;
            }
            return this.isRuleForDomain(ruleText, domain);
        };
        RuleSyntaxUtils.DUMMY_FILTER_ID = 0;
        return RuleSyntaxUtils;
    }());

    /**
     * Cookie rules manager class
     */
    var CookieRulesFinder = /** @class */ (function () {
        function CookieRulesFinder() {
        }
        /**
         * Filters blocking rules
         * Used in content scripts
         *
         * @param url
         * @param rules
         */
        CookieRulesFinder.getBlockingRules = function (url, rules) {
            return rules.filter(function (rule) { return !CookieRulesFinder.isModifyingRule(rule); });
        };
        /**
         * Finds a rule that doesn't modify cookie: i.e. this rule cancels cookie or it's a allowlist rule.
         *
         * @param cookieName Cookie name
         * @param rules Matching rules
         * @param isThirdPartyCookie
         * @return Found rule or null
         */
        CookieRulesFinder.lookupNotModifyingRule = function (cookieName, rules, isThirdPartyCookie) {
            var blockingRules = [];
            var allowlistRules = [];
            for (var i = 0; i < rules.length; i += 1) {
                var rule = rules[i];
                if (!CookieRulesFinder.matchThirdParty(rule, isThirdPartyCookie)) {
                    continue;
                }
                var cookieModifier = rule.getAdvancedModifier();
                if (cookieModifier.matches(cookieName) && !CookieRulesFinder.isModifyingRule(rule)) {
                    if (rule.isAllowlist()) {
                        allowlistRules.push(rule);
                    }
                    else {
                        blockingRules.push(rule);
                    }
                }
            }
            if (allowlistRules.length > 0) {
                return allowlistRules[0];
            }
            if (blockingRules.length > 0) {
                return blockingRules[0];
            }
            return null;
        };
        /**
         * Finds rules that modify cookie
         *
         * @param cookieName Cookie name
         * @param rules Matching rules
         * @param isThirdPartyCookie
         * @return Modifying rules
         */
        CookieRulesFinder.lookupModifyingRules = function (cookieName, rules, isThirdPartyCookie) {
            var result = [];
            var allowlistRules = [];
            if (rules && rules.length > 0) {
                for (var i = 0; i < rules.length; i += 1) {
                    var rule = rules[i];
                    if (!CookieRulesFinder.matchThirdParty(rule, isThirdPartyCookie)) {
                        continue;
                    }
                    var cookieModifier = rule.getAdvancedModifier();
                    if (!cookieModifier.matches(cookieName)) {
                        continue;
                    }
                    if (!rule.isAllowlist() && !CookieRulesFinder.isModifyingRule(rule)) {
                        return [];
                    }
                    if (rule.isAllowlist()) {
                        allowlistRules.push(rule);
                    }
                    else {
                        result.push(rule);
                    }
                }
            }
            if (allowlistRules.length > 0) {
                return allowlistRules;
            }
            return result;
        };
        /**
         * Checks if rule and third party flag matches
         *
         * @param rule
         * @param isThirdParty
         */
        CookieRulesFinder.matchThirdParty = function (rule, isThirdParty) {
            if (!rule.isOptionEnabled(exports.NetworkRuleOption.ThirdParty)) {
                return true;
            }
            return isThirdParty === rule.isOptionEnabled(exports.NetworkRuleOption.ThirdParty);
        };
        /**
         * Checks if $cookie rule is modifying
         *
         * @param rule $cookie rule
         * @return result
         */
        CookieRulesFinder.isModifyingRule = function (rule) {
            var cookieModifier = rule.getAdvancedModifier();
            return cookieModifier.getSameSite() !== null
                || (cookieModifier.getMaxAge() !== null && cookieModifier.getMaxAge() > 0);
        };
        return CookieRulesFinder;
    }());

    /**
     * Synthetic Cookie-like object parsed from headers
     */
    var ParsedCookie = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param name
         * @param value
         * @param url
         */
        function ParsedCookie(name, value, url) {
            /**
             * Cookie's third-party status.
             */
            this.thirdParty = false;
            this.name = name;
            this.value = value;
            this.url = url;
            var tldResult = parse(url);
            this.domain = tldResult.domain;
        }
        return ParsedCookie;
    }());

    /**
     * Cookie Utils
     */
    var CookieUtils = /** @class */ (function () {
        function CookieUtils() {
        }
        /**
         * Parses set-cookie header from http response header
         * @param header
         * @param url
         */
        CookieUtils.parseSetCookieHeader = function (header, url) {
            if (!header.name || header.name.toLowerCase() !== 'set-cookie') {
                return null;
            }
            if (!header.value) {
                return null;
            }
            return CookieUtils.parseSetCookie(header.value, url);
        };
        /**
         * Parses set-cookie headers for cookie objects
         *
         * @param responseHeaders
         * @param url
         * @returns array of parsed cookies
         */
        CookieUtils.parseSetCookieHeaders = function (responseHeaders, url) {
            var result = [];
            var iResponseHeaders = responseHeaders.length;
            while (iResponseHeaders > 0) {
                iResponseHeaders -= 1;
                var header = responseHeaders[iResponseHeaders];
                var setCookie = CookieUtils.parseSetCookieHeader(header, url);
                if (setCookie) {
                    result.push(setCookie);
                }
            }
            return result;
        };
        /**
         * Parse an HTTP Cookie header string and return an object with all cookie name-value pairs.
         *
         * @param cookieValue HTTP Cookie value
         * @param url
         * @returns Array of cookie name-value pairs
         */
        CookieUtils.parseCookies = function (cookieValue, url) {
            var cookies = [];
            // Split Cookie values
            var pairs = cookieValue.split(/; */);
            for (var i = 0; i < pairs.length; i += 1) {
                var pair = pairs[i];
                var eqIdx = pair.indexOf('=');
                // skip things that don't look like key=value
                if (eqIdx < 0) {
                    continue;
                }
                var key = pair.substr(0, eqIdx).trim();
                var value = pair.substr(eqIdx + 1, pair.length).trim();
                var parsedCookie = new ParsedCookie(key, value, url);
                /**
                 * Not obviously there are few special name prefixes
                 * https://developer.cdn.mozilla.net/pt-BR/docs/Web/HTTP/Headers/Set-Cookie
                 */
                if (key.startsWith('__Secure-') || key.startsWith('__Host-')) {
                    parsedCookie.secure = true;
                }
                cookies.push(parsedCookie);
            }
            return cookies;
        };
        /**
         * Parses "Set-Cookie" header value and returns a cookie object with its properties
         *
         * @param setCookieValue "Set-Cookie" header value to parse
         * @param url
         * @returns cookie object or null if it failed to parse the value
         */
        CookieUtils.parseSetCookie = function (setCookieValue, url) {
            var parts = setCookieValue.split(';').filter(function (s) { return !!s; });
            var nameValuePart = parts.shift();
            if (!nameValuePart) {
                return null;
            }
            var nameValue = nameValuePart.split('=');
            var name = nameValue.shift();
            // everything after the first =, joined by a "=" if there was more than one part
            var value = nameValue.join('=');
            var cookie = new ParsedCookie(name, value, url);
            parts.forEach(function (part) {
                var sides = part.split('=');
                var key = sides
                    .shift()
                    .trimStart()
                    .toLowerCase();
                var optionValue = sides.join('=');
                if (key === 'expires') {
                    cookie.expires = new Date(optionValue);
                }
                else if (key === 'max-age') {
                    cookie.maxAge = parseInt(optionValue, 10);
                }
                else if (key === 'secure') {
                    cookie.secure = true;
                }
                else if (key === 'httponly') {
                    cookie.httpOnly = true;
                }
                else if (key === 'samesite') {
                    cookie.sameSite = optionValue;
                }
                else if (key === 'path') {
                    cookie.path = optionValue;
                }
            });
            return cookie;
        };
        /**
         * Updates cookie maxAge value
         *
         * @param cookie Cookie to modify
         * @param maxAge
         * @return if cookie was modified
         */
        CookieUtils.updateCookieMaxAge = function (cookie, maxAge) {
            var currentTimeSec = Date.now() / 1000;
            var cookieExpiresTimeSec = null;
            if (cookie.maxAge) {
                cookieExpiresTimeSec = currentTimeSec + cookie.maxAge;
            }
            else if (cookie.expires) {
                cookieExpiresTimeSec = cookie.expires.getTime() / 1000;
            }
            var newCookieExpiresTimeSec = currentTimeSec + maxAge;
            if (cookieExpiresTimeSec === null || cookieExpiresTimeSec > newCookieExpiresTimeSec) {
                // eslint-disable-next-line no-param-reassign
                cookie.expires = new Date(newCookieExpiresTimeSec * 1000);
                // eslint-disable-next-line no-param-reassign
                cookie.maxAge = maxAge;
                return true;
            }
            return false;
        };
        /**
         * Serializes cookie data into a string suitable for Set-Cookie header.
         *
         * @param cookie A cookie object
         * @return Set-Cookie string or null if it failed to serialize object
         * @throws {TypeError} Thrown in case of invalid input data
         * @public
         */
        CookieUtils.serializeCookie = function (cookie) {
            if (!cookie) {
                throw new TypeError('empty cookie data');
            }
            // 1. Validate fields
            if (!CookieUtils.FIELD_CONTENT_REGEX.test(cookie.name)) {
                throw new TypeError("Cookie name is invalid: ".concat(cookie.name));
            }
            if (cookie.value && !CookieUtils.FIELD_CONTENT_REGEX.test(cookie.value)) {
                throw new TypeError("Cookie value is invalid: ".concat(cookie.value));
            }
            if (cookie.domain && !CookieUtils.FIELD_CONTENT_REGEX.test(cookie.domain)) {
                throw new TypeError("Cookie domain is invalid: ".concat(cookie.domain));
            }
            if (cookie.path && !CookieUtils.FIELD_CONTENT_REGEX.test(cookie.path)) {
                throw new TypeError("Cookie path is invalid: ".concat(cookie.path));
            }
            if (cookie.expires && typeof cookie.expires.toUTCString !== 'function') {
                throw new TypeError("Cookie expires is invalid: ".concat(cookie.expires));
            }
            // 2. Build Set-Cookie header value
            var setCookieValue = cookie.name + '=' + cookie.value;
            if (typeof cookie.maxAge === 'number' && !Number.isNaN(cookie.maxAge)) {
                setCookieValue += '; Max-Age=' + Math.floor(cookie.maxAge);
            }
            if (cookie.domain) {
                setCookieValue += '; Domain=' + cookie.domain;
            }
            if (cookie.path) {
                setCookieValue += '; Path=' + cookie.path;
            }
            if (cookie.expires) {
                setCookieValue += '; Expires=' + cookie.expires.toUTCString();
            }
            if (cookie.httpOnly) {
                setCookieValue += '; HttpOnly';
            }
            if (cookie.secure) {
                setCookieValue += '; Secure';
            }
            if (cookie.sameSite) {
                var sameSite = cookie.sameSite.toLowerCase();
                switch (sameSite) {
                    case 'lax':
                        setCookieValue += '; SameSite=Lax';
                        break;
                    case 'strict':
                        setCookieValue += '; SameSite=Strict';
                        break;
                    case 'none':
                        setCookieValue += '; SameSite=None';
                        break;
                    default:
                        throw new TypeError("Cookie sameSite is invalid: ".concat(cookie.sameSite));
                }
            }
            // Don't affected. Let it be here just in case
            // https://bugs.chromium.org/p/chromium/issues/detail?id=232693
            if (cookie.priority) {
                setCookieValue += "; Priority=".concat(cookie.priority);
            }
            return setCookieValue;
        };
        /**
         * RegExp to match field-content in RFC 7230 sec 3.2
         *
         * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
         * field-vchar   = VCHAR / obs-text
         * obs-text      = %x80-FF
         */
        // eslint-disable-next-line no-control-regex
        CookieUtils.FIELD_CONTENT_REGEX = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;
        return CookieUtils;
    }());

    var browserPolyfill = {exports: {}};

    (function (module, exports) {
    (function (global, factory) {
      {
        factory(module);
      }
    })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : commonjsGlobal, function (module) {
      if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) {
        const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received.";
        const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)";
        const wrapAPIs = extensionAPIs => {
          const apiMetadata = {
            "alarms": {
              "clear": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "clearAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "get": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "getAll": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "bookmarks": {
              "create": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "get": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getChildren": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getRecent": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getSubTree": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getTree": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "move": {
                "minArgs": 2,
                "maxArgs": 2
              },
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeTree": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "search": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "update": {
                "minArgs": 2,
                "maxArgs": 2
              }
            },
            "browserAction": {
              "disable": {
                "minArgs": 0,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "enable": {
                "minArgs": 0,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "getBadgeBackgroundColor": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getBadgeText": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getPopup": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getTitle": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "openPopup": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "setBadgeBackgroundColor": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "setBadgeText": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "setIcon": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "setPopup": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "setTitle": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              }
            },
            "browsingData": {
              "remove": {
                "minArgs": 2,
                "maxArgs": 2
              },
              "removeCache": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeCookies": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeDownloads": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeFormData": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeHistory": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeLocalStorage": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removePasswords": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removePluginData": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "settings": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "commands": {
              "getAll": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "contextMenus": {
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "update": {
                "minArgs": 2,
                "maxArgs": 2
              }
            },
            "cookies": {
              "get": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getAll": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getAllCookieStores": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "set": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "devtools": {
              "inspectedWindow": {
                "eval": {
                  "minArgs": 1,
                  "maxArgs": 2,
                  "singleCallbackArg": false
                }
              },
              "panels": {
                "create": {
                  "minArgs": 3,
                  "maxArgs": 3,
                  "singleCallbackArg": true
                },
                "elements": {
                  "createSidebarPane": {
                    "minArgs": 1,
                    "maxArgs": 1
                  }
                }
              }
            },
            "downloads": {
              "cancel": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "download": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "erase": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getFileIcon": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "open": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "pause": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeFile": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "resume": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "search": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "show": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              }
            },
            "extension": {
              "isAllowedFileSchemeAccess": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "isAllowedIncognitoAccess": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "history": {
              "addUrl": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "deleteAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "deleteRange": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "deleteUrl": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getVisits": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "search": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "i18n": {
              "detectLanguage": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getAcceptLanguages": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "identity": {
              "launchWebAuthFlow": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "idle": {
              "queryState": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "management": {
              "get": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "getSelf": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "setEnabled": {
                "minArgs": 2,
                "maxArgs": 2
              },
              "uninstallSelf": {
                "minArgs": 0,
                "maxArgs": 1
              }
            },
            "notifications": {
              "clear": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "create": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "getAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "getPermissionLevel": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "update": {
                "minArgs": 2,
                "maxArgs": 2
              }
            },
            "pageAction": {
              "getPopup": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getTitle": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "hide": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "setIcon": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "setPopup": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "setTitle": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              },
              "show": {
                "minArgs": 1,
                "maxArgs": 1,
                "fallbackToNoCallback": true
              }
            },
            "permissions": {
              "contains": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getAll": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "request": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "runtime": {
              "getBackgroundPage": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "getPlatformInfo": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "openOptionsPage": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "requestUpdateCheck": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "sendMessage": {
                "minArgs": 1,
                "maxArgs": 3
              },
              "sendNativeMessage": {
                "minArgs": 2,
                "maxArgs": 2
              },
              "setUninstallURL": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "sessions": {
              "getDevices": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "getRecentlyClosed": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "restore": {
                "minArgs": 0,
                "maxArgs": 1
              }
            },
            "storage": {
              "local": {
                "clear": {
                  "minArgs": 0,
                  "maxArgs": 0
                },
                "get": {
                  "minArgs": 0,
                  "maxArgs": 1
                },
                "getBytesInUse": {
                  "minArgs": 0,
                  "maxArgs": 1
                },
                "remove": {
                  "minArgs": 1,
                  "maxArgs": 1
                },
                "set": {
                  "minArgs": 1,
                  "maxArgs": 1
                }
              },
              "managed": {
                "get": {
                  "minArgs": 0,
                  "maxArgs": 1
                },
                "getBytesInUse": {
                  "minArgs": 0,
                  "maxArgs": 1
                }
              },
              "sync": {
                "clear": {
                  "minArgs": 0,
                  "maxArgs": 0
                },
                "get": {
                  "minArgs": 0,
                  "maxArgs": 1
                },
                "getBytesInUse": {
                  "minArgs": 0,
                  "maxArgs": 1
                },
                "remove": {
                  "minArgs": 1,
                  "maxArgs": 1
                },
                "set": {
                  "minArgs": 1,
                  "maxArgs": 1
                }
              }
            },
            "tabs": {
              "captureVisibleTab": {
                "minArgs": 0,
                "maxArgs": 2
              },
              "create": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "detectLanguage": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "discard": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "duplicate": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "executeScript": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "get": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getCurrent": {
                "minArgs": 0,
                "maxArgs": 0
              },
              "getZoom": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "getZoomSettings": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "goBack": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "goForward": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "highlight": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "insertCSS": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "move": {
                "minArgs": 2,
                "maxArgs": 2
              },
              "query": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "reload": {
                "minArgs": 0,
                "maxArgs": 2
              },
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "removeCSS": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "sendMessage": {
                "minArgs": 2,
                "maxArgs": 3
              },
              "setZoom": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "setZoomSettings": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "update": {
                "minArgs": 1,
                "maxArgs": 2
              }
            },
            "topSites": {
              "get": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "webNavigation": {
              "getAllFrames": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "getFrame": {
                "minArgs": 1,
                "maxArgs": 1
              }
            },
            "webRequest": {
              "handlerBehaviorChanged": {
                "minArgs": 0,
                "maxArgs": 0
              }
            },
            "windows": {
              "create": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "get": {
                "minArgs": 1,
                "maxArgs": 2
              },
              "getAll": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "getCurrent": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "getLastFocused": {
                "minArgs": 0,
                "maxArgs": 1
              },
              "remove": {
                "minArgs": 1,
                "maxArgs": 1
              },
              "update": {
                "minArgs": 2,
                "maxArgs": 2
              }
            }
          };
          if (Object.keys(apiMetadata).length === 0) {
            throw new Error("api-metadata.json has not been included in browser-polyfill");
          }
          class DefaultWeakMap extends WeakMap {
            constructor(createItem, items = undefined) {
              super(items);
              this.createItem = createItem;
            }
            get(key) {
              if (!this.has(key)) {
                this.set(key, this.createItem(key));
              }
              return super.get(key);
            }
          }
          const isThenable = value => {
            return value && typeof value === "object" && typeof value.then === "function";
          };
          const makeCallback = (promise, metadata) => {
            return (...callbackArgs) => {
              if (extensionAPIs.runtime.lastError) {
                promise.reject(new Error(extensionAPIs.runtime.lastError.message));
              } else if (metadata.singleCallbackArg || callbackArgs.length <= 1 && metadata.singleCallbackArg !== false) {
                promise.resolve(callbackArgs[0]);
              } else {
                promise.resolve(callbackArgs);
              }
            };
          };
          const pluralizeArguments = numArgs => numArgs == 1 ? "argument" : "arguments";
          const wrapAsyncFunction = (name, metadata) => {
            return function asyncFunctionWrapper(target, ...args) {
              if (args.length < metadata.minArgs) {
                throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
              }
              if (args.length > metadata.maxArgs) {
                throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
              }
              return new Promise((resolve, reject) => {
                if (metadata.fallbackToNoCallback) {
                  try {
                    target[name](...args, makeCallback({
                      resolve,
                      reject
                    }, metadata));
                  } catch (cbError) {
                    console.warn(`${name} API method doesn't seem to support the callback parameter, ` + "falling back to call it without a callback: ", cbError);
                    target[name](...args);
                    metadata.fallbackToNoCallback = false;
                    metadata.noCallback = true;
                    resolve();
                  }
                } else if (metadata.noCallback) {
                  target[name](...args);
                  resolve();
                } else {
                  target[name](...args, makeCallback({
                    resolve,
                    reject
                  }, metadata));
                }
              });
            };
          };
          const wrapMethod = (target, method, wrapper) => {
            return new Proxy(method, {
              apply(targetMethod, thisObj, args) {
                return wrapper.call(thisObj, target, ...args);
              }
            });
          };
          let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
          const wrapObject = (target, wrappers = {}, metadata = {}) => {
            let cache = Object.create(null);
            let handlers = {
              has(proxyTarget, prop) {
                return prop in target || prop in cache;
              },
              get(proxyTarget, prop, receiver) {
                if (prop in cache) {
                  return cache[prop];
                }
                if (!(prop in target)) {
                  return undefined;
                }
                let value = target[prop];
                if (typeof value === "function") {
                  if (typeof wrappers[prop] === "function") {
                    value = wrapMethod(target, target[prop], wrappers[prop]);
                  } else if (hasOwnProperty(metadata, prop)) {
                    let wrapper = wrapAsyncFunction(prop, metadata[prop]);
                    value = wrapMethod(target, target[prop], wrapper);
                  } else {
                    value = value.bind(target);
                  }
                } else if (typeof value === "object" && value !== null && (hasOwnProperty(wrappers, prop) || hasOwnProperty(metadata, prop))) {
                  value = wrapObject(value, wrappers[prop], metadata[prop]);
                } else if (hasOwnProperty(metadata, "*")) {
                  value = wrapObject(value, wrappers[prop], metadata["*"]);
                } else {
                  Object.defineProperty(cache, prop, {
                    configurable: true,
                    enumerable: true,
                    get() {
                      return target[prop];
                    },
                    set(value) {
                      target[prop] = value;
                    }
                  });
                  return value;
                }
                cache[prop] = value;
                return value;
              },
              set(proxyTarget, prop, value, receiver) {
                if (prop in cache) {
                  cache[prop] = value;
                } else {
                  target[prop] = value;
                }
                return true;
              },
              defineProperty(proxyTarget, prop, desc) {
                return Reflect.defineProperty(cache, prop, desc);
              },
              deleteProperty(proxyTarget, prop) {
                return Reflect.deleteProperty(cache, prop);
              }
            };
            let proxyTarget = Object.create(target);
            return new Proxy(proxyTarget, handlers);
          };
          const wrapEvent = wrapperMap => ({
            addListener(target, listener, ...args) {
              target.addListener(wrapperMap.get(listener), ...args);
            },
            hasListener(target, listener) {
              return target.hasListener(wrapperMap.get(listener));
            },
            removeListener(target, listener) {
              target.removeListener(wrapperMap.get(listener));
            }
          });
          const onRequestFinishedWrappers = new DefaultWeakMap(listener => {
            if (typeof listener !== "function") {
              return listener;
            }
            return function onRequestFinished(req) {
              const wrappedReq = wrapObject(req, {}
              , {
                getContent: {
                  minArgs: 0,
                  maxArgs: 0
                }
              });
              listener(wrappedReq);
            };
          });
          let loggedSendResponseDeprecationWarning = false;
          const onMessageWrappers = new DefaultWeakMap(listener => {
            if (typeof listener !== "function") {
              return listener;
            }
            return function onMessage(message, sender, sendResponse) {
              let didCallSendResponse = false;
              let wrappedSendResponse;
              let sendResponsePromise = new Promise(resolve => {
                wrappedSendResponse = function (response) {
                  if (!loggedSendResponseDeprecationWarning) {
                    console.warn(SEND_RESPONSE_DEPRECATION_WARNING, new Error().stack);
                    loggedSendResponseDeprecationWarning = true;
                  }
                  didCallSendResponse = true;
                  resolve(response);
                };
              });
              let result;
              try {
                result = listener(message, sender, wrappedSendResponse);
              } catch (err) {
                result = Promise.reject(err);
              }
              const isResultThenable = result !== true && isThenable(result);
              if (result !== true && !isResultThenable && !didCallSendResponse) {
                return false;
              }
              const sendPromisedResult = promise => {
                promise.then(msg => {
                  sendResponse(msg);
                }, error => {
                  let message;
                  if (error && (error instanceof Error || typeof error.message === "string")) {
                    message = error.message;
                  } else {
                    message = "An unexpected error occurred";
                  }
                  sendResponse({
                    __mozWebExtensionPolyfillReject__: true,
                    message
                  });
                }).catch(err => {
                  console.error("Failed to send onMessage rejected reply", err);
                });
              };
              if (isResultThenable) {
                sendPromisedResult(result);
              } else {
                sendPromisedResult(sendResponsePromise);
              }
              return true;
            };
          });
          const wrappedSendMessageCallback = ({
            reject,
            resolve
          }, reply) => {
            if (extensionAPIs.runtime.lastError) {
              if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) {
                resolve();
              } else {
                reject(new Error(extensionAPIs.runtime.lastError.message));
              }
            } else if (reply && reply.__mozWebExtensionPolyfillReject__) {
              reject(new Error(reply.message));
            } else {
              resolve(reply);
            }
          };
          const wrappedSendMessage = (name, metadata, apiNamespaceObj, ...args) => {
            if (args.length < metadata.minArgs) {
              throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
            }
            if (args.length > metadata.maxArgs) {
              throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
            }
            return new Promise((resolve, reject) => {
              const wrappedCb = wrappedSendMessageCallback.bind(null, {
                resolve,
                reject
              });
              args.push(wrappedCb);
              apiNamespaceObj.sendMessage(...args);
            });
          };
          const staticWrappers = {
            devtools: {
              network: {
                onRequestFinished: wrapEvent(onRequestFinishedWrappers)
              }
            },
            runtime: {
              onMessage: wrapEvent(onMessageWrappers),
              onMessageExternal: wrapEvent(onMessageWrappers),
              sendMessage: wrappedSendMessage.bind(null, "sendMessage", {
                minArgs: 1,
                maxArgs: 3
              })
            },
            tabs: {
              sendMessage: wrappedSendMessage.bind(null, "sendMessage", {
                minArgs: 2,
                maxArgs: 3
              })
            }
          };
          const settingMetadata = {
            clear: {
              minArgs: 1,
              maxArgs: 1
            },
            get: {
              minArgs: 1,
              maxArgs: 1
            },
            set: {
              minArgs: 1,
              maxArgs: 1
            }
          };
          apiMetadata.privacy = {
            network: {
              "*": settingMetadata
            },
            services: {
              "*": settingMetadata
            },
            websites: {
              "*": settingMetadata
            }
          };
          return wrapObject(extensionAPIs, staticWrappers, apiMetadata);
        };
        if (typeof chrome != "object" || !chrome || !chrome.runtime || !chrome.runtime.id) {
          throw new Error("This script should only be loaded in a browser extension.");
        }
        module.exports = wrapAPIs(chrome);
      } else {
        module.exports = browser;
      }
    });

    }(browserPolyfill));
    var browser$1 = browserPolyfill.exports;

    /**
     * Cookie api implementation
     */
    var BrowserCookieApi = /** @class */ (function () {
        function BrowserCookieApi() {
        }
        /**
         * Removes cookie
         *
         * @param name
         * @param url
         */
        BrowserCookieApi.prototype.removeCookie = function (name, url) {
            return __awaiter(this, void 0, void 0, function () {
                var e_1;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            _a.trys.push([0, 2, , 3]);
                            return [4 /*yield*/, browser$1.cookies.remove({ name: name, url: url })];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, true];
                        case 2:
                            e_1 = _a.sent();
                            exports.logger.error(e_1.message);
                            return [3 /*break*/, 3];
                        case 3: return [2 /*return*/, false];
                    }
                });
            });
        };
        /**
         * Updates cookie
         *
         * @param cookie Cookie for update
         */
        BrowserCookieApi.prototype.modifyCookie = function (cookie) {
            return __awaiter(this, void 0, void 0, function () {
                var update, e_2;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            _a.trys.push([0, 2, , 3]);
                            update = BrowserCookieApi.convertToSetDetailsType(cookie);
                            return [4 /*yield*/, browser$1.cookies.set(update)];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, true];
                        case 2:
                            e_2 = _a.sent();
                            exports.logger.error(e_2.message);
                            return [3 /*break*/, 3];
                        case 3: return [2 /*return*/, false];
                    }
                });
            });
        };
        BrowserCookieApi.convertToSetDetailsType = function (cookie) {
            return {
                /**
                 * The request-URI to associate with the setting of the cookie.
                 * This value can affect the default domain and path values of the created cookie.
                 * If host permissions for this URL are not specified in the manifest file, the API call will fail.
                 */
                url: cookie.url,
                /**
                 * The name of the cookie. Empty by default if omitted.
                 * Optional.
                 */
                name: cookie.name,
                /**
                 * The value of the cookie. Empty by default if omitted.
                 * Optional.
                 */
                value: cookie.value,
                /**
                 * The domain of the cookie. If omitted, the cookie becomes a host-only cookie.
                 * Optional.
                 */
                domain: cookie.domain,
                /**
                 * Whether the cookie should be marked as Secure. Defaults to false.
                 * Optional.
                 */
                secure: cookie.secure,
                /**
                 * Whether the cookie should be marked as HttpOnly. Defaults to false.
                 * Optional.
                 */
                httpOnly: cookie.httpOnly,
                /**
                 * The cookie's same-site status.
                 * Optional.
                 */
                sameSite: BrowserCookieApi.getSameSiteStatus(cookie.sameSite),
                /**
                 * The expiration date of the cookie as the number of seconds since the UNIX epoch.
                 * If omitted, the cookie becomes a session cookie.
                 * Optional.
                 */
                expirationDate: cookie.expires ? cookie.expires.getTime() : undefined,
            };
        };
        /**
         * Returns same-site type
         *
         * @param sameSite
         */
        BrowserCookieApi.getSameSiteStatus = function (sameSite) {
            if (sameSite) {
                if (sameSite.toLowerCase() === 'lax') {
                    return 'lax';
                }
                if (sameSite.toLowerCase() === 'strict') {
                    return 'strict';
                }
            }
            return undefined;
        };
        return BrowserCookieApi;
    }());

    /**
     * Finds header object by header name (case insensitive)
     *
     * @param headers Headers collection
     * @param headerName Header name
     * @returns header value
     */
    function findHeaderByName(headers, headerName) {
        for (var i = 0; i < headers.length; i += 1) {
            var header = headers[i];
            if (header.name.toLowerCase() === headerName.toLowerCase()) {
                return header;
            }
        }
        return null;
    }
    /**
     * Removes header from headers by name
     *
     * @param {Array} headers
     * @param {String} headerName
     * @return {boolean} True if header were removed
     */
    function removeHeader(headers, headerName) {
        var removed = false;
        if (headers) {
            for (var i = headers.length - 1; i >= 0; i -= 1) {
                var header = headers[i];
                if (header.name.toLowerCase() === headerName.toLowerCase()) {
                    headers.splice(i, 1);
                    removed = true;
                }
            }
        }
        return removed;
    }

    /**
     * Cookie filtering
     *
     * The following public methods should be set as suitable webrequest events listeners,
     * check sample extension in this repo for an example
     *
     * Logic introduction:
     *
     * onBeforeRequest:
     * - get $cookie rules for current url
     *
     * onBeforeSendHeaders:
     * - get all cookies for request url
     * - store cookies (first-party)
     *
     * onHeadersReceived:
     * - parse set-cookie header, only to detect if the cookie in header will be set from third-party request
     * - save third-party flag for this cookie cookie.thirdParty=request.thirdParty
     * - apply rules via removing them from headers and removing them with browser.cookies api
     * TODO Rewrite/split method for extensions on MV3, because we wont have possibility to remove rules via headers
     *
     * onCompleted/onErrorOccurred:
     * - delete request context from the storage
     *
     * onCompleted
     * - apply rules via content script
     * In content-scripts (check /src/content-script/cookie-controller.ts):
     * - get matching cookie rules
     * - apply
     */
    var CookieFiltering = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param filteringLog
         */
        function CookieFiltering(filteringLog) {
            this.browserCookieApi = new BrowserCookieApi();
            this.requestContextStorage = new Map();
            this.filteringLog = filteringLog;
        }
        /**
         * Finds rules for request and saves it to context storage
         * @param details
         * @param rules
         */
        CookieFiltering.prototype.onBeforeRequest = function (details, rules) {
            this.requestContextStorage.set(details.requestId, {
                rules: rules,
                cookies: [],
                url: details.url,
                tabId: details.tabId,
            });
        };
        /**
         * Parses cookies from headers
         * @param details
         */
        CookieFiltering.prototype.onBeforeSendHeaders = function (details) {
            if (!details.requestHeaders) {
                return;
            }
            var context = this.requestContextStorage.get(details.requestId);
            if (!context) {
                return;
            }
            var cookieHeader = findHeaderByName(details.requestHeaders, 'Cookie');
            if (!cookieHeader || !cookieHeader.value) {
                return;
            }
            var cookies = CookieUtils.parseCookies(cookieHeader.value, context.url);
            if (cookies.length === 0) {
                return;
            }
            context.cookies = cookies;
        };
        /**
         * Applies cookies to headers
         * @param details
         * @private
         */
        CookieFiltering.prototype.applyRulesToCookieHeaders = function (details) {
            var _this = this;
            var headersModified = false;
            if (!details.responseHeaders) {
                return headersModified;
            }
            var context = this.requestContextStorage.get(details.requestId);
            if (!context) {
                return headersModified;
            }
            var _loop_1 = function (i) {
                var header = details.responseHeaders[i];
                var cookie = CookieUtils.parseSetCookieHeader(header, details.url);
                if (!cookie) {
                    return "continue";
                }
                var bRule = CookieRulesFinder.lookupNotModifyingRule(cookie.name, context.rules, details.thirdParty);
                if (bRule) {
                    if (!bRule.isAllowlist()) {
                        details.responseHeaders.splice(i, 1);
                        headersModified = true;
                    }
                    this_1.filteringLog.addCookieEvent({
                        tabId: context.tabId,
                        cookieName: cookie.name,
                        cookieValue: cookie.value,
                        cookieDomain: cookie.domain,
                        cookieRule: bRule,
                        isModifyingCookieRule: false,
                        thirdParty: details.thirdParty,
                        timestamp: Date.now(),
                    });
                }
                var mRules = CookieRulesFinder.lookupModifyingRules(cookie.name, context.rules, details.thirdParty);
                if (mRules.length > 0) {
                    var appliedRules = CookieFiltering.applyRuleToBrowserCookie(cookie, mRules);
                    if (appliedRules.length > 0) {
                        headersModified = true;
                        details.responseHeaders[i] = { name: 'set-cookie', value: CookieUtils.serializeCookie(cookie) };
                        appliedRules.forEach(function (r) {
                            _this.filteringLog.addCookieEvent({
                                tabId: details.tabId,
                                cookieName: cookie.name,
                                cookieValue: cookie.value,
                                cookieDomain: cookie.domain,
                                cookieRule: r,
                                isModifyingCookieRule: true,
                                thirdParty: details.thirdParty,
                                timestamp: Date.now(),
                            });
                        });
                    }
                }
            };
            var this_1 = this;
            for (var i = details.responseHeaders.length - 1; i >= 0; i -= 1) {
                _loop_1(i);
            }
            return headersModified;
        };
        /**
         * Parses set-cookie header
         * looks up third-party cookies
         * This callback won't work for mv3 extensions
         * TODO separate or rewrite to mv2 and mv3 methods
         *
         * @param details
         */
        CookieFiltering.prototype.onHeadersReceived = function (details) {
            var _a;
            var context = this.requestContextStorage.get(details.requestId);
            if (!context) {
                return false;
            }
            if (details.responseHeaders) {
                var cookies = CookieUtils.parseSetCookieHeaders(details.responseHeaders, context.url);
                var newCookies = cookies.filter(function (c) { return !context.cookies.includes(c); });
                for (var _i = 0, newCookies_1 = newCookies; _i < newCookies_1.length; _i++) {
                    var cookie = newCookies_1[_i];
                    cookie.thirdParty = details.thirdParty;
                }
                (_a = context.cookies).push.apply(_a, newCookies);
            }
            // remove cookie headers
            // this method won't work in the extension build with manifest v3
            var headersModified = this.applyRulesToCookieHeaders(details);
            // removes cookies with browser.cookie api
            this.applyRules(details.requestId)
                .catch(function (e) {
                exports.logger.error(e.message);
            });
            return headersModified;
        };
        CookieFiltering.prototype.onCompleted = function (details) {
            this.requestContextStorage.delete(details.requestId);
        };
        CookieFiltering.prototype.onErrorOccurred = function (details) {
            this.requestContextStorage.delete(details.requestId);
        };
        /**
         * Looks up blocking rules for content-script
         *
         * @param requestId
         */
        CookieFiltering.prototype.getBlockingRules = function (requestId) {
            var context = this.requestContextStorage.get(requestId);
            if (!context) {
                return [];
            }
            return CookieRulesFinder.getBlockingRules(context.url, context.rules);
        };
        /**
         * Applies rules
         * @param requestId
         */
        CookieFiltering.prototype.applyRules = function (requestId) {
            return __awaiter(this, void 0, void 0, function () {
                var context, _a, rules, cookies, promises;
                var _this = this;
                return __generator(this, function (_b) {
                    switch (_b.label) {
                        case 0:
                            context = this.requestContextStorage.get(requestId);
                            _a = context, rules = _a.rules, cookies = _a.cookies;
                            if (!rules || !cookies) {
                                return [2 /*return*/];
                            }
                            promises = cookies.map(function (cookie) {
                                return _this.applyRulesToCookie(cookie, rules, context.tabId);
                            });
                            return [4 /*yield*/, Promise.all(promises)];
                        case 1:
                            _b.sent();
                            return [2 /*return*/];
                    }
                });
            });
        };
        /**
         * Applies rules to cookie
         *
         * @param cookie
         * @param cookieRules
         * @param tabId
         */
        /* istanbul ignore next */
        CookieFiltering.prototype.applyRulesToCookie = function (cookie, cookieRules, tabId) {
            return __awaiter(this, void 0, void 0, function () {
                var cookieName, isThirdPartyCookie, bRule, _a, mRules, appliedRules;
                var _this = this;
                return __generator(this, function (_b) {
                    switch (_b.label) {
                        case 0:
                            cookieName = cookie.name;
                            isThirdPartyCookie = cookie.thirdParty;
                            bRule = CookieRulesFinder.lookupNotModifyingRule(cookieName, cookieRules, isThirdPartyCookie);
                            if (!bRule) return [3 /*break*/, 3];
                            _a = bRule.isAllowlist();
                            if (_a) return [3 /*break*/, 2];
                            return [4 /*yield*/, this.browserCookieApi.removeCookie(cookie.name, cookie.url)];
                        case 1:
                            _a = (_b.sent());
                            _b.label = 2;
                        case 2:
                            if (_a) {
                                this.filteringLog.addCookieEvent({
                                    tabId: tabId,
                                    cookieName: cookie.name,
                                    cookieValue: cookie.value,
                                    cookieDomain: cookie.domain,
                                    cookieRule: bRule,
                                    isModifyingCookieRule: false,
                                    thirdParty: isThirdPartyCookie,
                                    timestamp: Date.now(),
                                });
                            }
                            return [2 /*return*/];
                        case 3:
                            mRules = CookieRulesFinder.lookupModifyingRules(cookieName, cookieRules, isThirdPartyCookie);
                            if (!(mRules.length > 0)) return [3 /*break*/, 5];
                            appliedRules = CookieFiltering.applyRuleToBrowserCookie(cookie, mRules);
                            if (!(appliedRules.length > 0)) return [3 /*break*/, 5];
                            return [4 /*yield*/, this.browserCookieApi.modifyCookie(cookie)];
                        case 4:
                            if (_b.sent()) {
                                appliedRules.forEach(function (r) {
                                    _this.filteringLog.addCookieEvent({
                                        tabId: tabId,
                                        cookieName: cookie.name,
                                        cookieValue: cookie.value,
                                        cookieDomain: cookie.domain,
                                        cookieRule: r,
                                        isModifyingCookieRule: true,
                                        thirdParty: isThirdPartyCookie,
                                        timestamp: Date.now(),
                                    });
                                });
                            }
                            _b.label = 5;
                        case 5: return [2 /*return*/];
                    }
                });
            });
        };
        /**
         * Modifies instance of BrowserCookie with provided rules
         *
         * @param cookie Cookie modify
         * @param rules Cookie matching rules
         * @return applied rules
         *
         */
        CookieFiltering.applyRuleToBrowserCookie = function (cookie, rules) {
            var appliedRules = [];
            for (var i = 0; i < rules.length; i += 1) {
                var rule = rules[i];
                if (rule.isAllowlist()) {
                    appliedRules.push(rule);
                    continue;
                }
                var cookieModifier = rule.getAdvancedModifier();
                var modified = false;
                var sameSite = cookieModifier.getSameSite();
                if (sameSite && cookie.sameSite !== sameSite) {
                    // eslint-disable-next-line no-param-reassign
                    cookie.sameSite = sameSite;
                    modified = true;
                }
                var maxAge = cookieModifier.getMaxAge();
                if (maxAge) {
                    if (CookieUtils.updateCookieMaxAge(cookie, maxAge)) {
                        modified = true;
                    }
                }
                if (modified) {
                    appliedRules.push(rule);
                }
            }
            return appliedRules;
        };
        return CookieFiltering;
    }());

    /**
     * This module applies stealth actions in page context
     */
    var StealthHelper = /** @class */ (function () {
        function StealthHelper() {
        }
        /**
         * Sends a Global Privacy Control DOM signal
         */
        StealthHelper.setDomSignal = function () {
            try {
                if ('globalPrivacyControl' in Navigator.prototype) {
                    return;
                }
                Object.defineProperty(Navigator.prototype, 'globalPrivacyControl', {
                    get: function () { return true; },
                    configurable: true,
                    enumerable: true,
                });
            }
            catch (ex) {
                // Ignore
            }
        };
        return StealthHelper;
    }());

    /**
     * Stealth action bitwise masks
     */
    exports.StealthActions = void 0;
    (function (StealthActions) {
        StealthActions[StealthActions["HIDE_REFERRER"] = 1] = "HIDE_REFERRER";
        StealthActions[StealthActions["HIDE_SEARCH_QUERIES"] = 2] = "HIDE_SEARCH_QUERIES";
        StealthActions[StealthActions["BLOCK_CHROME_CLIENT_DATA"] = 4] = "BLOCK_CHROME_CLIENT_DATA";
        StealthActions[StealthActions["SEND_DO_NOT_TRACK"] = 8] = "SEND_DO_NOT_TRACK";
        StealthActions[StealthActions["FIRST_PARTY_COOKIES"] = 16] = "FIRST_PARTY_COOKIES";
        StealthActions[StealthActions["THIRD_PARTY_COOKIES"] = 32] = "THIRD_PARTY_COOKIES";
    })(exports.StealthActions || (exports.StealthActions = {}));
    /**
     * Stealth service module
     */
    var StealthService = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param config
         */
        function StealthService(config) {
            this.config = config;
        }
        /**
         * Returns synthetic set of rules matching the specified request
         */
        StealthService.prototype.getCookieRulesTexts = function () {
            var result = [];
            if (this.config.selfDestructFirstPartyCookies) {
                result.push(StealthService.generateCookieRuleText(this.config.selfDestructFirstPartyCookiesTime));
            }
            if (this.config.selfDestructThirdPartyCookies) {
                result.push(StealthService.generateCookieRuleText(this.config.selfDestructThirdPartyCookiesTime, true));
            }
            return result;
        };
        /**
         * Applies stealth actions to request headers
         *
         * @param requestUrl
         * @param requestType
         * @param requestHeaders
         */
        StealthService.prototype.processRequestHeaders = function (requestUrl, requestType, requestHeaders) {
            var stealthActions = 0;
            // Remove referrer for third-party requests
            if (this.config.hideReferrer) {
                var refHeader = findHeaderByName(requestHeaders, StealthService.HEADERS.REFERRER);
                if (refHeader
                    && refHeader.value
                    && isThirdPartyRequest(requestUrl, refHeader.value)) {
                    refHeader.value = StealthService.createMockRefHeaderUrl(requestUrl);
                    stealthActions |= exports.StealthActions.HIDE_REFERRER;
                }
            }
            // Hide referrer in case of search engine is referrer
            var isMainFrame = requestType === exports.RequestType.Document;
            if (this.config.hideSearchQueries && isMainFrame) {
                var refHeader = findHeaderByName(requestHeaders, StealthService.HEADERS.REFERRER);
                if (refHeader
                    && refHeader.value
                    && StealthService.isSearchEngine(refHeader.value)
                    && isThirdPartyRequest(requestUrl, refHeader.value)) {
                    refHeader.value = StealthService.createMockRefHeaderUrl(requestUrl);
                    stealthActions |= exports.StealthActions.HIDE_SEARCH_QUERIES;
                }
            }
            // Remove X-Client-Data header
            if (this.config.blockChromeClientData) {
                if (removeHeader(requestHeaders, StealthService.HEADERS.X_CLIENT_DATA)) {
                    stealthActions |= exports.StealthActions.BLOCK_CHROME_CLIENT_DATA;
                }
            }
            // Adding Do-Not-Track (DNT) header
            if (this.config.sendDoNotTrack) {
                requestHeaders.push(StealthService.HEADER_VALUES.DO_NOT_TRACK);
                requestHeaders.push(StealthService.HEADER_VALUES.GLOBAL_PRIVACY_CONTROL);
                stealthActions |= exports.StealthActions.SEND_DO_NOT_TRACK;
            }
            return stealthActions;
        };
        /**
         * Returns set dom signal script if sendDoNotTrack enabled, otherwise empty string
         */
        StealthService.prototype.getSetDomSignalScript = function () {
            if (this.config.sendDoNotTrack) {
                return "(".concat(StealthHelper.setDomSignal.toString(), ")()");
            }
            return '';
        };
        /**
         * Generates rule removing cookies
         *
         * @param maxAgeMinutes Cookie maxAge in minutes
         * @param isThirdParty Flag for generating third-party rule texts
         */
        StealthService.generateCookieRuleText = function (maxAgeMinutes, isThirdParty) {
            if (isThirdParty === void 0) { isThirdParty = false; }
            var maxAgeOption = maxAgeMinutes > 0 ? ";maxAge=".concat(maxAgeMinutes * 60) : '';
            var thirdPartyOption = isThirdParty ? ',third-party' : '';
            var ruleText = "$cookie=/.+/".concat(maxAgeOption).concat(thirdPartyOption);
            return ruleText;
        };
        /**
         * Crops url path
         *
         * @param url URL
         * @return URL without path
         */
        StealthService.createMockRefHeaderUrl = function (url) {
            var host = getHost(url);
            return "".concat((url.indexOf('https') === 0 ? 'https://' : 'http://') + host, "/");
        };
        /**
         * Is url search engine
         *
         * @param url
         */
        StealthService.isSearchEngine = function (url) {
            return StealthService.SEARCH_ENGINES.some(function (searchEngineRegex) { return searchEngineRegex.test(url); });
        };
        /**
         * Headers
         */
        StealthService.HEADERS = {
            REFERRER: 'Referer',
            X_CLIENT_DATA: 'X-Client-Data',
            DO_NOT_TRACK: 'DNT',
        };
        /**
         * Header values
         */
        StealthService.HEADER_VALUES = {
            DO_NOT_TRACK: {
                name: 'DNT',
                value: '1',
            },
            GLOBAL_PRIVACY_CONTROL: {
                name: 'Sec-GPC',
                value: '1',
            },
        };
        /**
         * Search engines regexps
         *
         * @type {Array.<string>}
         */
        StealthService.SEARCH_ENGINES = [
            /https?:\/\/(www\.)?google\./i,
            /https?:\/\/(www\.)?yandex\./i,
            /https?:\/\/(www\.)?bing\./i,
            /https?:\/\/(www\.)?yahoo\./i,
            /https?:\/\/(www\.)?go\.mail\.ru/i,
            /https?:\/\/(www\.)?ask\.com/i,
            /https?:\/\/(www\.)?aol\.com/i,
            /https?:\/\/(www\.)?baidu\.com/i,
            /https?:\/\/(www\.)?seznam\.cz/i,
        ];
        return StealthService;
    }());

    /**
     * Headers filtering service module
     */
    var HeadersService = /** @class */ (function () {
        /**
         * Constructor
         *
         * @param filteringLog
         */
        function HeadersService(filteringLog) {
            this.filteringLog = filteringLog;
        }
        /**
         * On before send headers handler.
         * Removes request headers.
         *
         * @param details
         * @param rules
         * @return if headers modified
         */
        HeadersService.prototype.onBeforeSendHeaders = function (details, rules) {
            var _this = this;
            if (!details.requestHeaders) {
                return false;
            }
            if (rules.length === 0) {
                return false;
            }
            var result = false;
            rules.forEach(function (rule) {
                if (HeadersService.applyRule(details.requestHeaders, rule, true)) {
                    result = true;
                    _this.filteringLog.addRemoveHeaderEvent(details.tabId, details.url, rule.getAdvancedModifierValue(), rule);
                }
            });
            return result;
        };
        /**
         * On headers received handler.
         * Remove response headers.
         *
         * @param details
         * @param rules
         * @return if headers modified
         */
        HeadersService.prototype.onHeadersReceived = function (details, rules) {
            var _this = this;
            if (!details.responseHeaders) {
                return false;
            }
            if (rules.length === 0) {
                return false;
            }
            var result = false;
            rules.forEach(function (rule) {
                if (HeadersService.applyRule(details.responseHeaders, rule, false)) {
                    result = true;
                    _this.filteringLog.addRemoveHeaderEvent(details.tabId, details.url, rule.getAdvancedModifierValue(), rule);
                }
            });
            return result;
        };
        /**
         * Applies rule to headers
         *
         * @param headers
         * @param rule
         * @param isRequestHeaders
         */
        HeadersService.applyRule = function (headers, rule, isRequestHeaders) {
            var modifier = rule.getAdvancedModifier();
            if (!modifier) {
                return false;
            }
            var headerName = modifier.getApplicableHeaderName(isRequestHeaders);
            if (!headerName) {
                return false;
            }
            return removeHeader(headers, headerName);
        };
        return HeadersService;
    }());

    exports.ContentFiltering = ContentFiltering;
    exports.CookieFiltering = CookieFiltering;
    exports.CosmeticResult = CosmeticResult;
    exports.CosmeticRule = CosmeticRule;
    exports.CosmeticRuleParser = CosmeticRuleParser;
    exports.DeclarativeConverter = DeclarativeConverter;
    exports.DnsEngine = DnsEngine;
    exports.DnsResult = DnsResult;
    exports.EXT_CSS_PSEUDO_INDICATORS = EXT_CSS_PSEUDO_INDICATORS;
    exports.Engine = Engine;
    exports.HeadersService = HeadersService;
    exports.HostRule = HostRule;
    exports.IndexedRule = IndexedRule;
    exports.IndexedStorageRule = IndexedStorageRule;
    exports.LIST_ID_MAX_VALUE = LIST_ID_MAX_VALUE;
    exports.MatchingResult = MatchingResult;
    exports.NetworkRule = NetworkRule;
    exports.Request = Request$1;
    exports.RuleConverter = RuleConverter;
    exports.RuleFactory = RuleFactory;
    exports.RuleStorage = RuleStorage;
    exports.RuleSyntaxUtils = RuleSyntaxUtils;
    exports.RuleValidator = RuleValidator;
    exports.SimpleRegex = SimpleRegex;
    exports.StealthService = StealthService;
    exports.StringRuleList = StringRuleList;
    exports.cleanUrlParamByRegExp = cleanUrlParamByRegExp;
    exports.getCroppedDomain = getCroppedDomain;
    exports.getHost = getHost;
    exports.getRelativeUrl = getRelativeUrl;
    exports.isCompatibleWith = isCompatibleWith;
    exports.isDomainName = isDomainName;
    exports.isThirdPartyRequest = isThirdPartyRequest;
    exports.setConfiguration = setConfiguration;
    exports.setLogger = setLogger;

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

}));


/***/ }),

/***/ 8146:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);
var tryToString = __webpack_require__(368);

var TypeError = global.TypeError;

// `Assert: IsCallable(argument) is true`
module.exports = function (argument) {
  if (isCallable(argument)) return argument;
  throw TypeError(tryToString(argument) + ' is not a function');
};


/***/ }),

/***/ 7321:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isConstructor = __webpack_require__(7558);
var tryToString = __webpack_require__(368);

var TypeError = global.TypeError;

// `Assert: IsConstructor(argument) is true`
module.exports = function (argument) {
  if (isConstructor(argument)) return argument;
  throw TypeError(tryToString(argument) + ' is not a constructor');
};


/***/ }),

/***/ 1402:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);

var String = global.String;
var TypeError = global.TypeError;

module.exports = function (argument) {
  if (typeof argument == 'object' || isCallable(argument)) return argument;
  throw TypeError("Can't set " + String(argument) + ' as a prototype');
};


/***/ }),

/***/ 8514:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isObject = __webpack_require__(3041);

var String = global.String;
var TypeError = global.TypeError;

// `Assert: Type(argument) is Object`
module.exports = function (argument) {
  if (isObject(argument)) return argument;
  throw TypeError(String(argument) + ' is not an object');
};


/***/ }),

/***/ 4686:
/***/ ((module) => {

// eslint-disable-next-line es/no-typed-arrays -- safe
module.exports = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined';


/***/ }),

/***/ 9547:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var NATIVE_ARRAY_BUFFER = __webpack_require__(4686);
var DESCRIPTORS = __webpack_require__(6372);
var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);
var isObject = __webpack_require__(3041);
var hasOwn = __webpack_require__(1325);
var classof = __webpack_require__(7298);
var tryToString = __webpack_require__(368);
var createNonEnumerableProperty = __webpack_require__(7767);
var redefine = __webpack_require__(852);
var defineProperty = (__webpack_require__(6572).f);
var isPrototypeOf = __webpack_require__(3071);
var getPrototypeOf = __webpack_require__(6350);
var setPrototypeOf = __webpack_require__(744);
var wellKnownSymbol = __webpack_require__(4259);
var uid = __webpack_require__(6004);

var Int8Array = global.Int8Array;
var Int8ArrayPrototype = Int8Array && Int8Array.prototype;
var Uint8ClampedArray = global.Uint8ClampedArray;
var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
var TypedArray = Int8Array && getPrototypeOf(Int8Array);
var TypedArrayPrototype = Int8ArrayPrototype && getPrototypeOf(Int8ArrayPrototype);
var ObjectPrototype = Object.prototype;
var TypeError = global.TypeError;

var TO_STRING_TAG = wellKnownSymbol('toStringTag');
var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
var TYPED_ARRAY_CONSTRUCTOR = uid('TYPED_ARRAY_CONSTRUCTOR');
// Fixing native typed arrays in Opera Presto crashes the browser, see #595
var NATIVE_ARRAY_BUFFER_VIEWS = NATIVE_ARRAY_BUFFER && !!setPrototypeOf && classof(global.opera) !== 'Opera';
var TYPED_ARRAY_TAG_REQUIRED = false;
var NAME, Constructor, Prototype;

var TypedArrayConstructorsList = {
  Int8Array: 1,
  Uint8Array: 1,
  Uint8ClampedArray: 1,
  Int16Array: 2,
  Uint16Array: 2,
  Int32Array: 4,
  Uint32Array: 4,
  Float32Array: 4,
  Float64Array: 8
};

var BigIntArrayConstructorsList = {
  BigInt64Array: 8,
  BigUint64Array: 8
};

var isView = function isView(it) {
  if (!isObject(it)) return false;
  var klass = classof(it);
  return klass === 'DataView'
    || hasOwn(TypedArrayConstructorsList, klass)
    || hasOwn(BigIntArrayConstructorsList, klass);
};

var isTypedArray = function (it) {
  if (!isObject(it)) return false;
  var klass = classof(it);
  return hasOwn(TypedArrayConstructorsList, klass)
    || hasOwn(BigIntArrayConstructorsList, klass);
};

var aTypedArray = function (it) {
  if (isTypedArray(it)) return it;
  throw TypeError('Target is not a typed array');
};

var aTypedArrayConstructor = function (C) {
  if (isCallable(C) && (!setPrototypeOf || isPrototypeOf(TypedArray, C))) return C;
  throw TypeError(tryToString(C) + ' is not a typed array constructor');
};

var exportTypedArrayMethod = function (KEY, property, forced, options) {
  if (!DESCRIPTORS) return;
  if (forced) for (var ARRAY in TypedArrayConstructorsList) {
    var TypedArrayConstructor = global[ARRAY];
    if (TypedArrayConstructor && hasOwn(TypedArrayConstructor.prototype, KEY)) try {
      delete TypedArrayConstructor.prototype[KEY];
    } catch (error) {
      // old WebKit bug - some methods are non-configurable
      try {
        TypedArrayConstructor.prototype[KEY] = property;
      } catch (error2) { /* empty */ }
    }
  }
  if (!TypedArrayPrototype[KEY] || forced) {
    redefine(TypedArrayPrototype, KEY, forced ? property
      : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property, options);
  }
};

var exportTypedArrayStaticMethod = function (KEY, property, forced) {
  var ARRAY, TypedArrayConstructor;
  if (!DESCRIPTORS) return;
  if (setPrototypeOf) {
    if (forced) for (ARRAY in TypedArrayConstructorsList) {
      TypedArrayConstructor = global[ARRAY];
      if (TypedArrayConstructor && hasOwn(TypedArrayConstructor, KEY)) try {
        delete TypedArrayConstructor[KEY];
      } catch (error) { /* empty */ }
    }
    if (!TypedArray[KEY] || forced) {
      // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
      try {
        return redefine(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && TypedArray[KEY] || property);
      } catch (error) { /* empty */ }
    } else return;
  }
  for (ARRAY in TypedArrayConstructorsList) {
    TypedArrayConstructor = global[ARRAY];
    if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
      redefine(TypedArrayConstructor, KEY, property);
    }
  }
};

for (NAME in TypedArrayConstructorsList) {
  Constructor = global[NAME];
  Prototype = Constructor && Constructor.prototype;
  if (Prototype) createNonEnumerableProperty(Prototype, TYPED_ARRAY_CONSTRUCTOR, Constructor);
  else NATIVE_ARRAY_BUFFER_VIEWS = false;
}

for (NAME in BigIntArrayConstructorsList) {
  Constructor = global[NAME];
  Prototype = Constructor && Constructor.prototype;
  if (Prototype) createNonEnumerableProperty(Prototype, TYPED_ARRAY_CONSTRUCTOR, Constructor);
}

// WebKit bug - typed arrays constructors prototype is Object.prototype
if (!NATIVE_ARRAY_BUFFER_VIEWS || !isCallable(TypedArray) || TypedArray === Function.prototype) {
  // eslint-disable-next-line no-shadow -- safe
  TypedArray = function TypedArray() {
    throw TypeError('Incorrect invocation');
  };
  if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
    if (global[NAME]) setPrototypeOf(global[NAME], TypedArray);
  }
}

if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype) {
  TypedArrayPrototype = TypedArray.prototype;
  if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
    if (global[NAME]) setPrototypeOf(global[NAME].prototype, TypedArrayPrototype);
  }
}

// WebKit bug - one more object in Uint8ClampedArray prototype chain
if (NATIVE_ARRAY_BUFFER_VIEWS && getPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
  setPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
}

if (DESCRIPTORS && !hasOwn(TypedArrayPrototype, TO_STRING_TAG)) {
  TYPED_ARRAY_TAG_REQUIRED = true;
  defineProperty(TypedArrayPrototype, TO_STRING_TAG, { get: function () {
    return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
  } });
  for (NAME in TypedArrayConstructorsList) if (global[NAME]) {
    createNonEnumerableProperty(global[NAME], TYPED_ARRAY_TAG, NAME);
  }
}

module.exports = {
  NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
  TYPED_ARRAY_CONSTRUCTOR: TYPED_ARRAY_CONSTRUCTOR,
  TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQUIRED && TYPED_ARRAY_TAG,
  aTypedArray: aTypedArray,
  aTypedArrayConstructor: aTypedArrayConstructor,
  exportTypedArrayMethod: exportTypedArrayMethod,
  exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
  isView: isView,
  isTypedArray: isTypedArray,
  TypedArray: TypedArray,
  TypedArrayPrototype: TypedArrayPrototype
};


/***/ }),

/***/ 4465:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var toIndexedObject = __webpack_require__(9130);
var toAbsoluteIndex = __webpack_require__(3828);
var lengthOfArrayLike = __webpack_require__(5474);

// `Array.prototype.{ indexOf, includes }` methods implementation
var createMethod = function (IS_INCLUDES) {
  return function ($this, el, fromIndex) {
    var O = toIndexedObject($this);
    var length = lengthOfArrayLike(O);
    var index = toAbsoluteIndex(fromIndex, length);
    var value;
    // Array#includes uses SameValueZero equality algorithm
    // eslint-disable-next-line no-self-compare -- NaN check
    if (IS_INCLUDES && el != el) while (length > index) {
      value = O[index++];
      // eslint-disable-next-line no-self-compare -- NaN check
      if (value != value) return true;
    // Array#indexOf ignores holes, Array#includes - not
    } else for (;length > index; index++) {
      if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
    } return !IS_INCLUDES && -1;
  };
};

module.exports = {
  // `Array.prototype.includes` method
  // https://tc39.es/ecma262/#sec-array.prototype.includes
  includes: createMethod(true),
  // `Array.prototype.indexOf` method
  // https://tc39.es/ecma262/#sec-array.prototype.indexof
  indexOf: createMethod(false)
};


/***/ }),

/***/ 4021:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);

var toString = uncurryThis({}.toString);
var stringSlice = uncurryThis(''.slice);

module.exports = function (it) {
  return stringSlice(toString(it), 8, -1);
};


/***/ }),

/***/ 7298:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var TO_STRING_TAG_SUPPORT = __webpack_require__(8216);
var isCallable = __webpack_require__(2163);
var classofRaw = __webpack_require__(4021);
var wellKnownSymbol = __webpack_require__(4259);

var TO_STRING_TAG = wellKnownSymbol('toStringTag');
var Object = global.Object;

// ES3 wrong here
var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';

// fallback for IE11 Script Access Denied error
var tryGet = function (it, key) {
  try {
    return it[key];
  } catch (error) { /* empty */ }
};

// getting tag from ES6+ `Object.prototype.toString`
module.exports = TO_STRING_TAG_SUPPORT ? classofRaw : function (it) {
  var O, tag, result;
  return it === undefined ? 'Undefined' : it === null ? 'Null'
    // @@toStringTag case
    : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG)) == 'string' ? tag
    // builtinTag case
    : CORRECT_ARGUMENTS ? classofRaw(O)
    // ES3 arguments fallback
    : (result = classofRaw(O)) == 'Object' && isCallable(O.callee) ? 'Arguments' : result;
};


/***/ }),

/***/ 5425:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);

// https://github.com/tc39/collection-methods
module.exports = function addAll(/* ...elements */) {
  var set = anObject(this);
  var adder = aCallable(set.add);
  for (var k = 0, len = arguments.length; k < len; k++) {
    call(adder, set, arguments[k]);
  }
  return set;
};


/***/ }),

/***/ 11:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);

// https://github.com/tc39/collection-methods
module.exports = function deleteAll(/* ...elements */) {
  var collection = anObject(this);
  var remover = aCallable(collection['delete']);
  var allDeleted = true;
  var wasDeleted;
  for (var k = 0, len = arguments.length; k < len; k++) {
    wasDeleted = call(remover, collection, arguments[k]);
    allDeleted = allDeleted && wasDeleted;
  }
  return !!allDeleted;
};


/***/ }),

/***/ 1401:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var hasOwn = __webpack_require__(1325);
var ownKeys = __webpack_require__(810);
var getOwnPropertyDescriptorModule = __webpack_require__(9206);
var definePropertyModule = __webpack_require__(6572);

module.exports = function (target, source, exceptions) {
  var keys = ownKeys(source);
  var defineProperty = definePropertyModule.f;
  var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule.f;
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (!hasOwn(target, key) && !(exceptions && hasOwn(exceptions, key))) {
      defineProperty(target, key, getOwnPropertyDescriptor(source, key));
    }
  }
};


/***/ }),

/***/ 8165:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var fails = __webpack_require__(7931);

module.exports = !fails(function () {
  function F() { /* empty */ }
  F.prototype.constructor = null;
  // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
  return Object.getPrototypeOf(new F()) !== F.prototype;
});


/***/ }),

/***/ 7767:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var DESCRIPTORS = __webpack_require__(6372);
var definePropertyModule = __webpack_require__(6572);
var createPropertyDescriptor = __webpack_require__(8602);

module.exports = DESCRIPTORS ? function (object, key, value) {
  return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
} : function (object, key, value) {
  object[key] = value;
  return object;
};


/***/ }),

/***/ 8602:
/***/ ((module) => {

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


/***/ }),

/***/ 6372:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var fails = __webpack_require__(7931);

// Detect IE8's incomplete defineProperty implementation
module.exports = !fails(function () {
  // eslint-disable-next-line es/no-object-defineproperty -- required for testing
  return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
});


/***/ }),

/***/ 4193:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isObject = __webpack_require__(3041);

var document = global.document;
// typeof document.createElement is 'object' in old IE
var EXISTS = isObject(document) && isObject(document.createElement);

module.exports = function (it) {
  return EXISTS ? document.createElement(it) : {};
};


/***/ }),

/***/ 283:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var getBuiltIn = __webpack_require__(9997);

module.exports = getBuiltIn('navigator', 'userAgent') || '';


/***/ }),

/***/ 5111:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var userAgent = __webpack_require__(283);

var process = global.process;
var Deno = global.Deno;
var versions = process && process.versions || Deno && Deno.version;
var v8 = versions && versions.v8;
var match, version;

if (v8) {
  match = v8.split('.');
  // in old Chrome, versions of V8 isn't V8 = Chrome / 10
  // but their correct versions are not interesting for us
  version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);
}

// BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
// so check `userAgent` even if `.v8` exists, but 0
if (!version && userAgent) {
  match = userAgent.match(/Edge\/(\d+)/);
  if (!match || match[1] >= 74) {
    match = userAgent.match(/Chrome\/(\d+)/);
    if (match) version = +match[1];
  }
}

module.exports = version;


/***/ }),

/***/ 6606:
/***/ ((module) => {

// IE8- don't enum bug keys
module.exports = [
  'constructor',
  'hasOwnProperty',
  'isPrototypeOf',
  'propertyIsEnumerable',
  'toLocaleString',
  'toString',
  'valueOf'
];


/***/ }),

/***/ 5942:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var getOwnPropertyDescriptor = (__webpack_require__(9206).f);
var createNonEnumerableProperty = __webpack_require__(7767);
var redefine = __webpack_require__(852);
var setGlobal = __webpack_require__(6421);
var copyConstructorProperties = __webpack_require__(1401);
var isForced = __webpack_require__(1637);

/*
  options.target      - name of the target object
  options.global      - target is the global object
  options.stat        - export as static methods of target
  options.proto       - export as prototype methods of target
  options.real        - real prototype method for the `pure` version
  options.forced      - export even if the native feature is available
  options.bind        - bind methods to the target, required for the `pure` version
  options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
  options.unsafe      - use the simple assignment of property instead of delete + defineProperty
  options.sham        - add a flag to not completely full polyfills
  options.enumerable  - export as enumerable property
  options.noTargetGet - prevent calling a getter on target
  options.name        - the .name of the function if it does not match the key
*/
module.exports = function (options, source) {
  var TARGET = options.target;
  var GLOBAL = options.global;
  var STATIC = options.stat;
  var FORCED, target, key, targetProperty, sourceProperty, descriptor;
  if (GLOBAL) {
    target = global;
  } else if (STATIC) {
    target = global[TARGET] || setGlobal(TARGET, {});
  } else {
    target = (global[TARGET] || {}).prototype;
  }
  if (target) for (key in source) {
    sourceProperty = source[key];
    if (options.noTargetGet) {
      descriptor = getOwnPropertyDescriptor(target, key);
      targetProperty = descriptor && descriptor.value;
    } else targetProperty = target[key];
    FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
    // contained in target
    if (!FORCED && targetProperty !== undefined) {
      if (typeof sourceProperty == typeof targetProperty) continue;
      copyConstructorProperties(sourceProperty, targetProperty);
    }
    // add a flag to not completely full polyfills
    if (options.sham || (targetProperty && targetProperty.sham)) {
      createNonEnumerableProperty(sourceProperty, 'sham', true);
    }
    // extend global
    redefine(target, key, sourceProperty, options);
  }
};


/***/ }),

/***/ 7931:
/***/ ((module) => {

module.exports = function (exec) {
  try {
    return !!exec();
  } catch (error) {
    return true;
  }
};


/***/ }),

/***/ 8626:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var aCallable = __webpack_require__(8146);
var NATIVE_BIND = __webpack_require__(2637);

var bind = uncurryThis(uncurryThis.bind);

// optional / simple context binding
module.exports = function (fn, that) {
  aCallable(fn);
  return that === undefined ? fn : NATIVE_BIND ? bind(fn, that) : function (/* ...args */) {
    return fn.apply(that, arguments);
  };
};


/***/ }),

/***/ 2637:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var fails = __webpack_require__(7931);

module.exports = !fails(function () {
  var test = (function () { /* empty */ }).bind();
  // eslint-disable-next-line no-prototype-builtins -- safe
  return typeof test != 'function' || test.hasOwnProperty('prototype');
});


/***/ }),

/***/ 8624:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var NATIVE_BIND = __webpack_require__(2637);

var call = Function.prototype.call;

module.exports = NATIVE_BIND ? call.bind(call) : function () {
  return call.apply(call, arguments);
};


/***/ }),

/***/ 233:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var DESCRIPTORS = __webpack_require__(6372);
var hasOwn = __webpack_require__(1325);

var FunctionPrototype = Function.prototype;
// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
var getDescriptor = DESCRIPTORS && Object.getOwnPropertyDescriptor;

var EXISTS = hasOwn(FunctionPrototype, 'name');
// additional protection from minified / mangled / dropped function names
var PROPER = EXISTS && (function something() { /* empty */ }).name === 'something';
var CONFIGURABLE = EXISTS && (!DESCRIPTORS || (DESCRIPTORS && getDescriptor(FunctionPrototype, 'name').configurable));

module.exports = {
  EXISTS: EXISTS,
  PROPER: PROPER,
  CONFIGURABLE: CONFIGURABLE
};


/***/ }),

/***/ 3074:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var NATIVE_BIND = __webpack_require__(2637);

var FunctionPrototype = Function.prototype;
var bind = FunctionPrototype.bind;
var call = FunctionPrototype.call;
var uncurryThis = NATIVE_BIND && bind.bind(call, call);

module.exports = NATIVE_BIND ? function (fn) {
  return fn && uncurryThis(fn);
} : function (fn) {
  return fn && function () {
    return call.apply(fn, arguments);
  };
};


/***/ }),

/***/ 9997:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);

var aFunction = function (argument) {
  return isCallable(argument) ? argument : undefined;
};

module.exports = function (namespace, method) {
  return arguments.length < 2 ? aFunction(global[namespace]) : global[namespace] && global[namespace][method];
};


/***/ }),

/***/ 610:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var classof = __webpack_require__(7298);
var getMethod = __webpack_require__(4462);
var Iterators = __webpack_require__(6133);
var wellKnownSymbol = __webpack_require__(4259);

var ITERATOR = wellKnownSymbol('iterator');

module.exports = function (it) {
  if (it != undefined) return getMethod(it, ITERATOR)
    || getMethod(it, '@@iterator')
    || Iterators[classof(it)];
};


/***/ }),

/***/ 1570:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var tryToString = __webpack_require__(368);
var getIteratorMethod = __webpack_require__(610);

var TypeError = global.TypeError;

module.exports = function (argument, usingIterator) {
  var iteratorMethod = arguments.length < 2 ? getIteratorMethod(argument) : usingIterator;
  if (aCallable(iteratorMethod)) return anObject(call(iteratorMethod, argument));
  throw TypeError(tryToString(argument) + ' is not iterable');
};


/***/ }),

/***/ 1285:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var call = __webpack_require__(8624);

module.exports = function (it) {
  // eslint-disable-next-line es/no-map -- safe
  return call(Map.prototype.entries, it);
};


/***/ }),

/***/ 4462:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var aCallable = __webpack_require__(8146);

// `GetMethod` abstract operation
// https://tc39.es/ecma262/#sec-getmethod
module.exports = function (V, P) {
  var func = V[P];
  return func == null ? undefined : aCallable(func);
};


/***/ }),

/***/ 7762:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var call = __webpack_require__(8624);

module.exports = function (it) {
  // eslint-disable-next-line es/no-set -- safe
  return call(Set.prototype.values, it);
};


/***/ }),

/***/ 4053:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var toObject = __webpack_require__(7410);

var floor = Math.floor;
var charAt = uncurryThis(''.charAt);
var replace = uncurryThis(''.replace);
var stringSlice = uncurryThis(''.slice);
var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;

// `GetSubstitution` abstract operation
// https://tc39.es/ecma262/#sec-getsubstitution
module.exports = function (matched, str, position, captures, namedCaptures, replacement) {
  var tailPos = position + matched.length;
  var m = captures.length;
  var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
  if (namedCaptures !== undefined) {
    namedCaptures = toObject(namedCaptures);
    symbols = SUBSTITUTION_SYMBOLS;
  }
  return replace(replacement, symbols, function (match, ch) {
    var capture;
    switch (charAt(ch, 0)) {
      case '$': return '$';
      case '&': return matched;
      case '`': return stringSlice(str, 0, position);
      case "'": return stringSlice(str, tailPos);
      case '<':
        capture = namedCaptures[stringSlice(ch, 1, -1)];
        break;
      default: // \d\d?
        var n = +ch;
        if (n === 0) return match;
        if (n > m) {
          var f = floor(n / 10);
          if (f === 0) return match;
          if (f <= m) return captures[f - 1] === undefined ? charAt(ch, 1) : captures[f - 1] + charAt(ch, 1);
          return match;
        }
        capture = captures[n - 1];
    }
    return capture === undefined ? '' : capture;
  });
};


/***/ }),

/***/ 3406:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var check = function (it) {
  return it && it.Math == Math && it;
};

// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
module.exports =
  // eslint-disable-next-line es/no-global-this -- safe
  check(typeof globalThis == 'object' && globalThis) ||
  check(typeof window == 'object' && window) ||
  // eslint-disable-next-line no-restricted-globals -- safe
  check(typeof self == 'object' && self) ||
  check(typeof __webpack_require__.g == 'object' && __webpack_require__.g) ||
  // eslint-disable-next-line no-new-func -- fallback
  (function () { return this; })() || Function('return this')();


/***/ }),

/***/ 1325:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var toObject = __webpack_require__(7410);

var hasOwnProperty = uncurryThis({}.hasOwnProperty);

// `HasOwnProperty` abstract operation
// https://tc39.es/ecma262/#sec-hasownproperty
module.exports = Object.hasOwn || function hasOwn(it, key) {
  return hasOwnProperty(toObject(it), key);
};


/***/ }),

/***/ 3730:
/***/ ((module) => {

module.exports = {};


/***/ }),

/***/ 3202:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var DESCRIPTORS = __webpack_require__(6372);
var fails = __webpack_require__(7931);
var createElement = __webpack_require__(4193);

// Thanks to IE8 for its funny defineProperty
module.exports = !DESCRIPTORS && !fails(function () {
  // eslint-disable-next-line es/no-object-defineproperty -- required for testing
  return Object.defineProperty(createElement('div'), 'a', {
    get: function () { return 7; }
  }).a != 7;
});


/***/ }),

/***/ 2170:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var uncurryThis = __webpack_require__(3074);
var fails = __webpack_require__(7931);
var classof = __webpack_require__(4021);

var Object = global.Object;
var split = uncurryThis(''.split);

// fallback for non-array-like ES3 and non-enumerable old V8 strings
module.exports = fails(function () {
  // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
  // eslint-disable-next-line no-prototype-builtins -- safe
  return !Object('z').propertyIsEnumerable(0);
}) ? function (it) {
  return classof(it) == 'String' ? split(it, '') : Object(it);
} : Object;


/***/ }),

/***/ 2089:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var isCallable = __webpack_require__(2163);
var store = __webpack_require__(2846);

var functionToString = uncurryThis(Function.toString);

// this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
if (!isCallable(store.inspectSource)) {
  store.inspectSource = function (it) {
    return functionToString(it);
  };
}

module.exports = store.inspectSource;


/***/ }),

/***/ 3987:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var NATIVE_WEAK_MAP = __webpack_require__(5062);
var global = __webpack_require__(3406);
var uncurryThis = __webpack_require__(3074);
var isObject = __webpack_require__(3041);
var createNonEnumerableProperty = __webpack_require__(7767);
var hasOwn = __webpack_require__(1325);
var shared = __webpack_require__(2846);
var sharedKey = __webpack_require__(1320);
var hiddenKeys = __webpack_require__(3730);

var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
var TypeError = global.TypeError;
var WeakMap = global.WeakMap;
var set, get, has;

var enforce = function (it) {
  return has(it) ? get(it) : set(it, {});
};

var getterFor = function (TYPE) {
  return function (it) {
    var state;
    if (!isObject(it) || (state = get(it)).type !== TYPE) {
      throw TypeError('Incompatible receiver, ' + TYPE + ' required');
    } return state;
  };
};

if (NATIVE_WEAK_MAP || shared.state) {
  var store = shared.state || (shared.state = new WeakMap());
  var wmget = uncurryThis(store.get);
  var wmhas = uncurryThis(store.has);
  var wmset = uncurryThis(store.set);
  set = function (it, metadata) {
    if (wmhas(store, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
    metadata.facade = it;
    wmset(store, it, metadata);
    return metadata;
  };
  get = function (it) {
    return wmget(store, it) || {};
  };
  has = function (it) {
    return wmhas(store, it);
  };
} else {
  var STATE = sharedKey('state');
  hiddenKeys[STATE] = true;
  set = function (it, metadata) {
    if (hasOwn(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
    metadata.facade = it;
    createNonEnumerableProperty(it, STATE, metadata);
    return metadata;
  };
  get = function (it) {
    return hasOwn(it, STATE) ? it[STATE] : {};
  };
  has = function (it) {
    return hasOwn(it, STATE);
  };
}

module.exports = {
  set: set,
  get: get,
  has: has,
  enforce: enforce,
  getterFor: getterFor
};


/***/ }),

/***/ 8335:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var wellKnownSymbol = __webpack_require__(4259);
var Iterators = __webpack_require__(6133);

var ITERATOR = wellKnownSymbol('iterator');
var ArrayPrototype = Array.prototype;

// check on default Array iterator
module.exports = function (it) {
  return it !== undefined && (Iterators.Array === it || ArrayPrototype[ITERATOR] === it);
};


/***/ }),

/***/ 2163:
/***/ ((module) => {

// `IsCallable` abstract operation
// https://tc39.es/ecma262/#sec-iscallable
module.exports = function (argument) {
  return typeof argument == 'function';
};


/***/ }),

/***/ 7558:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var fails = __webpack_require__(7931);
var isCallable = __webpack_require__(2163);
var classof = __webpack_require__(7298);
var getBuiltIn = __webpack_require__(9997);
var inspectSource = __webpack_require__(2089);

var noop = function () { /* empty */ };
var empty = [];
var construct = getBuiltIn('Reflect', 'construct');
var constructorRegExp = /^\s*(?:class|function)\b/;
var exec = uncurryThis(constructorRegExp.exec);
var INCORRECT_TO_STRING = !constructorRegExp.exec(noop);

var isConstructorModern = function isConstructor(argument) {
  if (!isCallable(argument)) return false;
  try {
    construct(noop, empty, argument);
    return true;
  } catch (error) {
    return false;
  }
};

var isConstructorLegacy = function isConstructor(argument) {
  if (!isCallable(argument)) return false;
  switch (classof(argument)) {
    case 'AsyncFunction':
    case 'GeneratorFunction':
    case 'AsyncGeneratorFunction': return false;
  }
  try {
    // we can't check .prototype since constructors produced by .bind haven't it
    // `Function#toString` throws on some built-it function in some legacy engines
    // (for example, `DOMQuad` and similar in FF41-)
    return INCORRECT_TO_STRING || !!exec(constructorRegExp, inspectSource(argument));
  } catch (error) {
    return true;
  }
};

isConstructorLegacy.sham = true;

// `IsConstructor` abstract operation
// https://tc39.es/ecma262/#sec-isconstructor
module.exports = !construct || fails(function () {
  var called;
  return isConstructorModern(isConstructorModern.call)
    || !isConstructorModern(Object)
    || !isConstructorModern(function () { called = true; })
    || called;
}) ? isConstructorLegacy : isConstructorModern;


/***/ }),

/***/ 1637:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var fails = __webpack_require__(7931);
var isCallable = __webpack_require__(2163);

var replacement = /#|\.prototype\./;

var isForced = function (feature, detection) {
  var value = data[normalize(feature)];
  return value == POLYFILL ? true
    : value == NATIVE ? false
    : isCallable(detection) ? fails(detection)
    : !!detection;
};

var normalize = isForced.normalize = function (string) {
  return String(string).replace(replacement, '.').toLowerCase();
};

var data = isForced.data = {};
var NATIVE = isForced.NATIVE = 'N';
var POLYFILL = isForced.POLYFILL = 'P';

module.exports = isForced;


/***/ }),

/***/ 3041:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var isCallable = __webpack_require__(2163);

module.exports = function (it) {
  return typeof it == 'object' ? it !== null : isCallable(it);
};


/***/ }),

/***/ 2884:
/***/ ((module) => {

module.exports = false;


/***/ }),

/***/ 3948:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var isObject = __webpack_require__(3041);
var classof = __webpack_require__(4021);
var wellKnownSymbol = __webpack_require__(4259);

var MATCH = wellKnownSymbol('match');

// `IsRegExp` abstract operation
// https://tc39.es/ecma262/#sec-isregexp
module.exports = function (it) {
  var isRegExp;
  return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classof(it) == 'RegExp');
};


/***/ }),

/***/ 5666:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var getBuiltIn = __webpack_require__(9997);
var isCallable = __webpack_require__(2163);
var isPrototypeOf = __webpack_require__(3071);
var USE_SYMBOL_AS_UID = __webpack_require__(9525);

var Object = global.Object;

module.exports = USE_SYMBOL_AS_UID ? function (it) {
  return typeof it == 'symbol';
} : function (it) {
  var $Symbol = getBuiltIn('Symbol');
  return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, Object(it));
};


/***/ }),

/***/ 7523:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var bind = __webpack_require__(8626);
var call = __webpack_require__(8624);
var anObject = __webpack_require__(8514);
var tryToString = __webpack_require__(368);
var isArrayIteratorMethod = __webpack_require__(8335);
var lengthOfArrayLike = __webpack_require__(5474);
var isPrototypeOf = __webpack_require__(3071);
var getIterator = __webpack_require__(1570);
var getIteratorMethod = __webpack_require__(610);
var iteratorClose = __webpack_require__(1652);

var TypeError = global.TypeError;

var Result = function (stopped, result) {
  this.stopped = stopped;
  this.result = result;
};

var ResultPrototype = Result.prototype;

module.exports = function (iterable, unboundFunction, options) {
  var that = options && options.that;
  var AS_ENTRIES = !!(options && options.AS_ENTRIES);
  var IS_ITERATOR = !!(options && options.IS_ITERATOR);
  var INTERRUPTED = !!(options && options.INTERRUPTED);
  var fn = bind(unboundFunction, that);
  var iterator, iterFn, index, length, result, next, step;

  var stop = function (condition) {
    if (iterator) iteratorClose(iterator, 'normal', condition);
    return new Result(true, condition);
  };

  var callFn = function (value) {
    if (AS_ENTRIES) {
      anObject(value);
      return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
    } return INTERRUPTED ? fn(value, stop) : fn(value);
  };

  if (IS_ITERATOR) {
    iterator = iterable;
  } else {
    iterFn = getIteratorMethod(iterable);
    if (!iterFn) throw TypeError(tryToString(iterable) + ' is not iterable');
    // optimisation for array iterators
    if (isArrayIteratorMethod(iterFn)) {
      for (index = 0, length = lengthOfArrayLike(iterable); length > index; index++) {
        result = callFn(iterable[index]);
        if (result && isPrototypeOf(ResultPrototype, result)) return result;
      } return new Result(false);
    }
    iterator = getIterator(iterable, iterFn);
  }

  next = iterator.next;
  while (!(step = call(next, iterator)).done) {
    try {
      result = callFn(step.value);
    } catch (error) {
      iteratorClose(iterator, 'throw', error);
    }
    if (typeof result == 'object' && result && isPrototypeOf(ResultPrototype, result)) return result;
  } return new Result(false);
};


/***/ }),

/***/ 1652:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var call = __webpack_require__(8624);
var anObject = __webpack_require__(8514);
var getMethod = __webpack_require__(4462);

module.exports = function (iterator, kind, value) {
  var innerResult, innerError;
  anObject(iterator);
  try {
    innerResult = getMethod(iterator, 'return');
    if (!innerResult) {
      if (kind === 'throw') throw value;
      return value;
    }
    innerResult = call(innerResult, iterator);
  } catch (error) {
    innerError = true;
    innerResult = error;
  }
  if (kind === 'throw') throw value;
  if (innerError) throw innerResult;
  anObject(innerResult);
  return value;
};


/***/ }),

/***/ 6133:
/***/ ((module) => {

module.exports = {};


/***/ }),

/***/ 5474:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var toLength = __webpack_require__(1403);

// `LengthOfArrayLike` abstract operation
// https://tc39.es/ecma262/#sec-lengthofarraylike
module.exports = function (obj) {
  return toLength(obj.length);
};


/***/ }),

/***/ 3325:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

/* eslint-disable es/no-symbol -- required for testing */
var V8_VERSION = __webpack_require__(5111);
var fails = __webpack_require__(7931);

// eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
module.exports = !!Object.getOwnPropertySymbols && !fails(function () {
  var symbol = Symbol();
  // Chrome 38 Symbol has incorrect toString conversion
  // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
  return !String(symbol) || !(Object(symbol) instanceof Symbol) ||
    // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
    !Symbol.sham && V8_VERSION && V8_VERSION < 41;
});


/***/ }),

/***/ 5062:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);
var inspectSource = __webpack_require__(2089);

var WeakMap = global.WeakMap;

module.exports = isCallable(WeakMap) && /native code/.test(inspectSource(WeakMap));


/***/ }),

/***/ 6572:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var DESCRIPTORS = __webpack_require__(6372);
var IE8_DOM_DEFINE = __webpack_require__(3202);
var V8_PROTOTYPE_DEFINE_BUG = __webpack_require__(8814);
var anObject = __webpack_require__(8514);
var toPropertyKey = __webpack_require__(1973);

var TypeError = global.TypeError;
// eslint-disable-next-line es/no-object-defineproperty -- safe
var $defineProperty = Object.defineProperty;
// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var ENUMERABLE = 'enumerable';
var CONFIGURABLE = 'configurable';
var WRITABLE = 'writable';

// `Object.defineProperty` method
// https://tc39.es/ecma262/#sec-object.defineproperty
exports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) {
  anObject(O);
  P = toPropertyKey(P);
  anObject(Attributes);
  if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {
    var current = $getOwnPropertyDescriptor(O, P);
    if (current && current[WRITABLE]) {
      O[P] = Attributes.value;
      Attributes = {
        configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE],
        enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],
        writable: false
      };
    }
  } return $defineProperty(O, P, Attributes);
} : $defineProperty : function defineProperty(O, P, Attributes) {
  anObject(O);
  P = toPropertyKey(P);
  anObject(Attributes);
  if (IE8_DOM_DEFINE) try {
    return $defineProperty(O, P, Attributes);
  } catch (error) { /* empty */ }
  if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
  if ('value' in Attributes) O[P] = Attributes.value;
  return O;
};


/***/ }),

/***/ 9206:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {

var DESCRIPTORS = __webpack_require__(6372);
var call = __webpack_require__(8624);
var propertyIsEnumerableModule = __webpack_require__(2251);
var createPropertyDescriptor = __webpack_require__(8602);
var toIndexedObject = __webpack_require__(9130);
var toPropertyKey = __webpack_require__(1973);
var hasOwn = __webpack_require__(1325);
var IE8_DOM_DEFINE = __webpack_require__(3202);

// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;

// `Object.getOwnPropertyDescriptor` method
// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
exports.f = DESCRIPTORS ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
  O = toIndexedObject(O);
  P = toPropertyKey(P);
  if (IE8_DOM_DEFINE) try {
    return $getOwnPropertyDescriptor(O, P);
  } catch (error) { /* empty */ }
  if (hasOwn(O, P)) return createPropertyDescriptor(!call(propertyIsEnumerableModule.f, O, P), O[P]);
};


/***/ }),

/***/ 3311:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {

var internalObjectKeys = __webpack_require__(1429);
var enumBugKeys = __webpack_require__(6606);

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

// `Object.getOwnPropertyNames` method
// https://tc39.es/ecma262/#sec-object.getownpropertynames
// eslint-disable-next-line es/no-object-getownpropertynames -- safe
exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
  return internalObjectKeys(O, hiddenKeys);
};


/***/ }),

/***/ 395:
/***/ ((__unused_webpack_module, exports) => {

// eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
exports.f = Object.getOwnPropertySymbols;


/***/ }),

/***/ 6350:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var hasOwn = __webpack_require__(1325);
var isCallable = __webpack_require__(2163);
var toObject = __webpack_require__(7410);
var sharedKey = __webpack_require__(1320);
var CORRECT_PROTOTYPE_GETTER = __webpack_require__(8165);

var IE_PROTO = sharedKey('IE_PROTO');
var Object = global.Object;
var ObjectPrototype = Object.prototype;

// `Object.getPrototypeOf` method
// https://tc39.es/ecma262/#sec-object.getprototypeof
module.exports = CORRECT_PROTOTYPE_GETTER ? Object.getPrototypeOf : function (O) {
  var object = toObject(O);
  if (hasOwn(object, IE_PROTO)) return object[IE_PROTO];
  var constructor = object.constructor;
  if (isCallable(constructor) && object instanceof constructor) {
    return constructor.prototype;
  } return object instanceof Object ? ObjectPrototype : null;
};


/***/ }),

/***/ 3071:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);

module.exports = uncurryThis({}.isPrototypeOf);


/***/ }),

/***/ 1429:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);
var hasOwn = __webpack_require__(1325);
var toIndexedObject = __webpack_require__(9130);
var indexOf = (__webpack_require__(4465).indexOf);
var hiddenKeys = __webpack_require__(3730);

var push = uncurryThis([].push);

module.exports = function (object, names) {
  var O = toIndexedObject(object);
  var i = 0;
  var result = [];
  var key;
  for (key in O) !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key);
  // Don't enum bug & hidden keys
  while (names.length > i) if (hasOwn(O, key = names[i++])) {
    ~indexOf(result, key) || push(result, key);
  }
  return result;
};


/***/ }),

/***/ 2251:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

var $propertyIsEnumerable = {}.propertyIsEnumerable;
// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;

// Nashorn ~ JDK8 bug
var NASHORN_BUG = getOwnPropertyDescriptor && !$propertyIsEnumerable.call({ 1: 2 }, 1);

// `Object.prototype.propertyIsEnumerable` method implementation
// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
exports.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
  var descriptor = getOwnPropertyDescriptor(this, V);
  return !!descriptor && descriptor.enumerable;
} : $propertyIsEnumerable;


/***/ }),

/***/ 744:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

/* eslint-disable no-proto -- safe */
var uncurryThis = __webpack_require__(3074);
var anObject = __webpack_require__(8514);
var aPossiblePrototype = __webpack_require__(1402);

// `Object.setPrototypeOf` method
// https://tc39.es/ecma262/#sec-object.setprototypeof
// Works with __proto__ only. Old v8 can't work with null proto objects.
// eslint-disable-next-line es/no-object-setprototypeof -- safe
module.exports = Object.setPrototypeOf || ('__proto__' in {} ? function () {
  var CORRECT_SETTER = false;
  var test = {};
  var setter;
  try {
    // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
    setter = uncurryThis(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set);
    setter(test, []);
    CORRECT_SETTER = test instanceof Array;
  } catch (error) { /* empty */ }
  return function setPrototypeOf(O, proto) {
    anObject(O);
    aPossiblePrototype(proto);
    if (CORRECT_SETTER) setter(O, proto);
    else O.__proto__ = proto;
    return O;
  };
}() : undefined);


/***/ }),

/***/ 9207:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var isCallable = __webpack_require__(2163);
var isObject = __webpack_require__(3041);

var TypeError = global.TypeError;

// `OrdinaryToPrimitive` abstract operation
// https://tc39.es/ecma262/#sec-ordinarytoprimitive
module.exports = function (input, pref) {
  var fn, val;
  if (pref === 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;
  if (isCallable(fn = input.valueOf) && !isObject(val = call(fn, input))) return val;
  if (pref !== 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;
  throw TypeError("Can't convert object to primitive value");
};


/***/ }),

/***/ 810:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var getBuiltIn = __webpack_require__(9997);
var uncurryThis = __webpack_require__(3074);
var getOwnPropertyNamesModule = __webpack_require__(3311);
var getOwnPropertySymbolsModule = __webpack_require__(395);
var anObject = __webpack_require__(8514);

var concat = uncurryThis([].concat);

// all object keys, includes non-enumerable and symbols
module.exports = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
  var keys = getOwnPropertyNamesModule.f(anObject(it));
  var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
  return getOwnPropertySymbols ? concat(keys, getOwnPropertySymbols(it)) : keys;
};


/***/ }),

/***/ 852:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var isCallable = __webpack_require__(2163);
var hasOwn = __webpack_require__(1325);
var createNonEnumerableProperty = __webpack_require__(7767);
var setGlobal = __webpack_require__(6421);
var inspectSource = __webpack_require__(2089);
var InternalStateModule = __webpack_require__(3987);
var CONFIGURABLE_FUNCTION_NAME = (__webpack_require__(233).CONFIGURABLE);

var getInternalState = InternalStateModule.get;
var enforceInternalState = InternalStateModule.enforce;
var TEMPLATE = String(String).split('String');

(module.exports = function (O, key, value, options) {
  var unsafe = options ? !!options.unsafe : false;
  var simple = options ? !!options.enumerable : false;
  var noTargetGet = options ? !!options.noTargetGet : false;
  var name = options && options.name !== undefined ? options.name : key;
  var state;
  if (isCallable(value)) {
    if (String(name).slice(0, 7) === 'Symbol(') {
      name = '[' + String(name).replace(/^Symbol\(([^)]*)\)/, '$1') + ']';
    }
    if (!hasOwn(value, 'name') || (CONFIGURABLE_FUNCTION_NAME && value.name !== name)) {
      createNonEnumerableProperty(value, 'name', name);
    }
    state = enforceInternalState(value);
    if (!state.source) {
      state.source = TEMPLATE.join(typeof name == 'string' ? name : '');
    }
  }
  if (O === global) {
    if (simple) O[key] = value;
    else setGlobal(key, value);
    return;
  } else if (!unsafe) {
    delete O[key];
  } else if (!noTargetGet && O[key]) {
    simple = true;
  }
  if (simple) O[key] = value;
  else createNonEnumerableProperty(O, key, value);
// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
})(Function.prototype, 'toString', function toString() {
  return isCallable(this) && getInternalState(this).source || inspectSource(this);
});


/***/ }),

/***/ 6061:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var anObject = __webpack_require__(8514);

// `RegExp.prototype.flags` getter implementation
// https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
module.exports = function () {
  var that = anObject(this);
  var result = '';
  if (that.global) result += 'g';
  if (that.ignoreCase) result += 'i';
  if (that.multiline) result += 'm';
  if (that.dotAll) result += 's';
  if (that.unicode) result += 'u';
  if (that.sticky) result += 'y';
  return result;
};


/***/ }),

/***/ 5727:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);

var TypeError = global.TypeError;

// `RequireObjectCoercible` abstract operation
// https://tc39.es/ecma262/#sec-requireobjectcoercible
module.exports = function (it) {
  if (it == undefined) throw TypeError("Can't call method on " + it);
  return it;
};


/***/ }),

/***/ 2209:
/***/ ((module) => {

// `SameValueZero` abstract operation
// https://tc39.es/ecma262/#sec-samevaluezero
module.exports = function (x, y) {
  // eslint-disable-next-line no-self-compare -- NaN check
  return x === y || x != x && y != y;
};


/***/ }),

/***/ 6421:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);

// eslint-disable-next-line es/no-object-defineproperty -- safe
var defineProperty = Object.defineProperty;

module.exports = function (key, value) {
  try {
    defineProperty(global, key, { value: value, configurable: true, writable: true });
  } catch (error) {
    global[key] = value;
  } return value;
};


/***/ }),

/***/ 1320:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var shared = __webpack_require__(8519);
var uid = __webpack_require__(6004);

var keys = shared('keys');

module.exports = function (key) {
  return keys[key] || (keys[key] = uid(key));
};


/***/ }),

/***/ 2846:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var setGlobal = __webpack_require__(6421);

var SHARED = '__core-js_shared__';
var store = global[SHARED] || setGlobal(SHARED, {});

module.exports = store;


/***/ }),

/***/ 8519:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var IS_PURE = __webpack_require__(2884);
var store = __webpack_require__(2846);

(module.exports = function (key, value) {
  return store[key] || (store[key] = value !== undefined ? value : {});
})('versions', []).push({
  version: '3.21.1',
  mode: IS_PURE ? 'pure' : 'global',
  copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',
  license: 'https://github.com/zloirock/core-js/blob/v3.21.1/LICENSE',
  source: 'https://github.com/zloirock/core-js'
});


/***/ }),

/***/ 4499:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var anObject = __webpack_require__(8514);
var aConstructor = __webpack_require__(7321);
var wellKnownSymbol = __webpack_require__(4259);

var SPECIES = wellKnownSymbol('species');

// `SpeciesConstructor` abstract operation
// https://tc39.es/ecma262/#sec-speciesconstructor
module.exports = function (O, defaultConstructor) {
  var C = anObject(O).constructor;
  var S;
  return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? defaultConstructor : aConstructor(S);
};


/***/ }),

/***/ 3828:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var toIntegerOrInfinity = __webpack_require__(400);

var max = Math.max;
var min = Math.min;

// Helper for a popular repeating case of the spec:
// Let integer be ? ToInteger(index).
// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
module.exports = function (index, length) {
  var integer = toIntegerOrInfinity(index);
  return integer < 0 ? max(integer + length, 0) : min(integer, length);
};


/***/ }),

/***/ 9130:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

// toObject with fallback for non-array-like ES3 strings
var IndexedObject = __webpack_require__(2170);
var requireObjectCoercible = __webpack_require__(5727);

module.exports = function (it) {
  return IndexedObject(requireObjectCoercible(it));
};


/***/ }),

/***/ 400:
/***/ ((module) => {

var ceil = Math.ceil;
var floor = Math.floor;

// `ToIntegerOrInfinity` abstract operation
// https://tc39.es/ecma262/#sec-tointegerorinfinity
module.exports = function (argument) {
  var number = +argument;
  // eslint-disable-next-line no-self-compare -- safe
  return number !== number || number === 0 ? 0 : (number > 0 ? floor : ceil)(number);
};


/***/ }),

/***/ 1403:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var toIntegerOrInfinity = __webpack_require__(400);

var min = Math.min;

// `ToLength` abstract operation
// https://tc39.es/ecma262/#sec-tolength
module.exports = function (argument) {
  return argument > 0 ? min(toIntegerOrInfinity(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
};


/***/ }),

/***/ 7410:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var requireObjectCoercible = __webpack_require__(5727);

var Object = global.Object;

// `ToObject` abstract operation
// https://tc39.es/ecma262/#sec-toobject
module.exports = function (argument) {
  return Object(requireObjectCoercible(argument));
};


/***/ }),

/***/ 3170:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var toPositiveInteger = __webpack_require__(4064);

var RangeError = global.RangeError;

module.exports = function (it, BYTES) {
  var offset = toPositiveInteger(it);
  if (offset % BYTES) throw RangeError('Wrong offset');
  return offset;
};


/***/ }),

/***/ 4064:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var toIntegerOrInfinity = __webpack_require__(400);

var RangeError = global.RangeError;

module.exports = function (it) {
  var result = toIntegerOrInfinity(it);
  if (result < 0) throw RangeError("The argument can't be less than 0");
  return result;
};


/***/ }),

/***/ 8732:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var isObject = __webpack_require__(3041);
var isSymbol = __webpack_require__(5666);
var getMethod = __webpack_require__(4462);
var ordinaryToPrimitive = __webpack_require__(9207);
var wellKnownSymbol = __webpack_require__(4259);

var TypeError = global.TypeError;
var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');

// `ToPrimitive` abstract operation
// https://tc39.es/ecma262/#sec-toprimitive
module.exports = function (input, pref) {
  if (!isObject(input) || isSymbol(input)) return input;
  var exoticToPrim = getMethod(input, TO_PRIMITIVE);
  var result;
  if (exoticToPrim) {
    if (pref === undefined) pref = 'default';
    result = call(exoticToPrim, input, pref);
    if (!isObject(result) || isSymbol(result)) return result;
    throw TypeError("Can't convert object to primitive value");
  }
  if (pref === undefined) pref = 'number';
  return ordinaryToPrimitive(input, pref);
};


/***/ }),

/***/ 1973:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var toPrimitive = __webpack_require__(8732);
var isSymbol = __webpack_require__(5666);

// `ToPropertyKey` abstract operation
// https://tc39.es/ecma262/#sec-topropertykey
module.exports = function (argument) {
  var key = toPrimitive(argument, 'string');
  return isSymbol(key) ? key : key + '';
};


/***/ }),

/***/ 8216:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var wellKnownSymbol = __webpack_require__(4259);

var TO_STRING_TAG = wellKnownSymbol('toStringTag');
var test = {};

test[TO_STRING_TAG] = 'z';

module.exports = String(test) === '[object z]';


/***/ }),

/***/ 4896:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var classof = __webpack_require__(7298);

var String = global.String;

module.exports = function (argument) {
  if (classof(argument) === 'Symbol') throw TypeError('Cannot convert a Symbol value to a string');
  return String(argument);
};


/***/ }),

/***/ 368:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);

var String = global.String;

module.exports = function (argument) {
  try {
    return String(argument);
  } catch (error) {
    return 'Object';
  }
};


/***/ }),

/***/ 6004:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var uncurryThis = __webpack_require__(3074);

var id = 0;
var postfix = Math.random();
var toString = uncurryThis(1.0.toString);

module.exports = function (key) {
  return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);
};


/***/ }),

/***/ 9525:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

/* eslint-disable es/no-symbol -- required for testing */
var NATIVE_SYMBOL = __webpack_require__(3325);

module.exports = NATIVE_SYMBOL
  && !Symbol.sham
  && typeof Symbol.iterator == 'symbol';


/***/ }),

/***/ 8814:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var DESCRIPTORS = __webpack_require__(6372);
var fails = __webpack_require__(7931);

// V8 ~ Chrome 36-
// https://bugs.chromium.org/p/v8/issues/detail?id=3334
module.exports = DESCRIPTORS && fails(function () {
  // eslint-disable-next-line es/no-object-defineproperty -- required for testing
  return Object.defineProperty(function () { /* empty */ }, 'prototype', {
    value: 42,
    writable: false
  }).prototype != 42;
});


/***/ }),

/***/ 4259:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

var global = __webpack_require__(3406);
var shared = __webpack_require__(8519);
var hasOwn = __webpack_require__(1325);
var uid = __webpack_require__(6004);
var NATIVE_SYMBOL = __webpack_require__(3325);
var USE_SYMBOL_AS_UID = __webpack_require__(9525);

var WellKnownSymbolsStore = shared('wks');
var Symbol = global.Symbol;
var symbolFor = Symbol && Symbol['for'];
var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol : Symbol && Symbol.withoutSetter || uid;

module.exports = function (name) {
  if (!hasOwn(WellKnownSymbolsStore, name) || !(NATIVE_SYMBOL || typeof WellKnownSymbolsStore[name] == 'string')) {
    var description = 'Symbol.' + name;
    if (NATIVE_SYMBOL && hasOwn(Symbol, name)) {
      WellKnownSymbolsStore[name] = Symbol[name];
    } else if (USE_SYMBOL_AS_UID && symbolFor) {
      WellKnownSymbolsStore[name] = symbolFor(description);
    } else {
      WellKnownSymbolsStore[name] = createWellKnownSymbol(description);
    }
  } return WellKnownSymbolsStore[name];
};


/***/ }),

/***/ 8932:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var uncurryThis = __webpack_require__(3074);
var requireObjectCoercible = __webpack_require__(5727);
var isCallable = __webpack_require__(2163);
var isRegExp = __webpack_require__(3948);
var toString = __webpack_require__(4896);
var getMethod = __webpack_require__(4462);
var regExpFlags = __webpack_require__(6061);
var getSubstitution = __webpack_require__(4053);
var wellKnownSymbol = __webpack_require__(4259);
var IS_PURE = __webpack_require__(2884);

var REPLACE = wellKnownSymbol('replace');
var RegExpPrototype = RegExp.prototype;
var TypeError = global.TypeError;
var getFlags = uncurryThis(regExpFlags);
var indexOf = uncurryThis(''.indexOf);
var replace = uncurryThis(''.replace);
var stringSlice = uncurryThis(''.slice);
var max = Math.max;

var stringIndexOf = function (string, searchValue, fromIndex) {
  if (fromIndex > string.length) return -1;
  if (searchValue === '') return fromIndex;
  return indexOf(string, searchValue, fromIndex);
};

// `String.prototype.replaceAll` method
// https://tc39.es/ecma262/#sec-string.prototype.replaceall
$({ target: 'String', proto: true }, {
  replaceAll: function replaceAll(searchValue, replaceValue) {
    var O = requireObjectCoercible(this);
    var IS_REG_EXP, flags, replacer, string, searchString, functionalReplace, searchLength, advanceBy, replacement;
    var position = 0;
    var endOfLastMatch = 0;
    var result = '';
    if (searchValue != null) {
      IS_REG_EXP = isRegExp(searchValue);
      if (IS_REG_EXP) {
        flags = toString(requireObjectCoercible('flags' in RegExpPrototype
          ? searchValue.flags
          : getFlags(searchValue)
        ));
        if (!~indexOf(flags, 'g')) throw TypeError('`.replaceAll` does not allow non-global regexes');
      }
      replacer = getMethod(searchValue, REPLACE);
      if (replacer) {
        return call(replacer, searchValue, O, replaceValue);
      } else if (IS_PURE && IS_REG_EXP) {
        return replace(toString(O), searchValue, replaceValue);
      }
    }
    string = toString(O);
    searchString = toString(searchValue);
    functionalReplace = isCallable(replaceValue);
    if (!functionalReplace) replaceValue = toString(replaceValue);
    searchLength = searchString.length;
    advanceBy = max(1, searchLength);
    position = stringIndexOf(string, searchString, 0);
    while (position !== -1) {
      replacement = functionalReplace
        ? toString(replaceValue(searchString, position, string))
        : getSubstitution(searchString, string, position, [], undefined, replaceValue);
      result += stringSlice(string, endOfLastMatch, position) + replacement;
      endOfLastMatch = position + searchLength;
      position = stringIndexOf(string, searchString, position + advanceBy);
    }
    if (endOfLastMatch < string.length) {
      result += stringSlice(string, endOfLastMatch);
    }
    return result;
  }
});


/***/ }),

/***/ 7168:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var ArrayBufferViewCore = __webpack_require__(9547);
var lengthOfArrayLike = __webpack_require__(5474);
var toOffset = __webpack_require__(3170);
var toIndexedObject = __webpack_require__(7410);
var fails = __webpack_require__(7931);

var RangeError = global.RangeError;
var Int8Array = global.Int8Array;
var Int8ArrayPrototype = Int8Array && Int8Array.prototype;
var $set = Int8ArrayPrototype && Int8ArrayPrototype.set;
var aTypedArray = ArrayBufferViewCore.aTypedArray;
var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod;

var WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS = !fails(function () {
  // eslint-disable-next-line es/no-typed-arrays -- required for testing
  var array = new Uint8ClampedArray(2);
  call($set, array, { length: 1, 0: 3 }, 1);
  return array[1] !== 3;
});

// https://bugs.chromium.org/p/v8/issues/detail?id=11294 and other
var TO_OBJECT_BUG = WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS && ArrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS && fails(function () {
  var array = new Int8Array(2);
  array.set(1);
  array.set('2', 1);
  return array[0] !== 0 || array[1] !== 2;
});

// `%TypedArray%.prototype.set` method
// https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
exportTypedArrayMethod('set', function set(arrayLike /* , offset */) {
  aTypedArray(this);
  var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
  var src = toIndexedObject(arrayLike);
  if (WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS) return call($set, this, src, offset);
  var length = this.length;
  var len = lengthOfArrayLike(src);
  var index = 0;
  if (len + offset > length) throw RangeError('Wrong length');
  while (index < len) this[offset + index] = src[index++];
}, !WORKS_WITH_OBJECTS_AND_GEERIC_ON_TYPED_ARRAYS || TO_OBJECT_BUG);


/***/ }),

/***/ 3929:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var deleteAll = __webpack_require__(11);

// `Map.prototype.deleteAll` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  deleteAll: deleteAll
});


/***/ }),

/***/ 7851:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.every` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  every: function every(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return !iterate(iterator, function (key, value, stop) {
      if (!boundFunction(value, key, map)) return stop();
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 3633:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var bind = __webpack_require__(8626);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.filter` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  filter: function filter(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    var newMap = new (speciesConstructor(map, getBuiltIn('Map')))();
    var setter = aCallable(newMap.set);
    iterate(iterator, function (key, value) {
      if (boundFunction(value, key, map)) call(setter, newMap, key, value);
    }, { AS_ENTRIES: true, IS_ITERATOR: true });
    return newMap;
  }
});


/***/ }),

/***/ 7515:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.findKey` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  findKey: function findKey(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return iterate(iterator, function (key, value, stop) {
      if (boundFunction(value, key, map)) return stop(key);
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).result;
  }
});


/***/ }),

/***/ 1192:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.find` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  find: function find(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return iterate(iterator, function (key, value, stop) {
      if (boundFunction(value, key, map)) return stop(value);
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).result;
  }
});


/***/ }),

/***/ 8034:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var getMapIterator = __webpack_require__(1285);
var sameValueZero = __webpack_require__(2209);
var iterate = __webpack_require__(7523);

// `Map.prototype.includes` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  includes: function includes(searchElement) {
    return iterate(getMapIterator(anObject(this)), function (key, value, stop) {
      if (sameValueZero(value, searchElement)) return stop();
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 1480:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.keyOf` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  keyOf: function keyOf(searchElement) {
    return iterate(getMapIterator(anObject(this)), function (key, value, stop) {
      if (value === searchElement) return stop(key);
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).result;
  }
});


/***/ }),

/***/ 9027:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var bind = __webpack_require__(8626);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.mapKeys` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  mapKeys: function mapKeys(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    var newMap = new (speciesConstructor(map, getBuiltIn('Map')))();
    var setter = aCallable(newMap.set);
    iterate(iterator, function (key, value) {
      call(setter, newMap, boundFunction(value, key, map), value);
    }, { AS_ENTRIES: true, IS_ITERATOR: true });
    return newMap;
  }
});


/***/ }),

/***/ 5739:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var bind = __webpack_require__(8626);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Map.prototype.mapValues` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  mapValues: function mapValues(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    var newMap = new (speciesConstructor(map, getBuiltIn('Map')))();
    var setter = aCallable(newMap.set);
    iterate(iterator, function (key, value) {
      call(setter, newMap, key, boundFunction(value, key, map));
    }, { AS_ENTRIES: true, IS_ITERATOR: true });
    return newMap;
  }
});


/***/ }),

/***/ 9283:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var iterate = __webpack_require__(7523);

// `Map.prototype.merge` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  // eslint-disable-next-line no-unused-vars -- required for `.length`
  merge: function merge(iterable /* ...iterables */) {
    var map = anObject(this);
    var setter = aCallable(map.set);
    var argumentsLength = arguments.length;
    var i = 0;
    while (i < argumentsLength) {
      iterate(arguments[i++], setter, { that: map, AS_ENTRIES: true });
    }
    return map;
  }
});


/***/ }),

/***/ 4473:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var global = __webpack_require__(3406);
var anObject = __webpack_require__(8514);
var aCallable = __webpack_require__(8146);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

var TypeError = global.TypeError;

// `Map.prototype.reduce` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  reduce: function reduce(callbackfn /* , initialValue */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var noInitial = arguments.length < 2;
    var accumulator = noInitial ? undefined : arguments[1];
    aCallable(callbackfn);
    iterate(iterator, function (key, value) {
      if (noInitial) {
        noInitial = false;
        accumulator = value;
      } else {
        accumulator = callbackfn(accumulator, value, key, map);
      }
    }, { AS_ENTRIES: true, IS_ITERATOR: true });
    if (noInitial) throw TypeError('Reduce of empty map with no initial value');
    return accumulator;
  }
});


/***/ }),

/***/ 989:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getMapIterator = __webpack_require__(1285);
var iterate = __webpack_require__(7523);

// `Set.prototype.some` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  some: function some(callbackfn /* , thisArg */) {
    var map = anObject(this);
    var iterator = getMapIterator(map);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return iterate(iterator, function (key, value, stop) {
      if (boundFunction(value, key, map)) return stop();
    }, { AS_ENTRIES: true, IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 7194:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var global = __webpack_require__(3406);
var call = __webpack_require__(8624);
var anObject = __webpack_require__(8514);
var aCallable = __webpack_require__(8146);

var TypeError = global.TypeError;

// `Set.prototype.update` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Map', proto: true, real: true, forced: true }, {
  update: function update(key, callback /* , thunk */) {
    var map = anObject(this);
    var get = aCallable(map.get);
    var has = aCallable(map.has);
    var set = aCallable(map.set);
    var length = arguments.length;
    aCallable(callback);
    var isPresentInMap = call(has, map, key);
    if (!isPresentInMap && length < 3) {
      throw TypeError('Updating absent value');
    }
    var value = isPresentInMap ? call(get, map, key) : aCallable(length > 2 ? arguments[2] : undefined)(key, map);
    call(set, map, key, callback(value, key, map));
    return map;
  }
});


/***/ }),

/***/ 6063:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var addAll = __webpack_require__(5425);

// `Set.prototype.addAll` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  addAll: addAll
});


/***/ }),

/***/ 2336:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var deleteAll = __webpack_require__(11);

// `Set.prototype.deleteAll` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  deleteAll: deleteAll
});


/***/ }),

/***/ 7226:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var iterate = __webpack_require__(7523);

// `Set.prototype.difference` method
// https://github.com/tc39/proposal-set-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  difference: function difference(iterable) {
    var set = anObject(this);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))(set);
    var remover = aCallable(newSet['delete']);
    iterate(iterable, function (value) {
      call(remover, newSet, value);
    });
    return newSet;
  }
});


/***/ }),

/***/ 641:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

// `Set.prototype.every` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  every: function every(callbackfn /* , thisArg */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return !iterate(iterator, function (value, stop) {
      if (!boundFunction(value, value, set)) return stop();
    }, { IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 5299:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var speciesConstructor = __webpack_require__(4499);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

// `Set.prototype.filter` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  filter: function filter(callbackfn /* , thisArg */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))();
    var adder = aCallable(newSet.add);
    iterate(iterator, function (value) {
      if (boundFunction(value, value, set)) call(adder, newSet, value);
    }, { IS_ITERATOR: true });
    return newSet;
  }
});


/***/ }),

/***/ 2980:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

// `Set.prototype.find` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  find: function find(callbackfn /* , thisArg */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return iterate(iterator, function (value, stop) {
      if (boundFunction(value, value, set)) return stop(value);
    }, { IS_ITERATOR: true, INTERRUPTED: true }).result;
  }
});


/***/ }),

/***/ 2801:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var iterate = __webpack_require__(7523);

// `Set.prototype.intersection` method
// https://github.com/tc39/proposal-set-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  intersection: function intersection(iterable) {
    var set = anObject(this);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))();
    var hasCheck = aCallable(set.has);
    var adder = aCallable(newSet.add);
    iterate(iterable, function (value) {
      if (call(hasCheck, set, value)) call(adder, newSet, value);
    });
    return newSet;
  }
});


/***/ }),

/***/ 7396:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var iterate = __webpack_require__(7523);

// `Set.prototype.isDisjointFrom` method
// https://tc39.github.io/proposal-set-methods/#Set.prototype.isDisjointFrom
$({ target: 'Set', proto: true, real: true, forced: true }, {
  isDisjointFrom: function isDisjointFrom(iterable) {
    var set = anObject(this);
    var hasCheck = aCallable(set.has);
    return !iterate(iterable, function (value, stop) {
      if (call(hasCheck, set, value) === true) return stop();
    }, { INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 6600:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var isCallable = __webpack_require__(2163);
var anObject = __webpack_require__(8514);
var getIterator = __webpack_require__(1570);
var iterate = __webpack_require__(7523);

// `Set.prototype.isSubsetOf` method
// https://tc39.github.io/proposal-set-methods/#Set.prototype.isSubsetOf
$({ target: 'Set', proto: true, real: true, forced: true }, {
  isSubsetOf: function isSubsetOf(iterable) {
    var iterator = getIterator(this);
    var otherSet = anObject(iterable);
    var hasCheck = otherSet.has;
    if (!isCallable(hasCheck)) {
      otherSet = new (getBuiltIn('Set'))(iterable);
      hasCheck = aCallable(otherSet.has);
    }
    return !iterate(iterator, function (value, stop) {
      if (call(hasCheck, otherSet, value) === false) return stop();
    }, { IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 9503:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var iterate = __webpack_require__(7523);

// `Set.prototype.isSupersetOf` method
// https://tc39.github.io/proposal-set-methods/#Set.prototype.isSupersetOf
$({ target: 'Set', proto: true, real: true, forced: true }, {
  isSupersetOf: function isSupersetOf(iterable) {
    var set = anObject(this);
    var hasCheck = aCallable(set.has);
    return !iterate(iterable, function (value, stop) {
      if (call(hasCheck, set, value) === false) return stop();
    }, { INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 6119:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var uncurryThis = __webpack_require__(3074);
var anObject = __webpack_require__(8514);
var toString = __webpack_require__(4896);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

var arrayJoin = uncurryThis([].join);
var push = [].push;

// `Set.prototype.join` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  join: function join(separator) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var sep = separator === undefined ? ',' : toString(separator);
    var result = [];
    iterate(iterator, push, { that: result, IS_ITERATOR: true });
    return arrayJoin(result, sep);
  }
});


/***/ }),

/***/ 608:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var bind = __webpack_require__(8626);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

// `Set.prototype.map` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  map: function map(callbackfn /* , thisArg */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))();
    var adder = aCallable(newSet.add);
    iterate(iterator, function (value) {
      call(adder, newSet, boundFunction(value, value, set));
    }, { IS_ITERATOR: true });
    return newSet;
  }
});


/***/ }),

/***/ 4061:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var global = __webpack_require__(3406);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

var TypeError = global.TypeError;

// `Set.prototype.reduce` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  reduce: function reduce(callbackfn /* , initialValue */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var noInitial = arguments.length < 2;
    var accumulator = noInitial ? undefined : arguments[1];
    aCallable(callbackfn);
    iterate(iterator, function (value) {
      if (noInitial) {
        noInitial = false;
        accumulator = value;
      } else {
        accumulator = callbackfn(accumulator, value, value, set);
      }
    }, { IS_ITERATOR: true });
    if (noInitial) throw TypeError('Reduce of empty set with no initial value');
    return accumulator;
  }
});


/***/ }),

/***/ 2229:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var anObject = __webpack_require__(8514);
var bind = __webpack_require__(8626);
var getSetIterator = __webpack_require__(7762);
var iterate = __webpack_require__(7523);

// `Set.prototype.some` method
// https://github.com/tc39/proposal-collection-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  some: function some(callbackfn /* , thisArg */) {
    var set = anObject(this);
    var iterator = getSetIterator(set);
    var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    return iterate(iterator, function (value, stop) {
      if (boundFunction(value, value, set)) return stop();
    }, { IS_ITERATOR: true, INTERRUPTED: true }).stopped;
  }
});


/***/ }),

/***/ 9055:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var call = __webpack_require__(8624);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var iterate = __webpack_require__(7523);

// `Set.prototype.symmetricDifference` method
// https://github.com/tc39/proposal-set-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  symmetricDifference: function symmetricDifference(iterable) {
    var set = anObject(this);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))(set);
    var remover = aCallable(newSet['delete']);
    var adder = aCallable(newSet.add);
    iterate(iterable, function (value) {
      call(remover, newSet, value) || call(adder, newSet, value);
    });
    return newSet;
  }
});


/***/ }),

/***/ 3286:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

"use strict";

var $ = __webpack_require__(5942);
var getBuiltIn = __webpack_require__(9997);
var aCallable = __webpack_require__(8146);
var anObject = __webpack_require__(8514);
var speciesConstructor = __webpack_require__(4499);
var iterate = __webpack_require__(7523);

// `Set.prototype.union` method
// https://github.com/tc39/proposal-set-methods
$({ target: 'Set', proto: true, real: true, forced: true }, {
  union: function union(iterable) {
    var set = anObject(this);
    var newSet = new (speciesConstructor(set, getBuiltIn('Set')))(set);
    iterate(iterable, aCallable(newSet.add), { that: newSet });
    return newSet;
  }
});


/***/ }),

/***/ 1625:
/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {

// TODO: Remove from `core-js@4`
__webpack_require__(8932);


/***/ }),

/***/ 8118:
/***/ (function(module, exports, __webpack_require__) {

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory();
	}
	else {}
}(this, function () {

	/*globals window, global, require*/

	/**
	 * CryptoJS core components.
	 */
	var CryptoJS = CryptoJS || (function (Math, undefined) {

	    var crypto;

	    // Native crypto from window (Browser)
	    if (typeof window !== 'undefined' && window.crypto) {
	        crypto = window.crypto;
	    }

	    // Native crypto in web worker (Browser)
	    if (typeof self !== 'undefined' && self.crypto) {
	        crypto = self.crypto;
	    }

	    // Native crypto from worker
	    if (typeof globalThis !== 'undefined' && globalThis.crypto) {
	        crypto = globalThis.crypto;
	    }

	    // Native (experimental IE 11) crypto from window (Browser)
	    if (!crypto && typeof window !== 'undefined' && window.msCrypto) {
	        crypto = window.msCrypto;
	    }

	    // Native crypto from global (NodeJS)
	    if (!crypto && typeof __webpack_require__.g !== 'undefined' && __webpack_require__.g.crypto) {
	        crypto = __webpack_require__.g.crypto;
	    }

	    // Native crypto import via require (NodeJS)
	    if (!crypto && "function" === 'function') {
	        try {
	            crypto = __webpack_require__(2480);
	        } catch (err) {}
	    }

	    /*
	     * Cryptographically secure pseudorandom number generator
	     *
	     * As Math.random() is cryptographically not safe to use
	     */
	    var cryptoSecureRandomInt = function () {
	        if (crypto) {
	            // Use getRandomValues method (Browser)
	            if (typeof crypto.getRandomValues === 'function') {
	                try {
	                    return crypto.getRandomValues(new Uint32Array(1))[0];
	                } catch (err) {}
	            }

	            // Use randomBytes method (NodeJS)
	            if (typeof crypto.randomBytes === 'function') {
	                try {
	                    return crypto.randomBytes(4).readInt32LE();
	                } catch (err) {}
	            }
	        }

	        throw new Error('Native crypto module could not be used to get secure random number.');
	    };

	    /*
	     * Local polyfill of Object.create

	     */
	    var create = Object.create || (function () {
	        function F() {}

	        return function (obj) {
	            var subtype;

	            F.prototype = obj;

	            subtype = new F();

	            F.prototype = null;

	            return subtype;
	        };
	    }());

	    /**
	     * CryptoJS namespace.
	     */
	    var C = {};

	    /**
	     * Library namespace.
	     */
	    var C_lib = C.lib = {};

	    /**
	     * Base object for prototypal inheritance.
	     */
	    var Base = C_lib.Base = (function () {


	        return {
	            /**
	             * Creates a new object that inherits from this object.
	             *
	             * @param {Object} overrides Properties to copy into the new object.
	             *
	             * @return {Object} The new object.
	             *
	             * @static
	             *
	             * @example
	             *
	             *     var MyType = CryptoJS.lib.Base.extend({
	             *         field: 'value',
	             *
	             *         method: function () {
	             *         }
	             *     });
	             */
	            extend: function (overrides) {
	                // Spawn
	                var subtype = create(this);

	                // Augment
	                if (overrides) {
	                    subtype.mixIn(overrides);
	                }

	                // Create default initializer
	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
	                    subtype.init = function () {
	                        subtype.$super.init.apply(this, arguments);
	                    };
	                }

	                // Initializer's prototype is the subtype object
	                subtype.init.prototype = subtype;

	                // Reference supertype
	                subtype.$super = this;

	                return subtype;
	            },

	            /**
	             * Extends this object and runs the init method.
	             * Arguments to create() will be passed to init().
	             *
	             * @return {Object} The new object.
	             *
	             * @static
	             *
	             * @example
	             *
	             *     var instance = MyType.create();
	             */
	            create: function () {
	                var instance = this.extend();
	                instance.init.apply(instance, arguments);

	                return instance;
	            },

	            /**
	             * Initializes a newly created object.
	             * Override this method to add some logic when your objects are created.
	             *
	             * @example
	             *
	             *     var MyType = CryptoJS.lib.Base.extend({
	             *         init: function () {
	             *             // ...
	             *         }
	             *     });
	             */
	            init: function () {
	            },

	            /**
	             * Copies properties into this object.
	             *
	             * @param {Object} properties The properties to mix in.
	             *
	             * @example
	             *
	             *     MyType.mixIn({
	             *         field: 'value'
	             *     });
	             */
	            mixIn: function (properties) {
	                for (var propertyName in properties) {
	                    if (properties.hasOwnProperty(propertyName)) {
	                        this[propertyName] = properties[propertyName];
	                    }
	                }

	                // IE won't copy toString using the loop above
	                if (properties.hasOwnProperty('toString')) {
	                    this.toString = properties.toString;
	                }
	            },

	            /**
	             * Creates a copy of this object.
	             *
	             * @return {Object} The clone.
	             *
	             * @example
	             *
	             *     var clone = instance.clone();
	             */
	            clone: function () {
	                return this.init.prototype.extend(this);
	            }
	        };
	    }());

	    /**
	     * An array of 32-bit words.
	     *
	     * @property {Array} words The array of 32-bit words.
	     * @property {number} sigBytes The number of significant bytes in this word array.
	     */
	    var WordArray = C_lib.WordArray = Base.extend({
	        /**
	         * Initializes a newly created word array.
	         *
	         * @param {Array} words (Optional) An array of 32-bit words.
	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.lib.WordArray.create();
	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
	         */
	        init: function (words, sigBytes) {
	            words = this.words = words || [];

	            if (sigBytes != undefined) {
	                this.sigBytes = sigBytes;
	            } else {
	                this.sigBytes = words.length * 4;
	            }
	        },

	        /**
	         * Converts this word array to a string.
	         *
	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
	         *
	         * @return {string} The stringified word array.
	         *
	         * @example
	         *
	         *     var string = wordArray + '';
	         *     var string = wordArray.toString();
	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
	         */
	        toString: function (encoder) {
	            return (encoder || Hex).stringify(this);
	        },

	        /**
	         * Concatenates a word array to this word array.
	         *
	         * @param {WordArray} wordArray The word array to append.
	         *
	         * @return {WordArray} This word array.
	         *
	         * @example
	         *
	         *     wordArray1.concat(wordArray2);
	         */
	        concat: function (wordArray) {
	            // Shortcuts
	            var thisWords = this.words;
	            var thatWords = wordArray.words;
	            var thisSigBytes = this.sigBytes;
	            var thatSigBytes = wordArray.sigBytes;

	            // Clamp excess bits
	            this.clamp();

	            // Concat
	            if (thisSigBytes % 4) {
	                // Copy one byte at a time
	                for (var i = 0; i < thatSigBytes; i++) {
	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
	                }
	            } else {
	                // Copy one word at a time
	                for (var j = 0; j < thatSigBytes; j += 4) {
	                    thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2];
	                }
	            }
	            this.sigBytes += thatSigBytes;

	            // Chainable
	            return this;
	        },

	        /**
	         * Removes insignificant bits.
	         *
	         * @example
	         *
	         *     wordArray.clamp();
	         */
	        clamp: function () {
	            // Shortcuts
	            var words = this.words;
	            var sigBytes = this.sigBytes;

	            // Clamp
	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
	            words.length = Math.ceil(sigBytes / 4);
	        },

	        /**
	         * Creates a copy of this word array.
	         *
	         * @return {WordArray} The clone.
	         *
	         * @example
	         *
	         *     var clone = wordArray.clone();
	         */
	        clone: function () {
	            var clone = Base.clone.call(this);
	            clone.words = this.words.slice(0);

	            return clone;
	        },

	        /**
	         * Creates a word array filled with random bytes.
	         *
	         * @param {number} nBytes The number of random bytes to generate.
	         *
	         * @return {WordArray} The random word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
	         */
	        random: function (nBytes) {
	            var words = [];

	            for (var i = 0; i < nBytes; i += 4) {
	                words.push(cryptoSecureRandomInt());
	            }

	            return new WordArray.init(words, nBytes);
	        }
	    });

	    /**
	     * Encoder namespace.
	     */
	    var C_enc = C.enc = {};

	    /**
	     * Hex encoding strategy.
	     */
	    var Hex = C_enc.Hex = {
	        /**
	         * Converts a word array to a hex string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The hex string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            // Shortcuts
	            var words = wordArray.words;
	            var sigBytes = wordArray.sigBytes;

	            // Convert
	            var hexChars = [];
	            for (var i = 0; i < sigBytes; i++) {
	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                hexChars.push((bite >>> 4).toString(16));
	                hexChars.push((bite & 0x0f).toString(16));
	            }

	            return hexChars.join('');
	        },

	        /**
	         * Converts a hex string to a word array.
	         *
	         * @param {string} hexStr The hex string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
	         */
	        parse: function (hexStr) {
	            // Shortcut
	            var hexStrLength = hexStr.length;

	            // Convert
	            var words = [];
	            for (var i = 0; i < hexStrLength; i += 2) {
	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
	            }

	            return new WordArray.init(words, hexStrLength / 2);
	        }
	    };

	    /**
	     * Latin1 encoding strategy.
	     */
	    var Latin1 = C_enc.Latin1 = {
	        /**
	         * Converts a word array to a Latin1 string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The Latin1 string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            // Shortcuts
	            var words = wordArray.words;
	            var sigBytes = wordArray.sigBytes;

	            // Convert
	            var latin1Chars = [];
	            for (var i = 0; i < sigBytes; i++) {
	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                latin1Chars.push(String.fromCharCode(bite));
	            }

	            return latin1Chars.join('');
	        },

	        /**
	         * Converts a Latin1 string to a word array.
	         *
	         * @param {string} latin1Str The Latin1 string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
	         */
	        parse: function (latin1Str) {
	            // Shortcut
	            var latin1StrLength = latin1Str.length;

	            // Convert
	            var words = [];
	            for (var i = 0; i < latin1StrLength; i++) {
	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
	            }

	            return new WordArray.init(words, latin1StrLength);
	        }
	    };

	    /**
	     * UTF-8 encoding strategy.
	     */
	    var Utf8 = C_enc.Utf8 = {
	        /**
	         * Converts a word array to a UTF-8 string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The UTF-8 string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            try {
	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
	            } catch (e) {
	                throw new Error('Malformed UTF-8 data');
	            }
	        },

	        /**
	         * Converts a UTF-8 string to a word array.
	         *
	         * @param {string} utf8Str The UTF-8 string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
	         */
	        parse: function (utf8Str) {
	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
	        }
	    };

	    /**
	     * Abstract buffered block algorithm template.
	     *
	     * The property blockSize must be implemented in a concrete subtype.
	     *
	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
	     */
	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
	        /**
	         * Resets this block algorithm's data buffer to its initial state.
	         *
	         * @example
	         *
	         *     bufferedBlockAlgorithm.reset();
	         */
	        reset: function () {
	            // Initial values
	            this._data = new WordArray.init();
	            this._nDataBytes = 0;
	        },

	        /**
	         * Adds new data to this block algorithm's buffer.
	         *
	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
	         *
	         * @example
	         *
	         *     bufferedBlockAlgorithm._append('data');
	         *     bufferedBlockAlgorithm._append(wordArray);
	         */
	        _append: function (data) {
	            // Convert string to WordArray, else assume WordArray already
	            if (typeof data == 'string') {
	                data = Utf8.parse(data);
	            }

	            // Append
	            this._data.concat(data);
	            this._nDataBytes += data.sigBytes;
	        },

	        /**
	         * Processes available data blocks.
	         *
	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
	         *
	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
	         *
	         * @return {WordArray} The processed data.
	         *
	         * @example
	         *
	         *     var processedData = bufferedBlockAlgorithm._process();
	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
	         */
	        _process: function (doFlush) {
	            var processedWords;

	            // Shortcuts
	            var data = this._data;
	            var dataWords = data.words;
	            var dataSigBytes = data.sigBytes;
	            var blockSize = this.blockSize;
	            var blockSizeBytes = blockSize * 4;

	            // Count blocks ready
	            var nBlocksReady = dataSigBytes / blockSizeBytes;
	            if (doFlush) {
	                // Round up to include partial blocks
	                nBlocksReady = Math.ceil(nBlocksReady);
	            } else {
	                // Round down to include only full blocks,
	                // less the number of blocks that must remain in the buffer
	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
	            }

	            // Count words ready
	            var nWordsReady = nBlocksReady * blockSize;

	            // Count bytes ready
	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);

	            // Process blocks
	            if (nWordsReady) {
	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
	                    // Perform concrete-algorithm logic
	                    this._doProcessBlock(dataWords, offset);
	                }

	                // Remove processed words
	                processedWords = dataWords.splice(0, nWordsReady);
	                data.sigBytes -= nBytesReady;
	            }

	            // Return processed words
	            return new WordArray.init(processedWords, nBytesReady);
	        },

	        /**
	         * Creates a copy of this object.
	         *
	         * @return {Object} The clone.
	         *
	         * @example
	         *
	         *     var clone = bufferedBlockAlgorithm.clone();
	         */
	        clone: function () {
	            var clone = Base.clone.call(this);
	            clone._data = this._data.clone();

	            return clone;
	        },

	        _minBufferSize: 0
	    });

	    /**
	     * Abstract hasher template.
	     *
	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
	     */
	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
	        /**
	         * Configuration options.
	         */
	        cfg: Base.extend(),

	        /**
	         * Initializes a newly created hasher.
	         *
	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
	         *
	         * @example
	         *
	         *     var hasher = CryptoJS.algo.SHA256.create();
	         */
	        init: function (cfg) {
	            // Apply config defaults
	            this.cfg = this.cfg.extend(cfg);

	            // Set initial values
	            this.reset();
	        },

	        /**
	         * Resets this hasher to its initial state.
	         *
	         * @example
	         *
	         *     hasher.reset();
	         */
	        reset: function () {
	            // Reset data buffer
	            BufferedBlockAlgorithm.reset.call(this);

	            // Perform concrete-hasher logic
	            this._doReset();
	        },

	        /**
	         * Updates this hasher with a message.
	         *
	         * @param {WordArray|string} messageUpdate The message to append.
	         *
	         * @return {Hasher} This hasher.
	         *
	         * @example
	         *
	         *     hasher.update('message');
	         *     hasher.update(wordArray);
	         */
	        update: function (messageUpdate) {
	            // Append
	            this._append(messageUpdate);

	            // Update the hash
	            this._process();

	            // Chainable
	            return this;
	        },

	        /**
	         * Finalizes the hash computation.
	         * Note that the finalize operation is effectively a destructive, read-once operation.
	         *
	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
	         *
	         * @return {WordArray} The hash.
	         *
	         * @example
	         *
	         *     var hash = hasher.finalize();
	         *     var hash = hasher.finalize('message');
	         *     var hash = hasher.finalize(wordArray);
	         */
	        finalize: function (messageUpdate) {
	            // Final message update
	            if (messageUpdate) {
	                this._append(messageUpdate);
	            }

	            // Perform concrete-hasher logic
	            var hash = this._doFinalize();

	            return hash;
	        },

	        blockSize: 512/32,

	        /**
	         * Creates a shortcut function to a hasher's object interface.
	         *
	         * @param {Hasher} hasher The hasher to create a helper for.
	         *
	         * @return {Function} The shortcut function.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
	         */
	        _createHelper: function (hasher) {
	            return function (message, cfg) {
	                return new hasher.init(cfg).finalize(message);
	            };
	        },

	        /**
	         * Creates a shortcut function to the HMAC's object interface.
	         *
	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
	         *
	         * @return {Function} The shortcut function.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
	         */
	        _createHmacHelper: function (hasher) {
	            return function (message, key) {
	                return new C_algo.HMAC.init(hasher, key).finalize(message);
	            };
	        }
	    });

	    /**
	     * Algorithm namespace.
	     */
	    var C_algo = C.algo = {};

	    return C;
	}(Math));


	return CryptoJS;

}));

/***/ }),

/***/ 6172:
/***/ (function(module, exports, __webpack_require__) {

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory(__webpack_require__(8118));
	}
	else {}
}(this, function (CryptoJS) {

	(function (Math) {
	    // Shortcuts
	    var C = CryptoJS;
	    var C_lib = C.lib;
	    var WordArray = C_lib.WordArray;
	    var Hasher = C_lib.Hasher;
	    var C_algo = C.algo;

	    // Constants table
	    var T = [];

	    // Compute constants
	    (function () {
	        for (var i = 0; i < 64; i++) {
	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
	        }
	    }());

	    /**
	     * MD5 hash algorithm.
	     */
	    var MD5 = C_algo.MD5 = Hasher.extend({
	        _doReset: function () {
	            this._hash = new WordArray.init([
	                0x67452301, 0xefcdab89,
	                0x98badcfe, 0x10325476
	            ]);
	        },

	        _doProcessBlock: function (M, offset) {
	            // Swap endian
	            for (var i = 0; i < 16; i++) {
	                // Shortcuts
	                var offset_i = offset + i;
	                var M_offset_i = M[offset_i];

	                M[offset_i] = (
	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
	                );
	            }

	            // Shortcuts
	            var H = this._hash.words;

	            var M_offset_0  = M[offset + 0];
	            var M_offset_1  = M[offset + 1];
	            var M_offset_2  = M[offset + 2];
	            var M_offset_3  = M[offset + 3];
	            var M_offset_4  = M[offset + 4];
	            var M_offset_5  = M[offset + 5];
	            var M_offset_6  = M[offset + 6];
	            var M_offset_7  = M[offset + 7];
	            var M_offset_8  = M[offset + 8];
	            var M_offset_9  = M[offset + 9];
	            var M_offset_10 = M[offset + 10];
	            var M_offset_11 = M[offset + 11];
	            var M_offset_12 = M[offset + 12];
	            var M_offset_13 = M[offset + 13];
	            var M_offset_14 = M[offset + 14];
	            var M_offset_15 = M[offset + 15];

	            // Working varialbes
	            var a = H[0];
	            var b = H[1];
	            var c = H[2];
	            var d = H[3];

	            // Computation
	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);

	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);

	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);

	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
	            b = II(b, c, d, a, M_offset_9,  21, T[63]);

	            // Intermediate hash value
	            H[0] = (H[0] + a) | 0;
	            H[1] = (H[1] + b) | 0;
	            H[2] = (H[2] + c) | 0;
	            H[3] = (H[3] + d) | 0;
	        },

	        _doFinalize: function () {
	            // Shortcuts
	            var data = this._data;
	            var dataWords = data.words;

	            var nBitsTotal = this._nDataBytes * 8;
	            var nBitsLeft = data.sigBytes * 8;

	            // Add padding
	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);

	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
	            var nBitsTotalL = nBitsTotal;
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
	            );
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
	            );

	            data.sigBytes = (dataWords.length + 1) * 4;

	            // Hash final blocks
	            this._process();

	            // Shortcuts
	            var hash = this._hash;
	            var H = hash.words;

	            // Swap endian
	            for (var i = 0; i < 4; i++) {
	                // Shortcut
	                var H_i = H[i];

	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
	            }

	            // Return final computed hash
	            return hash;
	        },

	        clone: function () {
	            var clone = Hasher.clone.call(this);
	            clone._hash = this._hash.clone();

	            return clone;
	        }
	    });

	    function FF(a, b, c, d, x, s, t) {
	        var n = a + ((b & c) | (~b & d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function GG(a, b, c, d, x, s, t) {
	        var n = a + ((b & d) | (c & ~d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function HH(a, b, c, d, x, s, t) {
	        var n = a + (b ^ c ^ d) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function II(a, b, c, d, x, s, t) {
	        var n = a + (c ^ (b | ~d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    /**
	     * Shortcut function to the hasher's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     *
	     * @return {WordArray} The hash.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hash = CryptoJS.MD5('message');
	     *     var hash = CryptoJS.MD5(wordArray);
	     */
	    C.MD5 = Hasher._createHelper(MD5);

	    /**
	     * Shortcut function to the HMAC's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     * @param {WordArray|string} key The secret key.
	     *
	     * @return {WordArray} The HMAC.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hmac = CryptoJS.HmacMD5(message, key);
	     */
	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
	}(Math));


	return CryptoJS.MD5;

}));

/***/ }),

/***/ 8975:
/***/ (function(module, exports, __webpack_require__) {

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory(__webpack_require__(8118));
	}
	else {}
}(this, function (CryptoJS) {

	(function (Math) {
	    // Shortcuts
	    var C = CryptoJS;
	    var C_lib = C.lib;
	    var WordArray = C_lib.WordArray;
	    var Hasher = C_lib.Hasher;
	    var C_algo = C.algo;

	    // Initialization and round constants tables
	    var H = [];
	    var K = [];

	    // Compute constants
	    (function () {
	        function isPrime(n) {
	            var sqrtN = Math.sqrt(n);
	            for (var factor = 2; factor <= sqrtN; factor++) {
	                if (!(n % factor)) {
	                    return false;
	                }
	            }

	            return true;
	        }

	        function getFractionalBits(n) {
	            return ((n - (n | 0)) * 0x100000000) | 0;
	        }

	        var n = 2;
	        var nPrime = 0;
	        while (nPrime < 64) {
	            if (isPrime(n)) {
	                if (nPrime < 8) {
	                    H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));
	                }
	                K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));

	                nPrime++;
	            }

	            n++;
	        }
	    }());

	    // Reusable object
	    var W = [];

	    /**
	     * SHA-256 hash algorithm.
	     */
	    var SHA256 = C_algo.SHA256 = Hasher.extend({
	        _doReset: function () {
	            this._hash = new WordArray.init(H.slice(0));
	        },

	        _doProcessBlock: function (M, offset) {
	            // Shortcut
	            var H = this._hash.words;

	            // Working variables
	            var a = H[0];
	            var b = H[1];
	            var c = H[2];
	            var d = H[3];
	            var e = H[4];
	            var f = H[5];
	            var g = H[6];
	            var h = H[7];

	            // Computation
	            for (var i = 0; i < 64; i++) {
	                if (i < 16) {
	                    W[i] = M[offset + i] | 0;
	                } else {
	                    var gamma0x = W[i - 15];
	                    var gamma0  = ((gamma0x << 25) | (gamma0x >>> 7))  ^
	                                  ((gamma0x << 14) | (gamma0x >>> 18)) ^
	                                   (gamma0x >>> 3);

	                    var gamma1x = W[i - 2];
	                    var gamma1  = ((gamma1x << 15) | (gamma1x >>> 17)) ^
	                                  ((gamma1x << 13) | (gamma1x >>> 19)) ^
	                                   (gamma1x >>> 10);

	                    W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];
	                }

	                var ch  = (e & f) ^ (~e & g);
	                var maj = (a & b) ^ (a & c) ^ (b & c);

	                var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));
	                var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7)  | (e >>> 25));

	                var t1 = h + sigma1 + ch + K[i] + W[i];
	                var t2 = sigma0 + maj;

	                h = g;
	                g = f;
	                f = e;
	                e = (d + t1) | 0;
	                d = c;
	                c = b;
	                b = a;
	                a = (t1 + t2) | 0;
	            }

	            // Intermediate hash value
	            H[0] = (H[0] + a) | 0;
	            H[1] = (H[1] + b) | 0;
	            H[2] = (H[2] + c) | 0;
	            H[3] = (H[3] + d) | 0;
	            H[4] = (H[4] + e) | 0;
	            H[5] = (H[5] + f) | 0;
	            H[6] = (H[6] + g) | 0;
	            H[7] = (H[7] + h) | 0;
	        },

	        _doFinalize: function () {
	            // Shortcuts
	            var data = this._data;
	            var dataWords = data.words;

	            var nBitsTotal = this._nDataBytes * 8;
	            var nBitsLeft = data.sigBytes * 8;

	            // Add padding
	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;
	            data.sigBytes = dataWords.length * 4;

	            // Hash final blocks
	            this._process();

	            // Return final computed hash
	            return this._hash;
	        },

	        clone: function () {
	            var clone = Hasher.clone.call(this);
	            clone._hash = this._hash.clone();

	            return clone;
	        }
	    });

	    /**
	     * Shortcut function to the hasher's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     *
	     * @return {WordArray} The hash.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hash = CryptoJS.SHA256('message');
	     *     var hash = CryptoJS.SHA256(wordArray);
	     */
	    C.SHA256 = Hasher._createHelper(SHA256);

	    /**
	     * Shortcut function to the HMAC's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     * @param {WordArray|string} key The secret key.
	     *
	     * @return {WordArray} The HMAC.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hmac = CryptoJS.HmacSHA256(message, key);
	     */
	    C.HmacSHA256 = Hasher._createHmacHelper(SHA256);
	}(Math));


	return CryptoJS.SHA256;

}));

/***/ }),

/***/ 7553:
/***/ (function(__unused_webpack_module, exports) {

!function(g,c){ true?c(exports):0}(this,function(g){const c=Symbol("newer"),e=Symbol("older");class n{constructor(a,b){typeof a!=="number"&&(b=a,a=0),this.size=0,this.limit=a,this.oldest=this.newest=void 0,this._keymap=new Map(),b&&(this.assign(b),a<1&&(this.limit=this.size))}_markEntryAsUsed(a){if(a===this.newest)return;a[c]&&(a===this.oldest&&(this.oldest=a[c]),a[c][e]=a[e]),a[e]&&(a[e][c]=a[c]),a[c]=void 0,a[e]=this.newest,this.newest&&(this.newest[c]=a),this.newest=a}assign(a){let b,d=this.limit||Number.MAX_VALUE;this._keymap.clear();let m=a[Symbol.iterator]();for(let h=m.next();!h.done;h=m.next()){let f=new l(h.value[0],h.value[1]);this._keymap.set(f.key,f),b?(b[c]=f,f[e]=b):this.oldest=f,b=f;if(d--==0)throw new Error("overflow")}this.newest=b,this.size=this._keymap.size}get(a){var b=this._keymap.get(a);return b?(this._markEntryAsUsed(b),b.value):void 0}set(a,b){var d=this._keymap.get(a);return d?(d.value=b,this._markEntryAsUsed(d),this):(this._keymap.set(a,d=new l(a,b)),this.newest?(this.newest[c]=d,d[e]=this.newest):this.oldest=d,this.newest=d,++this.size,this.size>this.limit&&this.shift(),this)}shift(){var a=this.oldest;if(a)return this.oldest[c]?(this.oldest=this.oldest[c],this.oldest[e]=void 0):(this.oldest=void 0,this.newest=void 0),a[c]=a[e]=void 0,this._keymap.delete(a.key),--this.size,[a.key,a.value]}find(a){let b=this._keymap.get(a);return b?b.value:void 0}has(a){return this._keymap.has(a)}delete(a){var b=this._keymap.get(a);return b?(this._keymap.delete(b.key),b[c]&&b[e]?(b[e][c]=b[c],b[c][e]=b[e]):b[c]?(b[c][e]=void 0,this.oldest=b[c]):b[e]?(b[e][c]=void 0,this.newest=b[e]):this.oldest=this.newest=void 0,this.size--,b.value):void 0}clear(){this.oldest=this.newest=void 0,this.size=0,this._keymap.clear()}keys(){return new j(this.oldest)}values(){return new k(this.oldest)}entries(){return this}[Symbol.iterator](){return new i(this.oldest)}forEach(a,b){typeof b!=="object"&&(b=this);let d=this.oldest;for(;d;)a.call(b,d.value,d.key,this),d=d[c]}toJSON(){for(var a=new Array(this.size),b=0,d=this.oldest;d;)a[b++]={key:d.key,value:d.value},d=d[c];return a}toString(){for(var a="",b=this.oldest;b;)a+=String(b.key)+":"+b.value,b=b[c],b&&(a+=" < ");return a}}g.LRUMap=n;function l(a,b){this.key=a,this.value=b,this[c]=void 0,this[e]=void 0}function i(a){this.entry=a}i.prototype[Symbol.iterator]=function(){return this},i.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:[a.key,a.value]}):{done:!0,value:void 0}};function j(a){this.entry=a}j.prototype[Symbol.iterator]=function(){return this},j.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:a.key}):{done:!0,value:void 0}};function k(a){this.entry=a}k.prototype[Symbol.iterator]=function(){return this},k.prototype.next=function(){let a=this.entry;return a?(this.entry=a[c],{done:!1,value:a.value}):{done:!0,value:void 0}}});


/***/ }),

/***/ 9182:
/***/ ((module) => {

"use strict";
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.



// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
function hasOwnProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

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

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

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

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

  var len = qs.length;
  // maxKeys <= 0 means that we should not limit keys count
  if (maxKeys > 0 && len > maxKeys) {
    len = maxKeys;
  }

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

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

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

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

  return obj;
};


/***/ }),

/***/ 9265:
/***/ ((module) => {

"use strict";
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.



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

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

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

    default:
      return '';
  }
};

module.exports = function(obj, sep, eq, name) {
  sep = sep || '&';
  eq = eq || '=';
  if (obj === null) {
    obj = undefined;
  }

  if (typeof obj === 'object') {
    return Object.keys(obj).map(function(k) {
      var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
      if (Array.isArray(obj[k])) {
        return obj[k].map(function(v) {
          return ks + encodeURIComponent(stringifyPrimitive(v));
        }).join(sep);
      } else {
        return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
      }
    }).join(sep);

  }

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


/***/ }),

/***/ 8528:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {

"use strict";


exports.decode = exports.parse = __webpack_require__(9182);
exports.encode = exports.stringify = __webpack_require__(9265);


/***/ }),

/***/ 9473:
/***/ (function(module, exports, __webpack_require__) {

/* module decorator */ module = __webpack_require__.nmd(module);
var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.3.2 by @mathias */
;(function(root) {

	/** Detect free variables */
	var freeExports =  true && exports &&
		!exports.nodeType && exports;
	var freeModule =  true && module &&
		!module.nodeType && module;
	var freeGlobal = typeof __webpack_require__.g == 'object' && __webpack_require__.g;
	if (
		freeGlobal.global === freeGlobal ||
		freeGlobal.window === freeGlobal ||
		freeGlobal.self === freeGlobal
	) {
		root = freeGlobal;
	}

	/**
	 * The `punycode` object.
	 * @name punycode
	 * @type Object
	 */
	var punycode,

	/** Highest positive signed 32-bit float value */
	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1

	/** Bootstring parameters */
	base = 36,
	tMin = 1,
	tMax = 26,
	skew = 38,
	damp = 700,
	initialBias = 72,
	initialN = 128, // 0x80
	delimiter = '-', // '\x2D'

	/** Regular expressions */
	regexPunycode = /^xn--/,
	regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
	regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators

	/** Error messages */
	errors = {
		'overflow': 'Overflow: input needs wider integers to process',
		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
		'invalid-input': 'Invalid input'
	},

	/** Convenience shortcuts */
	baseMinusTMin = base - tMin,
	floor = Math.floor,
	stringFromCharCode = String.fromCharCode,

	/** Temporary variable */
	key;

	/*--------------------------------------------------------------------------*/

	/**
	 * A generic error utility function.
	 * @private
	 * @param {String} type The error type.
	 * @returns {Error} Throws a `RangeError` with the applicable error message.
	 */
	function error(type) {
		throw RangeError(errors[type]);
	}

	/**
	 * A generic `Array#map` utility function.
	 * @private
	 * @param {Array} array The array to iterate over.
	 * @param {Function} callback The function that gets called for every array
	 * item.
	 * @returns {Array} A new array of values returned by the callback function.
	 */
	function map(array, fn) {
		var length = array.length;
		var result = [];
		while (length--) {
			result[length] = fn(array[length]);
		}
		return result;
	}

	/**
	 * A simple `Array#map`-like wrapper to work with domain name strings or email
	 * addresses.
	 * @private
	 * @param {String} domain The domain name or email address.
	 * @param {Function} callback The function that gets called for every
	 * character.
	 * @returns {Array} A new string of characters returned by the callback
	 * function.
	 */
	function mapDomain(string, fn) {
		var parts = string.split('@');
		var result = '';
		if (parts.length > 1) {
			// In email addresses, only the domain name should be punycoded. Leave
			// the local part (i.e. everything up to `@`) intact.
			result = parts[0] + '@';
			string = parts[1];
		}
		// Avoid `split(regex)` for IE8 compatibility. See #17.
		string = string.replace(regexSeparators, '\x2E');
		var labels = string.split('.');
		var encoded = map(labels, fn).join('.');
		return result + encoded;
	}

	/**
	 * Creates an array containing the numeric code points of each Unicode
	 * character in the string. While JavaScript uses UCS-2 internally,
	 * this function will convert a pair of surrogate halves (each of which
	 * UCS-2 exposes as separate characters) into a single code point,
	 * matching UTF-16.
	 * @see `punycode.ucs2.encode`
	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
	 * @memberOf punycode.ucs2
	 * @name decode
	 * @param {String} string The Unicode input string (UCS-2).
	 * @returns {Array} The new array of code points.
	 */
	function ucs2decode(string) {
		var output = [],
		    counter = 0,
		    length = string.length,
		    value,
		    extra;
		while (counter < length) {
			value = string.charCodeAt(counter++);
			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
				// high surrogate, and there is a next character
				extra = string.charCodeAt(counter++);
				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
				} else {
					// unmatched surrogate; only append this code unit, in case the next
					// code unit is the high surrogate of a surrogate pair
					output.push(value);
					counter--;
				}
			} else {
				output.push(value);
			}
		}
		return output;
	}

	/**
	 * Creates a string based on an array of numeric code points.
	 * @see `punycode.ucs2.decode`
	 * @memberOf punycode.ucs2
	 * @name encode
	 * @param {Array} codePoints The array of numeric code points.
	 * @returns {String} The new Unicode string (UCS-2).
	 */
	function ucs2encode(array) {
		return map(array, function(value) {
			var output = '';
			if (value > 0xFFFF) {
				value -= 0x10000;
				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
				value = 0xDC00 | value & 0x3FF;
			}
			output += stringFromCharCode(value);
			return output;
		}).join('');
	}

	/**
	 * Converts a basic code point into a digit/integer.
	 * @see `digitToBasic()`
	 * @private
	 * @param {Number} codePoint The basic numeric code point value.
	 * @returns {Number} The numeric value of a basic code point (for use in
	 * representing integers) in the range `0` to `base - 1`, or `base` if
	 * the code point does not represent a value.
	 */
	function basicToDigit(codePoint) {
		if (codePoint - 48 < 10) {
			return codePoint - 22;
		}
		if (codePoint - 65 < 26) {
			return codePoint - 65;
		}
		if (codePoint - 97 < 26) {
			return codePoint - 97;
		}
		return base;
	}

	/**
	 * Converts a digit/integer into a basic code point.
	 * @see `basicToDigit()`
	 * @private
	 * @param {Number} digit The numeric value of a basic code point.
	 * @returns {Number} The basic code point whose value (when used for
	 * representing integers) is `digit`, which needs to be in the range
	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
	 * used; else, the lowercase form is used. The behavior is undefined
	 * if `flag` is non-zero and `digit` has no uppercase form.
	 */
	function digitToBasic(digit, flag) {
		//  0..25 map to ASCII a..z or A..Z
		// 26..35 map to ASCII 0..9
		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
	}

	/**
	 * Bias adaptation function as per section 3.4 of RFC 3492.
	 * http://tools.ietf.org/html/rfc3492#section-3.4
	 * @private
	 */
	function adapt(delta, numPoints, firstTime) {
		var k = 0;
		delta = firstTime ? floor(delta / damp) : delta >> 1;
		delta += floor(delta / numPoints);
		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
			delta = floor(delta / baseMinusTMin);
		}
		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
	}

	/**
	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
	 * symbols.
	 * @memberOf punycode
	 * @param {String} input The Punycode string of ASCII-only symbols.
	 * @returns {String} The resulting string of Unicode symbols.
	 */
	function decode(input) {
		// Don't use UCS-2
		var output = [],
		    inputLength = input.length,
		    out,
		    i = 0,
		    n = initialN,
		    bias = initialBias,
		    basic,
		    j,
		    index,
		    oldi,
		    w,
		    k,
		    digit,
		    t,
		    /** Cached calculation results */
		    baseMinusT;

		// Handle the basic code points: let `basic` be the number of input code
		// points before the last delimiter, or `0` if there is none, then copy
		// the first basic code points to the output.

		basic = input.lastIndexOf(delimiter);
		if (basic < 0) {
			basic = 0;
		}

		for (j = 0; j < basic; ++j) {
			// if it's not a basic code point
			if (input.charCodeAt(j) >= 0x80) {
				error('not-basic');
			}
			output.push(input.charCodeAt(j));
		}

		// Main decoding loop: start just after the last delimiter if any basic code
		// points were copied; start at the beginning otherwise.

		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {

			// `index` is the index of the next character to be consumed.
			// Decode a generalized variable-length integer into `delta`,
			// which gets added to `i`. The overflow checking is easier
			// if we increase `i` as we go, then subtract off its starting
			// value at the end to obtain `delta`.
			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {

				if (index >= inputLength) {
					error('invalid-input');
				}

				digit = basicToDigit(input.charCodeAt(index++));

				if (digit >= base || digit > floor((maxInt - i) / w)) {
					error('overflow');
				}

				i += digit * w;
				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);

				if (digit < t) {
					break;
				}

				baseMinusT = base - t;
				if (w > floor(maxInt / baseMinusT)) {
					error('overflow');
				}

				w *= baseMinusT;

			}

			out = output.length + 1;
			bias = adapt(i - oldi, out, oldi == 0);

			// `i` was supposed to wrap around from `out` to `0`,
			// incrementing `n` each time, so we'll fix that now:
			if (floor(i / out) > maxInt - n) {
				error('overflow');
			}

			n += floor(i / out);
			i %= out;

			// Insert `n` at position `i` of the output
			output.splice(i++, 0, n);

		}

		return ucs2encode(output);
	}

	/**
	 * Converts a string of Unicode symbols (e.g. a domain name label) to a
	 * Punycode string of ASCII-only symbols.
	 * @memberOf punycode
	 * @param {String} input The string of Unicode symbols.
	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
	 */
	function encode(input) {
		var n,
		    delta,
		    handledCPCount,
		    basicLength,
		    bias,
		    j,
		    m,
		    q,
		    k,
		    t,
		    currentValue,
		    output = [],
		    /** `inputLength` will hold the number of code points in `input`. */
		    inputLength,
		    /** Cached calculation results */
		    handledCPCountPlusOne,
		    baseMinusT,
		    qMinusT;

		// Convert the input in UCS-2 to Unicode
		input = ucs2decode(input);

		// Cache the length
		inputLength = input.length;

		// Initialize the state
		n = initialN;
		delta = 0;
		bias = initialBias;

		// Handle the basic code points
		for (j = 0; j < inputLength; ++j) {
			currentValue = input[j];
			if (currentValue < 0x80) {
				output.push(stringFromCharCode(currentValue));
			}
		}

		handledCPCount = basicLength = output.length;

		// `handledCPCount` is the number of code points that have been handled;
		// `basicLength` is the number of basic code points.

		// Finish the basic string - if it is not empty - with a delimiter
		if (basicLength) {
			output.push(delimiter);
		}

		// Main encoding loop:
		while (handledCPCount < inputLength) {

			// All non-basic code points < n have been handled already. Find the next
			// larger one:
			for (m = maxInt, j = 0; j < inputLength; ++j) {
				currentValue = input[j];
				if (currentValue >= n && currentValue < m) {
					m = currentValue;
				}
			}

			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
			// but guard against overflow
			handledCPCountPlusOne = handledCPCount + 1;
			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
				error('overflow');
			}

			delta += (m - n) * handledCPCountPlusOne;
			n = m;

			for (j = 0; j < inputLength; ++j) {
				currentValue = input[j];

				if (currentValue < n && ++delta > maxInt) {
					error('overflow');
				}

				if (currentValue == n) {
					// Represent delta as a generalized variable-length integer
					for (q = delta, k = base; /* no condition */; k += base) {
						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
						if (q < t) {
							break;
						}
						qMinusT = q - t;
						baseMinusT = base - t;
						output.push(
							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
						);
						q = floor(qMinusT / baseMinusT);
					}

					output.push(stringFromCharCode(digitToBasic(q, 0)));
					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
					delta = 0;
					++handledCPCount;
				}
			}

			++delta;
			++n;

		}
		return output.join('');
	}

	/**
	 * Converts a Punycode string representing a domain name or an email address
	 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
	 * it doesn't matter if you call it on a string that has already been
	 * converted to Unicode.
	 * @memberOf punycode
	 * @param {String} input The Punycoded domain name or email address to
	 * convert to Unicode.
	 * @returns {String} The Unicode representation of the given Punycode
	 * string.
	 */
	function toUnicode(input) {
		return mapDomain(input, function(string) {
			return regexPunycode.test(string)
				? decode(string.slice(4).toLowerCase())
				: string;
		});
	}

	/**
	 * Converts a Unicode string representing a domain name or an email address to
	 * Punycode. Only the non-ASCII parts of the domain name will be converted,
	 * i.e. it doesn't matter if you call it with a domain that's already in
	 * ASCII.
	 * @memberOf punycode
	 * @param {String} input The domain name or email address to convert, as a
	 * Unicode string.
	 * @returns {String} The Punycode representation of the given domain name or
	 * email address.
	 */
	function toASCII(input) {
		return mapDomain(input, function(string) {
			return regexNonASCII.test(string)
				? 'xn--' + encode(string)
				: string;
		});
	}

	/*--------------------------------------------------------------------------*/

	/** Define the public API */
	punycode = {
		/**
		 * A string representing the current Punycode.js version number.
		 * @memberOf punycode
		 * @type String
		 */
		'version': '1.3.2',
		/**
		 * An object of methods to convert from JavaScript's internal character
		 * representation (UCS-2) to Unicode code points, and back.
		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
		 * @memberOf punycode
		 * @type Object
		 */
		'ucs2': {
			'decode': ucs2decode,
			'encode': ucs2encode
		},
		'decode': decode,
		'encode': encode,
		'toASCII': toASCII,
		'toUnicode': toUnicode
	};

	/** Expose `punycode` */
	// Some AMD build optimizers, like r.js, check for specific condition patterns
	// like the following:
	if (
		true
	) {
		!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
			return punycode;
		}).call(exports, __webpack_require__, exports, module),
		__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	} else {}

}(this));


/***/ }),

/***/ 3548:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {

"use strict";
var __webpack_unused_export__;
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.



var punycode = __webpack_require__(9473);
var util = __webpack_require__(6729);

__webpack_unused_export__ = urlParse;
__webpack_unused_export__ = urlResolve;
__webpack_unused_export__ = urlResolveObject;
__webpack_unused_export__ = urlFormat;

__webpack_unused_export__ = Url;

function Url() {
  this.protocol = null;
  this.slashes = null;
  this.auth = null;
  this.host = null;
  this.port = null;
  this.hostname = null;
  this.hash = null;
  this.search = null;
  this.query = null;
  this.pathname = null;
  this.path = null;
  this.href = null;
}

// Reference: RFC 3986, RFC 1808, RFC 2396

// define these here so at least they only have to be
// compiled once on the first module load.
var protocolPattern = /^([a-z0-9.+-]+:)/i,
    portPattern = /:[0-9]*$/,

    // Special case for a simple path URL
    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,

    // RFC 2396: characters reserved for delimiting URLs.
    // We actually just auto-escape these.
    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],

    // RFC 2396: characters not allowed for various reasons.
    unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),

    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
    autoEscape = ['\''].concat(unwise),
    // Characters that are never ever allowed in a hostname.
    // Note that any invalid chars are also handled, but these
    // are the ones that are *expected* to be seen, so we fast-path
    // them.
    nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
    hostEndingChars = ['/', '?', '#'],
    hostnameMaxLen = 255,
    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
    // protocols that can allow "unsafe" and "unwise" chars.
    unsafeProtocol = {
      'javascript': true,
      'javascript:': true
    },
    // protocols that never have a hostname.
    hostlessProtocol = {
      'javascript': true,
      'javascript:': true
    },
    // protocols that always contain a // bit.
    slashedProtocol = {
      'http': true,
      'https': true,
      'ftp': true,
      'gopher': true,
      'file': true,
      'http:': true,
      'https:': true,
      'ftp:': true,
      'gopher:': true,
      'file:': true
    },
    querystring = __webpack_require__(8528);

function urlParse(url, parseQueryString, slashesDenoteHost) {
  if (url && util.isObject(url) && url instanceof Url) return url;

  var u = new Url;
  u.parse(url, parseQueryString, slashesDenoteHost);
  return u;
}

Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
  if (!util.isString(url)) {
    throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
  }

  // Copy chrome, IE, opera backslash-handling behavior.
  // Back slashes before the query string get converted to forward slashes
  // See: https://code.google.com/p/chromium/issues/detail?id=25916
  var queryIndex = url.indexOf('?'),
      splitter =
          (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
      uSplit = url.split(splitter),
      slashRegex = /\\/g;
  uSplit[0] = uSplit[0].replace(slashRegex, '/');
  url = uSplit.join(splitter);

  var rest = url;

  // trim before proceeding.
  // This is to support parse stuff like "  http://foo.com  \n"
  rest = rest.trim();

  if (!slashesDenoteHost && url.split('#').length === 1) {
    // Try fast path regexp
    var simplePath = simplePathPattern.exec(rest);
    if (simplePath) {
      this.path = rest;
      this.href = rest;
      this.pathname = simplePath[1];
      if (simplePath[2]) {
        this.search = simplePath[2];
        if (parseQueryString) {
          this.query = querystring.parse(this.search.substr(1));
        } else {
          this.query = this.search.substr(1);
        }
      } else if (parseQueryString) {
        this.search = '';
        this.query = {};
      }
      return this;
    }
  }

  var proto = protocolPattern.exec(rest);
  if (proto) {
    proto = proto[0];
    var lowerProto = proto.toLowerCase();
    this.protocol = lowerProto;
    rest = rest.substr(proto.length);
  }

  // figure out if it's got a host
  // user@server is *always* interpreted as a hostname, and url
  // resolution will treat //foo/bar as host=foo,path=bar because that's
  // how the browser resolves relative URLs.
  if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
    var slashes = rest.substr(0, 2) === '//';
    if (slashes && !(proto && hostlessProtocol[proto])) {
      rest = rest.substr(2);
      this.slashes = true;
    }
  }

  if (!hostlessProtocol[proto] &&
      (slashes || (proto && !slashedProtocol[proto]))) {

    // there's a hostname.
    // the first instance of /, ?, ;, or # ends the host.
    //
    // If there is an @ in the hostname, then non-host chars *are* allowed
    // to the left of the last @ sign, unless some host-ending character
    // comes *before* the @-sign.
    // URLs are obnoxious.
    //
    // ex:
    // http://a@b@c/ => user:a@b host:c
    // http://a@b?@c => user:a host:c path:/?@c

    // v0.12 TODO(isaacs): This is not quite how Chrome does things.
    // Review our test case against browsers more comprehensively.

    // find the first instance of any hostEndingChars
    var hostEnd = -1;
    for (var i = 0; i < hostEndingChars.length; i++) {
      var hec = rest.indexOf(hostEndingChars[i]);
      if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
        hostEnd = hec;
    }

    // at this point, either we have an explicit point where the
    // auth portion cannot go past, or the last @ char is the decider.
    var auth, atSign;
    if (hostEnd === -1) {
      // atSign can be anywhere.
      atSign = rest.lastIndexOf('@');
    } else {
      // atSign must be in auth portion.
      // http://a@b/c@d => host:b auth:a path:/c@d
      atSign = rest.lastIndexOf('@', hostEnd);
    }

    // Now we have a portion which is definitely the auth.
    // Pull that off.
    if (atSign !== -1) {
      auth = rest.slice(0, atSign);
      rest = rest.slice(atSign + 1);
      this.auth = decodeURIComponent(auth);
    }

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

    this.host = rest.slice(0, hostEnd);
    rest = rest.slice(hostEnd);

    // pull out port.
    this.parseHost();

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

    // if hostname begins with [ and ends with ]
    // assume that it's an IPv6 address.
    var ipv6Hostname = this.hostname[0] === '[' &&
        this.hostname[this.hostname.length - 1] === ']';

    // validate a little.
    if (!ipv6Hostname) {
      var hostparts = this.hostname.split(/\./);
      for (var i = 0, l = hostparts.length; i < l; i++) {
        var part = hostparts[i];
        if (!part) continue;
        if (!part.match(hostnamePartPattern)) {
          var newpart = '';
          for (var j = 0, k = part.length; j < k; j++) {
            if (part.charCodeAt(j) > 127) {
              // we replace non-ASCII char with a temporary placeholder
              // we need this to make sure size of hostname is not
              // broken by replacing non-ASCII by nothing
              newpart += 'x';
            } else {
              newpart += part[j];
            }
          }
          // we test again with ASCII char only
          if (!newpart.match(hostnamePartPattern)) {
            var validParts = hostparts.slice(0, i);
            var notHost = hostparts.slice(i + 1);
            var bit = part.match(hostnamePartStart);
            if (bit) {
              validParts.push(bit[1]);
              notHost.unshift(bit[2]);
            }
            if (notHost.length) {
              rest = '/' + notHost.join('.') + rest;
            }
            this.hostname = validParts.join('.');
            break;
          }
        }
      }
    }

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

    if (!ipv6Hostname) {
      // IDNA Support: Returns a punycoded representation of "domain".
      // It only converts parts of the domain name that
      // have non-ASCII characters, i.e. it doesn't matter if
      // you call it with a domain that already is ASCII-only.
      this.hostname = punycode.toASCII(this.hostname);
    }

    var p = this.port ? ':' + this.port : '';
    var h = this.hostname || '';
    this.host = h + p;
    this.href += this.host;

    // strip [ and ] from the hostname
    // the host field still retains them, though
    if (ipv6Hostname) {
      this.hostname = this.hostname.substr(1, this.hostname.length - 2);
      if (rest[0] !== '/') {
        rest = '/' + rest;
      }
    }
  }

  // now rest is set to the post-host stuff.
  // chop off any delim chars.
  if (!unsafeProtocol[lowerProto]) {

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


  // chop off from the tail first.
  var hash = rest.indexOf('#');
  if (hash !== -1) {
    // got a fragment string.
    this.hash = rest.substr(hash);
    rest = rest.slice(0, hash);
  }
  var qm = rest.indexOf('?');
  if (qm !== -1) {
    this.search = rest.substr(qm);
    this.query = rest.substr(qm + 1);
    if (parseQueryString) {
      this.query = querystring.parse(this.query);
    }
    rest = rest.slice(0, qm);
  } else if (parseQueryString) {
    // no query string, but parseQueryString still requested
    this.search = '';
    this.query = {};
  }
  if (rest) this.pathname = rest;
  if (slashedProtocol[lowerProto] &&
      this.hostname && !this.pathname) {
    this.pathname = '/';
  }

  //to support http.request
  if (this.pathname || this.search) {
    var p = this.pathname || '';
    var s = this.search || '';
    this.path = p + s;
  }

  // finally, reconstruct the href based on what has been validated.
  this.href = this.format();
  return this;
};

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

Url.prototype.format = function() {
  var auth = this.auth || '';
  if (auth) {
    auth = encodeURIComponent(auth);
    auth = auth.replace(/%3A/i, ':');
    auth += '@';
  }

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

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

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

  var search = this.search || (query && ('?' + query)) || '';

  if (protocol && protocol.substr(-1) !== ':') protocol += ':';

  // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
  // unless they had them to begin with.
  if (this.slashes ||
      (!protocol || slashedProtocol[protocol]) && host !== false) {
    host = '//' + (host || '');
    if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
  } else if (!host) {
    host = '';
  }

  if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
  if (search && search.charAt(0) !== '?') search = '?' + search;

  pathname = pathname.replace(/[?#]/g, function(match) {
    return encodeURIComponent(match);
  });
  search = search.replace('#', '%23');

  return protocol + host + pathname + search + hash;
};

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

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

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

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

  var result = new Url();
  var tkeys = Object.keys(this);
  for (var tk = 0; tk < tkeys.length; tk++) {
    var tkey = tkeys[tk];
    result[tkey] = this[tkey];
  }

  // hash is always overridden, no matter what.
  // even href="" will remove it.
  result.hash = relative.hash;

  // if the relative url is empty, then there's nothing left to do here.
  if (relative.href === '') {
    result.href = result.format();
    return result;
  }

  // hrefs like //foo/bar always cut to the protocol.
  if (relative.slashes && !relative.protocol) {
    // take everything except the protocol from relative
    var rkeys = Object.keys(relative);
    for (var rk = 0; rk < rkeys.length; rk++) {
      var rkey = rkeys[rk];
      if (rkey !== 'protocol')
        result[rkey] = relative[rkey];
    }

    //urlParse appends trailing / to urls like http://www.example.com
    if (slashedProtocol[result.protocol] &&
        result.hostname && !result.pathname) {
      result.path = result.pathname = '/';
    }

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

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

    result.protocol = relative.protocol;
    if (!relative.host && !hostlessProtocol[relative.protocol]) {
      var relPath = (relative.pathname || '').split('/');
      while (relPath.length && !(relative.host = relPath.shift()));
      if (!relative.host) relative.host = '';
      if (!relative.hostname) relative.hostname = '';
      if (relPath[0] !== '') relPath.unshift('');
      if (relPath.length < 2) relPath.unshift('');
      result.pathname = relPath.join('/');
    } else {
      result.pathname = relative.pathname;
    }
    result.search = relative.search;
    result.query = relative.query;
    result.host = relative.host || '';
    result.auth = relative.auth;
    result.hostname = relative.hostname || relative.host;
    result.port = relative.port;
    // to support http.request
    if (result.pathname || result.search) {
      var p = result.pathname || '';
      var s = result.search || '';
      result.path = p + s;
    }
    result.slashes = result.slashes || relative.slashes;
    result.href = result.format();
    return result;
  }

  var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
      isRelAbs = (
          relative.host ||
          relative.pathname && relative.pathname.charAt(0) === '/'
      ),
      mustEndAbs = (isRelAbs || isSourceAbs ||
                    (result.host && relative.pathname)),
      removeAllDots = mustEndAbs,
      srcPath = result.pathname && result.pathname.split('/') || [],
      relPath = relative.pathname && relative.pathname.split('/') || [],
      psychotic = result.protocol && !slashedProtocol[result.protocol];

  // if the url is a non-slashed url, then relative
  // links like ../.. should be able
  // to crawl up to the hostname, as well.  This is strange.
  // result.protocol has already been set by now.
  // Later on, put the first path part into the host field.
  if (psychotic) {
    result.hostname = '';
    result.port = null;
    if (result.host) {
      if (srcPath[0] === '') srcPath[0] = result.host;
      else srcPath.unshift(result.host);
    }
    result.host = '';
    if (relative.protocol) {
      relative.hostname = null;
      relative.port = null;
      if (relative.host) {
        if (relPath[0] === '') relPath[0] = relative.host;
        else relPath.unshift(relative.host);
      }
      relative.host = null;
    }
    mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
  }

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

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

  // if a url ENDs in . or .., then it must get a trailing slash.
  // however, if it ends in anything else non-slashy,
  // then it must NOT get a trailing slash.
  var last = srcPath.slice(-1)[0];
  var hasTrailingSlash = (
      (result.host || relative.host || srcPath.length > 1) &&
      (last === '.' || last === '..') || last === '');

  // strip single dots, resolve double dots to parent dir
  // if the path tries to go above the root, `up` ends up > 0
  var up = 0;
  for (var i = srcPath.length; i >= 0; i--) {
    last = srcPath[i];
    if (last === '.') {
      srcPath.splice(i, 1);
    } else if (last === '..') {
      srcPath.splice(i, 1);
      up++;
    } else if (up) {
      srcPath.splice(i, 1);
      up--;
    }
  }

  // if the path is allowed to go above the root, restore leading ..s
  if (!mustEndAbs && !removeAllDots) {
    for (; up--; up) {
      srcPath.unshift('..');
    }
  }

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

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

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

  // put the host back
  if (psychotic) {
    result.hostname = result.host = isAbsolute ? '' :
                                    srcPath.length ? srcPath.shift() : '';
    //occationaly the auth can get stuck only in host
    //this especially happens in cases like
    //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
    var authInHost = result.host && result.host.indexOf('@') > 0 ?
                     result.host.split('@') : false;
    if (authInHost) {
      result.auth = authInHost.shift();
      result.host = result.hostname = authInHost.shift();
    }
  }

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

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

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

  //to support request.http
  if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
    result.path = (result.pathname ? result.pathname : '') +
                  (result.search ? result.search : '');
  }
  result.auth = relative.auth || result.auth;
  result.slashes = result.slashes || relative.slashes;
  result.href = result.format();
  return result;
};

Url.prototype.parseHost = function() {
  var host = this.host;
  var port = portPattern.exec(host);
  if (port) {
    port = port[0];
    if (port !== ':') {
      this.port = port.substr(1);
    }
    host = host.substr(0, host.length - port.length);
  }
  if (host) this.hostname = host;
};


/***/ }),

/***/ 6729:
/***/ ((module) => {

"use strict";


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


/***/ }),

/***/ 3679:
/***/ (function(module, exports) {

var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (global, factory) {
  if (true) {
    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [module], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
		__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
		(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
		__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  } else { var mod; }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (module) {
  /* webextension-polyfill - v0.8.0 - Tue Apr 20 2021 11:27:38 */

  /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */

  /* vim: set sts=2 sw=2 et tw=80: */

  /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  "use strict";

  if (typeof browser === "undefined" || Object.getPrototypeOf(browser) !== Object.prototype) {
    const CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE = "The message port closed before a response was received.";
    const SEND_RESPONSE_DEPRECATION_WARNING = "Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)"; // Wrapping the bulk of this polyfill in a one-time-use function is a minor
    // optimization for Firefox. Since Spidermonkey does not fully parse the
    // contents of a function until the first time it's called, and since it will
    // never actually need to be called, this allows the polyfill to be included
    // in Firefox nearly for free.

    const wrapAPIs = extensionAPIs => {
      // NOTE: apiMetadata is associated to the content of the api-metadata.json file
      // at build time by replacing the following "include" with the content of the
      // JSON file.
      const apiMetadata = {
        "alarms": {
          "clear": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "clearAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "get": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "getAll": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "bookmarks": {
          "create": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "get": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getChildren": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getRecent": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getSubTree": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getTree": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "move": {
            "minArgs": 2,
            "maxArgs": 2
          },
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeTree": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "search": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "update": {
            "minArgs": 2,
            "maxArgs": 2
          }
        },
        "browserAction": {
          "disable": {
            "minArgs": 0,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "enable": {
            "minArgs": 0,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "getBadgeBackgroundColor": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getBadgeText": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getPopup": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getTitle": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "openPopup": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "setBadgeBackgroundColor": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "setBadgeText": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "setIcon": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "setPopup": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "setTitle": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          }
        },
        "browsingData": {
          "remove": {
            "minArgs": 2,
            "maxArgs": 2
          },
          "removeCache": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeCookies": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeDownloads": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeFormData": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeHistory": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeLocalStorage": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removePasswords": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removePluginData": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "settings": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "commands": {
          "getAll": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "contextMenus": {
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "update": {
            "minArgs": 2,
            "maxArgs": 2
          }
        },
        "cookies": {
          "get": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getAll": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getAllCookieStores": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "set": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "devtools": {
          "inspectedWindow": {
            "eval": {
              "minArgs": 1,
              "maxArgs": 2,
              "singleCallbackArg": false
            }
          },
          "panels": {
            "create": {
              "minArgs": 3,
              "maxArgs": 3,
              "singleCallbackArg": true
            },
            "elements": {
              "createSidebarPane": {
                "minArgs": 1,
                "maxArgs": 1
              }
            }
          }
        },
        "downloads": {
          "cancel": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "download": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "erase": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getFileIcon": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "open": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "pause": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeFile": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "resume": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "search": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "show": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          }
        },
        "extension": {
          "isAllowedFileSchemeAccess": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "isAllowedIncognitoAccess": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "history": {
          "addUrl": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "deleteAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "deleteRange": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "deleteUrl": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getVisits": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "search": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "i18n": {
          "detectLanguage": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getAcceptLanguages": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "identity": {
          "launchWebAuthFlow": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "idle": {
          "queryState": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "management": {
          "get": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "getSelf": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "setEnabled": {
            "minArgs": 2,
            "maxArgs": 2
          },
          "uninstallSelf": {
            "minArgs": 0,
            "maxArgs": 1
          }
        },
        "notifications": {
          "clear": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "create": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "getAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "getPermissionLevel": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "update": {
            "minArgs": 2,
            "maxArgs": 2
          }
        },
        "pageAction": {
          "getPopup": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getTitle": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "hide": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "setIcon": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "setPopup": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "setTitle": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          },
          "show": {
            "minArgs": 1,
            "maxArgs": 1,
            "fallbackToNoCallback": true
          }
        },
        "permissions": {
          "contains": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getAll": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "request": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "runtime": {
          "getBackgroundPage": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "getPlatformInfo": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "openOptionsPage": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "requestUpdateCheck": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "sendMessage": {
            "minArgs": 1,
            "maxArgs": 3
          },
          "sendNativeMessage": {
            "minArgs": 2,
            "maxArgs": 2
          },
          "setUninstallURL": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "sessions": {
          "getDevices": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "getRecentlyClosed": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "restore": {
            "minArgs": 0,
            "maxArgs": 1
          }
        },
        "storage": {
          "local": {
            "clear": {
              "minArgs": 0,
              "maxArgs": 0
            },
            "get": {
              "minArgs": 0,
              "maxArgs": 1
            },
            "getBytesInUse": {
              "minArgs": 0,
              "maxArgs": 1
            },
            "remove": {
              "minArgs": 1,
              "maxArgs": 1
            },
            "set": {
              "minArgs": 1,
              "maxArgs": 1
            }
          },
          "managed": {
            "get": {
              "minArgs": 0,
              "maxArgs": 1
            },
            "getBytesInUse": {
              "minArgs": 0,
              "maxArgs": 1
            }
          },
          "sync": {
            "clear": {
              "minArgs": 0,
              "maxArgs": 0
            },
            "get": {
              "minArgs": 0,
              "maxArgs": 1
            },
            "getBytesInUse": {
              "minArgs": 0,
              "maxArgs": 1
            },
            "remove": {
              "minArgs": 1,
              "maxArgs": 1
            },
            "set": {
              "minArgs": 1,
              "maxArgs": 1
            }
          }
        },
        "tabs": {
          "captureVisibleTab": {
            "minArgs": 0,
            "maxArgs": 2
          },
          "create": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "detectLanguage": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "discard": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "duplicate": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "executeScript": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "get": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getCurrent": {
            "minArgs": 0,
            "maxArgs": 0
          },
          "getZoom": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "getZoomSettings": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "goBack": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "goForward": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "highlight": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "insertCSS": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "move": {
            "minArgs": 2,
            "maxArgs": 2
          },
          "query": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "reload": {
            "minArgs": 0,
            "maxArgs": 2
          },
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "removeCSS": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "sendMessage": {
            "minArgs": 2,
            "maxArgs": 3
          },
          "setZoom": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "setZoomSettings": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "update": {
            "minArgs": 1,
            "maxArgs": 2
          }
        },
        "topSites": {
          "get": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "webNavigation": {
          "getAllFrames": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "getFrame": {
            "minArgs": 1,
            "maxArgs": 1
          }
        },
        "webRequest": {
          "handlerBehaviorChanged": {
            "minArgs": 0,
            "maxArgs": 0
          }
        },
        "windows": {
          "create": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "get": {
            "minArgs": 1,
            "maxArgs": 2
          },
          "getAll": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "getCurrent": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "getLastFocused": {
            "minArgs": 0,
            "maxArgs": 1
          },
          "remove": {
            "minArgs": 1,
            "maxArgs": 1
          },
          "update": {
            "minArgs": 2,
            "maxArgs": 2
          }
        }
      };

      if (Object.keys(apiMetadata).length === 0) {
        throw new Error("api-metadata.json has not been included in browser-polyfill");
      }
      /**
       * A WeakMap subclass which creates and stores a value for any key which does
       * not exist when accessed, but behaves exactly as an ordinary WeakMap
       * otherwise.
       *
       * @param {function} createItem
       *        A function which will be called in order to create the value for any
       *        key which does not exist, the first time it is accessed. The
       *        function receives, as its only argument, the key being created.
       */


      class DefaultWeakMap extends WeakMap {
        constructor(createItem, items = undefined) {
          super(items);
          this.createItem = createItem;
        }

        get(key) {
          if (!this.has(key)) {
            this.set(key, this.createItem(key));
          }

          return super.get(key);
        }

      }
      /**
       * Returns true if the given object is an object with a `then` method, and can
       * therefore be assumed to behave as a Promise.
       *
       * @param {*} value The value to test.
       * @returns {boolean} True if the value is thenable.
       */


      const isThenable = value => {
        return value && typeof value === "object" && typeof value.then === "function";
      };
      /**
       * Creates and returns a function which, when called, will resolve or reject
       * the given promise based on how it is called:
       *
       * - If, when called, `chrome.runtime.lastError` contains a non-null object,
       *   the promise is rejected with that value.
       * - If the function is called with exactly one argument, the promise is
       *   resolved to that value.
       * - Otherwise, the promise is resolved to an array containing all of the
       *   function's arguments.
       *
       * @param {object} promise
       *        An object containing the resolution and rejection functions of a
       *        promise.
       * @param {function} promise.resolve
       *        The promise's resolution function.
       * @param {function} promise.reject
       *        The promise's rejection function.
       * @param {object} metadata
       *        Metadata about the wrapped method which has created the callback.
       * @param {boolean} metadata.singleCallbackArg
       *        Whether or not the promise is resolved with only the first
       *        argument of the callback, alternatively an array of all the
       *        callback arguments is resolved. By default, if the callback
       *        function is invoked with only a single argument, that will be
       *        resolved to the promise, while all arguments will be resolved as
       *        an array if multiple are given.
       *
       * @returns {function}
       *        The generated callback function.
       */


      const makeCallback = (promise, metadata) => {
        return (...callbackArgs) => {
          if (extensionAPIs.runtime.lastError) {
            promise.reject(new Error(extensionAPIs.runtime.lastError.message));
          } else if (metadata.singleCallbackArg || callbackArgs.length <= 1 && metadata.singleCallbackArg !== false) {
            promise.resolve(callbackArgs[0]);
          } else {
            promise.resolve(callbackArgs);
          }
        };
      };

      const pluralizeArguments = numArgs => numArgs == 1 ? "argument" : "arguments";
      /**
       * Creates a wrapper function for a method with the given name and metadata.
       *
       * @param {string} name
       *        The name of the method which is being wrapped.
       * @param {object} metadata
       *        Metadata about the method being wrapped.
       * @param {integer} metadata.minArgs
       *        The minimum number of arguments which must be passed to the
       *        function. If called with fewer than this number of arguments, the
       *        wrapper will raise an exception.
       * @param {integer} metadata.maxArgs
       *        The maximum number of arguments which may be passed to the
       *        function. If called with more than this number of arguments, the
       *        wrapper will raise an exception.
       * @param {boolean} metadata.singleCallbackArg
       *        Whether or not the promise is resolved with only the first
       *        argument of the callback, alternatively an array of all the
       *        callback arguments is resolved. By default, if the callback
       *        function is invoked with only a single argument, that will be
       *        resolved to the promise, while all arguments will be resolved as
       *        an array if multiple are given.
       *
       * @returns {function(object, ...*)}
       *       The generated wrapper function.
       */


      const wrapAsyncFunction = (name, metadata) => {
        return function asyncFunctionWrapper(target, ...args) {
          if (args.length < metadata.minArgs) {
            throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
          }

          if (args.length > metadata.maxArgs) {
            throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
          }

          return new Promise((resolve, reject) => {
            if (metadata.fallbackToNoCallback) {
              // This API method has currently no callback on Chrome, but it return a promise on Firefox,
              // and so the polyfill will try to call it with a callback first, and it will fallback
              // to not passing the callback if the first call fails.
              try {
                target[name](...args, makeCallback({
                  resolve,
                  reject
                }, metadata));
              } catch (cbError) {
                console.warn(`${name} API method doesn't seem to support the callback parameter, ` + "falling back to call it without a callback: ", cbError);
                target[name](...args); // Update the API method metadata, so that the next API calls will not try to
                // use the unsupported callback anymore.

                metadata.fallbackToNoCallback = false;
                metadata.noCallback = true;
                resolve();
              }
            } else if (metadata.noCallback) {
              target[name](...args);
              resolve();
            } else {
              target[name](...args, makeCallback({
                resolve,
                reject
              }, metadata));
            }
          });
        };
      };
      /**
       * Wraps an existing method of the target object, so that calls to it are
       * intercepted by the given wrapper function. The wrapper function receives,
       * as its first argument, the original `target` object, followed by each of
       * the arguments passed to the original method.
       *
       * @param {object} target
       *        The original target object that the wrapped method belongs to.
       * @param {function} method
       *        The method being wrapped. This is used as the target of the Proxy
       *        object which is created to wrap the method.
       * @param {function} wrapper
       *        The wrapper function which is called in place of a direct invocation
       *        of the wrapped method.
       *
       * @returns {Proxy<function>}
       *        A Proxy object for the given method, which invokes the given wrapper
       *        method in its place.
       */


      const wrapMethod = (target, method, wrapper) => {
        return new Proxy(method, {
          apply(targetMethod, thisObj, args) {
            return wrapper.call(thisObj, target, ...args);
          }

        });
      };

      let hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
      /**
       * Wraps an object in a Proxy which intercepts and wraps certain methods
       * based on the given `wrappers` and `metadata` objects.
       *
       * @param {object} target
       *        The target object to wrap.
       *
       * @param {object} [wrappers = {}]
       *        An object tree containing wrapper functions for special cases. Any
       *        function present in this object tree is called in place of the
       *        method in the same location in the `target` object tree. These
       *        wrapper methods are invoked as described in {@see wrapMethod}.
       *
       * @param {object} [metadata = {}]
       *        An object tree containing metadata used to automatically generate
       *        Promise-based wrapper functions for asynchronous. Any function in
       *        the `target` object tree which has a corresponding metadata object
       *        in the same location in the `metadata` tree is replaced with an
       *        automatically-generated wrapper function, as described in
       *        {@see wrapAsyncFunction}
       *
       * @returns {Proxy<object>}
       */

      const wrapObject = (target, wrappers = {}, metadata = {}) => {
        let cache = Object.create(null);
        let handlers = {
          has(proxyTarget, prop) {
            return prop in target || prop in cache;
          },

          get(proxyTarget, prop, receiver) {
            if (prop in cache) {
              return cache[prop];
            }

            if (!(prop in target)) {
              return undefined;
            }

            let value = target[prop];

            if (typeof value === "function") {
              // This is a method on the underlying object. Check if we need to do
              // any wrapping.
              if (typeof wrappers[prop] === "function") {
                // We have a special-case wrapper for this method.
                value = wrapMethod(target, target[prop], wrappers[prop]);
              } else if (hasOwnProperty(metadata, prop)) {
                // This is an async method that we have metadata for. Create a
                // Promise wrapper for it.
                let wrapper = wrapAsyncFunction(prop, metadata[prop]);
                value = wrapMethod(target, target[prop], wrapper);
              } else {
                // This is a method that we don't know or care about. Return the
                // original method, bound to the underlying object.
                value = value.bind(target);
              }
            } else if (typeof value === "object" && value !== null && (hasOwnProperty(wrappers, prop) || hasOwnProperty(metadata, prop))) {
              // This is an object that we need to do some wrapping for the children
              // of. Create a sub-object wrapper for it with the appropriate child
              // metadata.
              value = wrapObject(value, wrappers[prop], metadata[prop]);
            } else if (hasOwnProperty(metadata, "*")) {
              // Wrap all properties in * namespace.
              value = wrapObject(value, wrappers[prop], metadata["*"]);
            } else {
              // We don't need to do any wrapping for this property,
              // so just forward all access to the underlying object.
              Object.defineProperty(cache, prop, {
                configurable: true,
                enumerable: true,

                get() {
                  return target[prop];
                },

                set(value) {
                  target[prop] = value;
                }

              });
              return value;
            }

            cache[prop] = value;
            return value;
          },

          set(proxyTarget, prop, value, receiver) {
            if (prop in cache) {
              cache[prop] = value;
            } else {
              target[prop] = value;
            }

            return true;
          },

          defineProperty(proxyTarget, prop, desc) {
            return Reflect.defineProperty(cache, prop, desc);
          },

          deleteProperty(proxyTarget, prop) {
            return Reflect.deleteProperty(cache, prop);
          }

        }; // Per contract of the Proxy API, the "get" proxy handler must return the
        // original value of the target if that value is declared read-only and
        // non-configurable. For this reason, we create an object with the
        // prototype set to `target` instead of using `target` directly.
        // Otherwise we cannot return a custom object for APIs that
        // are declared read-only and non-configurable, such as `chrome.devtools`.
        //
        // The proxy handlers themselves will still use the original `target`
        // instead of the `proxyTarget`, so that the methods and properties are
        // dereferenced via the original targets.

        let proxyTarget = Object.create(target);
        return new Proxy(proxyTarget, handlers);
      };
      /**
       * Creates a set of wrapper functions for an event object, which handles
       * wrapping of listener functions that those messages are passed.
       *
       * A single wrapper is created for each listener function, and stored in a
       * map. Subsequent calls to `addListener`, `hasListener`, or `removeListener`
       * retrieve the original wrapper, so that  attempts to remove a
       * previously-added listener work as expected.
       *
       * @param {DefaultWeakMap<function, function>} wrapperMap
       *        A DefaultWeakMap object which will create the appropriate wrapper
       *        for a given listener function when one does not exist, and retrieve
       *        an existing one when it does.
       *
       * @returns {object}
       */


      const wrapEvent = wrapperMap => ({
        addListener(target, listener, ...args) {
          target.addListener(wrapperMap.get(listener), ...args);
        },

        hasListener(target, listener) {
          return target.hasListener(wrapperMap.get(listener));
        },

        removeListener(target, listener) {
          target.removeListener(wrapperMap.get(listener));
        }

      });

      const onRequestFinishedWrappers = new DefaultWeakMap(listener => {
        if (typeof listener !== "function") {
          return listener;
        }
        /**
         * Wraps an onRequestFinished listener function so that it will return a
         * `getContent()` property which returns a `Promise` rather than using a
         * callback API.
         *
         * @param {object} req
         *        The HAR entry object representing the network request.
         */


        return function onRequestFinished(req) {
          const wrappedReq = wrapObject(req, {}
          /* wrappers */
          , {
            getContent: {
              minArgs: 0,
              maxArgs: 0
            }
          });
          listener(wrappedReq);
        };
      }); // Keep track if the deprecation warning has been logged at least once.

      let loggedSendResponseDeprecationWarning = false;
      const onMessageWrappers = new DefaultWeakMap(listener => {
        if (typeof listener !== "function") {
          return listener;
        }
        /**
         * Wraps a message listener function so that it may send responses based on
         * its return value, rather than by returning a sentinel value and calling a
         * callback. If the listener function returns a Promise, the response is
         * sent when the promise either resolves or rejects.
         *
         * @param {*} message
         *        The message sent by the other end of the channel.
         * @param {object} sender
         *        Details about the sender of the message.
         * @param {function(*)} sendResponse
         *        A callback which, when called with an arbitrary argument, sends
         *        that value as a response.
         * @returns {boolean}
         *        True if the wrapped listener returned a Promise, which will later
         *        yield a response. False otherwise.
         */


        return function onMessage(message, sender, sendResponse) {
          let didCallSendResponse = false;
          let wrappedSendResponse;
          let sendResponsePromise = new Promise(resolve => {
            wrappedSendResponse = function (response) {
              if (!loggedSendResponseDeprecationWarning) {
                console.warn(SEND_RESPONSE_DEPRECATION_WARNING, new Error().stack);
                loggedSendResponseDeprecationWarning = true;
              }

              didCallSendResponse = true;
              resolve(response);
            };
          });
          let result;

          try {
            result = listener(message, sender, wrappedSendResponse);
          } catch (err) {
            result = Promise.reject(err);
          }

          const isResultThenable = result !== true && isThenable(result); // If the listener didn't returned true or a Promise, or called
          // wrappedSendResponse synchronously, we can exit earlier
          // because there will be no response sent from this listener.

          if (result !== true && !isResultThenable && !didCallSendResponse) {
            return false;
          } // A small helper to send the message if the promise resolves
          // and an error if the promise rejects (a wrapped sendMessage has
          // to translate the message into a resolved promise or a rejected
          // promise).


          const sendPromisedResult = promise => {
            promise.then(msg => {
              // send the message value.
              sendResponse(msg);
            }, error => {
              // Send a JSON representation of the error if the rejected value
              // is an instance of error, or the object itself otherwise.
              let message;

              if (error && (error instanceof Error || typeof error.message === "string")) {
                message = error.message;
              } else {
                message = "An unexpected error occurred";
              }

              sendResponse({
                __mozWebExtensionPolyfillReject__: true,
                message
              });
            }).catch(err => {
              // Print an error on the console if unable to send the response.
              console.error("Failed to send onMessage rejected reply", err);
            });
          }; // If the listener returned a Promise, send the resolved value as a
          // result, otherwise wait the promise related to the wrappedSendResponse
          // callback to resolve and send it as a response.


          if (isResultThenable) {
            sendPromisedResult(result);
          } else {
            sendPromisedResult(sendResponsePromise);
          } // Let Chrome know that the listener is replying.


          return true;
        };
      });

      const wrappedSendMessageCallback = ({
        reject,
        resolve
      }, reply) => {
        if (extensionAPIs.runtime.lastError) {
          // Detect when none of the listeners replied to the sendMessage call and resolve
          // the promise to undefined as in Firefox.
          // See https://github.com/mozilla/webextension-polyfill/issues/130
          if (extensionAPIs.runtime.lastError.message === CHROME_SEND_MESSAGE_CALLBACK_NO_RESPONSE_MESSAGE) {
            resolve();
          } else {
            reject(new Error(extensionAPIs.runtime.lastError.message));
          }
        } else if (reply && reply.__mozWebExtensionPolyfillReject__) {
          // Convert back the JSON representation of the error into
          // an Error instance.
          reject(new Error(reply.message));
        } else {
          resolve(reply);
        }
      };

      const wrappedSendMessage = (name, metadata, apiNamespaceObj, ...args) => {
        if (args.length < metadata.minArgs) {
          throw new Error(`Expected at least ${metadata.minArgs} ${pluralizeArguments(metadata.minArgs)} for ${name}(), got ${args.length}`);
        }

        if (args.length > metadata.maxArgs) {
          throw new Error(`Expected at most ${metadata.maxArgs} ${pluralizeArguments(metadata.maxArgs)} for ${name}(), got ${args.length}`);
        }

        return new Promise((resolve, reject) => {
          const wrappedCb = wrappedSendMessageCallback.bind(null, {
            resolve,
            reject
          });
          args.push(wrappedCb);
          apiNamespaceObj.sendMessage(...args);
        });
      };

      const staticWrappers = {
        devtools: {
          network: {
            onRequestFinished: wrapEvent(onRequestFinishedWrappers)
          }
        },
        runtime: {
          onMessage: wrapEvent(onMessageWrappers),
          onMessageExternal: wrapEvent(onMessageWrappers),
          sendMessage: wrappedSendMessage.bind(null, "sendMessage", {
            minArgs: 1,
            maxArgs: 3
          })
        },
        tabs: {
          sendMessage: wrappedSendMessage.bind(null, "sendMessage", {
            minArgs: 2,
            maxArgs: 3
          })
        }
      };
      const settingMetadata = {
        clear: {
          minArgs: 1,
          maxArgs: 1
        },
        get: {
          minArgs: 1,
          maxArgs: 1
        },
        set: {
          minArgs: 1,
          maxArgs: 1
        }
      };
      apiMetadata.privacy = {
        network: {
          "*": settingMetadata
        },
        services: {
          "*": settingMetadata
        },
        websites: {
          "*": settingMetadata
        }
      };
      return wrapObject(extensionAPIs, staticWrappers, apiMetadata);
    };

    if (typeof chrome != "object" || !chrome || !chrome.runtime || !chrome.runtime.id) {
      throw new Error("This script should only be loaded in a browser extension.");
    } // The build process adds a UMD wrapper around this file, which makes the
    // `module` variable available.


    module.exports = wrapAPIs(chrome);
  } else {
    module.exports = browser;
  }
});


/***/ }),

/***/ 2480:
/***/ (() => {

/* (ignored) */

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			id: moduleId,
/******/ 			loaded: false,
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/compat get default export */
/******/ 	(() => {
/******/ 		// getDefaultExport function for compatibility with non-harmony modules
/******/ 		__webpack_require__.n = (module) => {
/******/ 			var getter = module && module.__esModule ?
/******/ 				() => (module['default']) :
/******/ 				() => (module);
/******/ 			__webpack_require__.d(getter, { a: getter });
/******/ 			return getter;
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/global */
/******/ 	(() => {
/******/ 		__webpack_require__.g = (function() {
/******/ 			if (typeof globalThis === 'object') return globalThis;
/******/ 			try {
/******/ 				return this || new Function('return this')();
/******/ 			} catch (e) {
/******/ 				if (typeof window === 'object') return window;
/******/ 			}
/******/ 		})();
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/node module decorator */
/******/ 	(() => {
/******/ 		__webpack_require__.nmd = (module) => {
/******/ 			module.paths = [];
/******/ 			if (!module.children) module.children = [];
/******/ 			return module;
/******/ 		};
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";

;// CONCATENATED MODULE: ./Extension/src/common/log.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable no-console */

/**
 * Simple logger with log levels
 */
const log = (() => {
  // Redefine if you need it
  const CURRENT_LEVEL = 'INFO';
  const LEVELS = {
    ERROR: 1,
    WARN: 2,
    INFO: 3,
    DEBUG: 4
  };
  /**
   * Pretty-print javascript error
   */

  const errorToString = function (error) {
    return `${error.toString()}\nStack trace:\n${error.stack}`;
  };

  const getLocalTimeString = date => {
    const ONE_MINUTE_MS = 60 * 1000;
    const timeZoneOffsetMs = date.getTimezoneOffset() * ONE_MINUTE_MS;
    const localTime = new Date(date - timeZoneOffsetMs);
    return localTime.toISOString().replace('Z', '');
  };
  /**
   * Prints log message
   */


  const print = function (level, method, args) {
    // check log level
    if (LEVELS[CURRENT_LEVEL] < LEVELS[level]) {
      return;
    }

    if (!args || args.length === 0 || !args[0]) {
      return;
    }

    const str = `${args[0]}`;
    args = Array.prototype.slice.call(args, 1);
    let formatted = str.replace(/{(\d+)}/g, (match, number) => {
      if (typeof args[number] !== 'undefined') {
        let value = args[number];

        if (value instanceof Error) {
          value = errorToString(value);
        } else if (value && value.message) {
          value = value.message;
        } else if (typeof value === 'object') {
          value = JSON.stringify(value);
        }

        return value;
      }

      return match;
    });
    formatted = `${getLocalTimeString(new Date())}: ${formatted}`;
    console[method](formatted);
  };
  /**
   * Expose public API
   */


  return {
    debug(...args) {
      print('DEBUG', 'log', args);
    },

    info(...args) {
      print('INFO', 'info', args);
    },

    warn(...args) {
      print('WARN', 'info', args);
    },

    error(...args) {
      print('ERROR', 'error', args);
    }

  };
})();
// EXTERNAL MODULE: ./node_modules/@adguard/tsurlfilter/dist/tsurlfilter.browser.js
var tsurlfilter_browser = __webpack_require__(4346);
;// CONCATENATED MODULE: ./node_modules/@adguard/tsurlfilter/dist/es/request-type.js
/**
 * RequestType is the request types enumeration
 */
var RequestType;
(function (RequestType) {
    /** main frame */
    RequestType[RequestType["Document"] = 1] = "Document";
    /** (iframe) $subdocument */
    RequestType[RequestType["Subdocument"] = 2] = "Subdocument";
    /** (javascript, etc) $script */
    RequestType[RequestType["Script"] = 4] = "Script";
    /** (css) $stylesheet */
    RequestType[RequestType["Stylesheet"] = 8] = "Stylesheet";
    /** (flash, etc) $object */
    RequestType[RequestType["Object"] = 16] = "Object";
    /** (any image) $image */
    RequestType[RequestType["Image"] = 32] = "Image";
    /** (ajax/fetch) $xmlhttprequest */
    RequestType[RequestType["XmlHttpRequest"] = 64] = "XmlHttpRequest";
    /** (video/music) $media */
    RequestType[RequestType["Media"] = 128] = "Media";
    /** (any custom font) $font */
    RequestType[RequestType["Font"] = 256] = "Font";
    /** (a websocket connection) $websocket */
    RequestType[RequestType["Websocket"] = 512] = "Websocket";
    /** (navigator.sendBeacon()) $ping */
    RequestType[RequestType["Ping"] = 1024] = "Ping";
    /** (webrtc, in extension works via wrappers) $webrtc */
    RequestType[RequestType["Webrtc"] = 2048] = "Webrtc";
    /** any other request type */
    RequestType[RequestType["Other"] = 4096] = "Other";
})(RequestType || (RequestType = {}));



;// CONCATENATED MODULE: ./Extension/src/background/utils/request-types.js

/**
 * Request types enumeration
 */

const RequestTypes = {
  /**
   * Document that is loaded for a top-level frame
   */
  DOCUMENT: 'DOCUMENT',

  /**
   * Document that is loaded for an embedded frame (iframe)
   */
  SUBDOCUMENT: 'SUBDOCUMENT',
  SCRIPT: 'SCRIPT',
  STYLESHEET: 'STYLESHEET',
  OBJECT: 'OBJECT',
  IMAGE: 'IMAGE',
  XMLHTTPREQUEST: 'XMLHTTPREQUEST',
  MEDIA: 'MEDIA',
  FONT: 'FONT',
  WEBSOCKET: 'WEBSOCKET',
  WEBRTC: 'WEBRTC',
  OTHER: 'OTHER',
  CSP: 'CSP',
  COOKIE: 'COOKIE',
  PING: 'PING',
  CSP_REPORT: 'CSP_REPORT',

  /**
   * Transforms to TSUrlFilter.RequestType
   *
   * @param requestType
   * @return {number}
   */
  transformRequestType(requestType) {
    const contentTypes = RequestTypes;

    switch (requestType) {
      case contentTypes.DOCUMENT:
        return RequestType.Document;

      case contentTypes.SUBDOCUMENT:
        return RequestType.Subdocument;

      case contentTypes.STYLESHEET:
        return RequestType.Stylesheet;

      case contentTypes.FONT:
        return RequestType.Font;

      case contentTypes.IMAGE:
        return RequestType.Image;

      case contentTypes.MEDIA:
        return RequestType.Media;

      case contentTypes.SCRIPT:
        return RequestType.Script;

      case contentTypes.XMLHTTPREQUEST:
        return RequestType.XmlHttpRequest;

      case contentTypes.WEBSOCKET:
        return RequestType.Websocket;

      case contentTypes.WEBRTC:
        return RequestType.Webrtc;

      case contentTypes.PING:
        return RequestType.Ping;

      default:
        return RequestType.Other;
    }
  },

  /**
   * Transforms from TSUrlFilter.RequestType
   *
   * @param requestType
   * @return {string}
   */
  transformRequestTypeFromTs(requestType) {
    const contentTypes = RequestTypes;

    switch (requestType) {
      case RequestType.Document:
        return contentTypes.DOCUMENT;

      case RequestType.Subdocument:
        return contentTypes.SUBDOCUMENT;

      case RequestType.Stylesheet:
        return contentTypes.STYLESHEET;

      case RequestType.Font:
        return contentTypes.FONT;

      case RequestType.Image:
        return contentTypes.IMAGE;

      case RequestType.Media:
        return contentTypes.MEDIA;

      case RequestType.Script:
        return contentTypes.SCRIPT;

      case RequestType.XmlHttpRequest:
        return contentTypes.XMLHTTPREQUEST;

      case RequestType.Websocket:
        return contentTypes.WEBSOCKET;

      case RequestType.Ping:
        return contentTypes.PING;

      default:
        return contentTypes.OTHER;
    }
  }

};
/**
 * Parse content type from path
 * @param path Path
 * @returns {*} content type (RequestTypes.*) or null
 */

function parseContentTypeFromUrlPath(path) {
  const objectContentTypes = '.jar.swf.';
  const mediaContentTypes = '.mp4.flv.avi.m3u.webm.mpeg.3gp.3gpp.3g2.3gpp2.ogg.mov.qt.';
  const fontContentTypes = '.ttf.otf.woff.woff2.eot.';
  const imageContentTypes = '.ico.png.gif.jpg.jpeg.webp.';
  let ext = path.slice(-6);
  const pos = ext.lastIndexOf('.'); // Unable to parse extension from url

  if (pos === -1) {
    return null;
  }

  ext = `${ext.slice(pos)}.`;

  if (objectContentTypes.indexOf(ext) !== -1) {
    return RequestTypes.OBJECT;
  }

  if (mediaContentTypes.indexOf(ext) !== -1) {
    return RequestTypes.MEDIA;
  }

  if (fontContentTypes.indexOf(ext) !== -1) {
    return RequestTypes.FONT;
  }

  if (imageContentTypes.indexOf(ext) !== -1) {
    return RequestTypes.IMAGE;
  }

  return null;
}
;// CONCATENATED MODULE: ./Extension/src/common/strings.js
/**
 * Util class for work with strings
 */
const strings = (() => {
  const StringUtils = {
    isEmpty(str) {
      return !str || str.trim().length === 0;
    },

    startWith(str, prefix) {
      return str && str.indexOf(prefix) === 0;
    },

    endsWith(str, postfix) {
      return str.endsWith(postfix);
    },

    substringAfter(str, separator) {
      if (!str) {
        return str;
      }

      const index = str.indexOf(separator);
      return index < 0 ? '' : str.substring(index + separator.length);
    },

    substringBefore(str, separator) {
      if (!str || !separator) {
        return str;
      }

      const index = str.indexOf(separator);
      return index < 0 ? str : str.substring(0, index);
    },

    contains(str, searchString) {
      return str && str.indexOf(searchString) >= 0;
    },

    containsIgnoreCase(str, searchString) {
      return str && searchString && str.toUpperCase().indexOf(searchString.toUpperCase()) >= 0;
    },

    replaceAll(str, find, replace) {
      if (!str) {
        return str;
      }

      return str.split(find).join(replace);
    },

    join(array, separator, startIndex, endIndex) {
      if (!array) {
        return null;
      }

      if (!startIndex) {
        startIndex = 0;
      }

      if (!endIndex) {
        endIndex = array.length;
      }

      if (startIndex >= endIndex) {
        return '';
      }

      const buf = [];

      for (let i = startIndex; i < endIndex; i += 1) {
        buf.push(array[i]);
      }

      return buf.join(separator);
    },

    /**
     * Get string before regexp first match
     * @param {string} str
     * @param {RegExp} rx
     */
    getBeforeRegExp(str, rx) {
      const index = str.search(rx);
      return str.substring(0, index);
    },

    /**
     * Look for any symbol from "chars" array starting at "start" index or from the start of the string
     *
     * @param str   String to search
     * @param chars Chars to search for
     * @param start Start index (optional, inclusive)
     * @return int Index of the element found or null
     */
    indexOfAny(str, chars, start) {
      start = start || 0;

      if (typeof str === 'string' && str.length <= start) {
        return -1;
      }

      for (let i = start; i < str.length; i += 1) {
        const c = str.charAt(i);

        if (chars.indexOf(c) > -1) {
          return i;
        }
      }

      return -1;
    },

    /**
     * Splits string by a delimiter, ignoring escaped delimiters
     * @param str               String to split
     * @param delimiter         Delimiter
     * @param escapeCharacter   Escape character
     * @param preserveAllTokens If true - preserve empty entries.
     */
    splitByDelimiterWithEscapeCharacter(str, delimiter, escapeCharacter, preserveAllTokens) {
      const parts = [];

      if (this.isEmpty(str)) {
        return parts;
      }

      let sb = [];

      for (let i = 0; i < str.length; i += 1) {
        const c = str.charAt(i);

        if (c === delimiter) {
          if (i === 0) {// Ignore
          } else if (str.charAt(i - 1) === escapeCharacter) {
            sb.splice(sb.length - 1, 1);
            sb.push(c);
          } else if (preserveAllTokens || sb.length > 0) {
            const part = sb.join('');
            parts.push(part);
            sb = [];
          }
        } else {
          sb.push(c);
        }
      }

      if (preserveAllTokens || sb.length > 0) {
        parts.push(sb.join(''));
      }

      return parts;
    },

    /**
     * Serialize HTML element
     * @param element
     */
    elementToString(element) {
      const s = [];
      s.push('<');
      s.push(element.localName);
      const {
        attributes
      } = element;

      for (let i = 0; i < attributes.length; i += 1) {
        const attr = attributes[i];
        s.push(' ');
        s.push(attr.name);
        s.push('="');
        const value = attr.value === null ? '' : attr.value.replace(/"/g, '\\"');
        s.push(value);
        s.push('"');
      }

      s.push('>');
      return s.join('');
    },

    /**
     * Checks if the specified string starts with a substr at the specified index.
     * @param str - String to check
     * @param startIndex - Index to start checking from
     * @param substr - Substring to check
     * @return boolean true if it does start
     */
    startsAtIndexWith(str, startIndex, substr) {
      if (str.length - startIndex < substr.length) {
        return false;
      }

      for (let i = 0; i < substr.length; i += 1) {
        if (str.charAt(startIndex + i) !== substr.charAt(i)) {
          return false;
        }
      }

      return true;
    },

    /**
     * Checks if str has unquoted substr
     * @param str
     * @param substr
     */
    hasUnquotedSubstring(str, substr) {
      const quotes = ['"', "'", '/'];
      const stack = [];

      for (let i = 0; i < str.length; i += 1) {
        const cursor = str[i];

        if (stack.length === 0) {
          if (this.startsAtIndexWith(str, i, substr)) {
            return true;
          }
        }

        if (quotes.indexOf(cursor) >= 0 && (i === 0 || str[i - 1] !== '\\')) {
          const last = stack.pop();

          if (!last) {
            stack.push(cursor);
          } else if (last !== cursor) {
            stack.push(last);
            stack.push(cursor);
          }
        }
      }

      return false;
    }

  };
  return StringUtils;
})();
;// CONCATENATED MODULE: ./Extension/src/background/utils/dates.js
/**
 * Util class for dates
 */
const dates = function () {
  const DateUtils = {
    isSameHour(a, b) {
      return this.isSameDay(a, b) && a.getHours() === b.getHours();
    },

    isSameDay(a, b) {
      return this.isSameMonth(a, b) && a.getDate() === b.getDate();
    },

    isSameMonth(a, b) {
      if (!a || !b) {
        return false;
      }

      return a.getYear() === b.getYear() && a.getMonth() === b.getMonth();
    },

    getDifferenceInHours(a, b) {
      return (a.getTime() - b.getTime()) / 1000 / 60 / 60;
    },

    getDifferenceInDays(a, b) {
      return this.getDifferenceInHours(a, b) / 24;
    },

    getDifferenceInMonths(a, b) {
      return this.getDifferenceInDays(a, b) / 30;
    }

  };
  return DateUtils;
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/collections.js
/**
 * Util class for work with collections
 */
const collections = (() => {
  const CollectionUtils = {
    remove(collection, element) {
      if (!element || !collection) {
        return;
      }

      const index = collection.indexOf(element);

      if (index >= 0) {
        collection.splice(index, 1);
      }
    },

    removeAll(collection, element) {
      if (!element || !collection) {
        return;
      }

      for (let i = collection.length - 1; i >= 0; i -= 1) {
        if (collection[i] === element) {
          collection.splice(i, 1);
        }
      }
    },

    /**
     * Removes elements from collection if predicate returns true
     * @param collection
     * @param predicate
     */
    removeBy(collection, predicate) {
      if (!predicate || !collection) {
        return;
      }

      for (let i = collection.length - 1; i >= 0; i -= 1) {
        if (predicate(collection[i])) {
          collection.splice(i, 1);
        }
      }
    },

    removeRule(collection, rule) {
      if (!rule || !collection) {
        return;
      }

      for (let i = collection.length - 1; i >= 0; i -= 1) {
        if (rule.getText() === collection[i].getText()) {
          collection.splice(i, 1);
        }
      }
    },

    removeDuplicates(arr) {
      if (!arr || arr.length === 1) {
        return arr;
      }

      return arr.filter((elem, pos) => arr.indexOf(elem) === pos);
    },

    getRulesText(collection) {
      const text = [];

      if (!collection) {
        return text;
      }

      for (let i = 0; i < collection.length; i += 1) {
        text.push(collection[i].getText());
      }

      return text;
    },

    /**
     * Find element in array by property
     * @param array
     * @param property
     * @param value
     * @returns {*}
     */
    find(array, property, value) {
      if (typeof array.find === 'function') {
        return array.find(a => a[property] === value);
      }

      for (let i = 0; i < array.length; i += 1) {
        const elem = array[i];

        if (elem[property] === value) {
          return elem;
        }
      }

      return null;
    },

    /**
     * Checks if specified object is array
     * We don't use instanceof because it is too slow: http://jsperf.com/instanceof-performance/2
     * @param obj Object
     */
    isArray: Array.isArray || function (obj) {
      return `${obj}` === '[object Array]';
    },

    /**
     * Returns array elements of a, which is not included in b
     *
     * @param a
     * @param b
     */
    getArraySubtraction(a, b) {
      return a.filter(i => b.indexOf(i) < 0);
    }

  };
  return CollectionUtils;
})();
;// CONCATENATED MODULE: ./Extension/src/background/utils/concurrent.js
/* eslint-disable prefer-rest-params */

/**
 * Util class for support timeout, retry operations, debounce
 */
const concurrent = function () {
  const ConcurrentUtils = {
    runAsync(callback, context) {
      const params = Array.prototype.slice.call(arguments, 2);
      setTimeout(() => {
        callback.apply(context, params);
      }, 0);
    },

    retryUntil(predicate, main, details) {
      if (typeof details !== 'object') {
        details = {};
      }

      let now = 0;
      const next = details.next || 200;
      const until = details.until || 2000;

      const check = function () {
        if (predicate() === true || now >= until) {
          main();
          return;
        }

        now += next;
        setTimeout(check, next);
      };

      setTimeout(check, 1);
    },

    debounce(func, wait) {
      let timeout;
      return function () {
        const context = this;
        const args = arguments;

        const later = function () {
          timeout = null;
          func.apply(context, args);
        };

        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    },

    /**
     * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.
     * https://github.com/component/throttle
     *
     * @param {Function} func Function to wrap.
     * @param {Number} wait Number of milliseconds that must elapse between `func` invocations.
     * @return {Function} A new function that wraps the `func` function passed in.
     */
    throttle(func, wait) {
      let ctx;
      let args;
      let rtn;
      let timeoutID; // caching

      let last = 0;

      function call() {
        timeoutID = 0;
        last = +new Date();
        rtn = func.apply(ctx, args);
        ctx = null;
        args = null;
      }

      return function throttled() {
        ctx = this;
        args = arguments;
        const delta = new Date() - last;

        if (!timeoutID) {
          if (delta >= wait) {
            call();
          } else {
            timeoutID = setTimeout(call, wait - delta);
          }
        }

        return rtn;
      };
    }

  };
  return ConcurrentUtils;
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/channels.js
/* eslint-disable prefer-rest-params */

/**
 * Simple publish-subscribe implementation
 */
const channels = (() => {
  const EventChannels = (() => {
    const EventChannel = function () {
      let listeners = null;
      let listenerCallback = null;

      const addListener = function (callback) {
        if (typeof callback !== 'function') {
          throw new Error('Illegal callback');
        }

        if (listeners !== null) {
          listeners.push(callback);
          return;
        }

        if (listenerCallback !== null) {
          listeners = [];
          listeners.push(listenerCallback);
          listeners.push(callback);
          listenerCallback = null;
        } else {
          listenerCallback = callback;
        }
      };

      const removeListener = function (callback) {
        if (listenerCallback !== null) {
          listenerCallback = null;
        } else {
          const index = listeners.indexOf(callback);

          if (index >= 0) {
            listeners.splice(index, 1);
          }
        }
      };

      const notify = function () {
        if (listenerCallback !== null) {
          return listenerCallback.apply(listenerCallback, arguments);
        }

        if (listeners !== null) {
          for (let i = 0; i < listeners.length; i += 1) {
            const listener = listeners[i];
            listener.apply(listener, arguments);
          }
        }
      };

      const notifyInReverseOrder = function () {
        if (listenerCallback !== null) {
          return listenerCallback.apply(listenerCallback, arguments);
        }

        if (listeners !== null) {
          for (let i = listeners.length - 1; i >= 0; i -= 1) {
            const listener = listeners[i];
            listener.apply(listener, arguments);
          }
        }
      };

      return {
        addListener,
        removeListener,
        notify,
        notifyInReverseOrder
      };
    };

    const namedChannels = Object.create(null);

    const newChannel = function () {
      return new EventChannel();
    };

    const newNamedChannel = function (name) {
      const channel = newChannel();
      namedChannels[name] = channel;
      return channel;
    };

    const getNamedChannel = function (name) {
      return namedChannels[name];
    };

    return {
      newChannel,
      newNamedChannel,
      getNamedChannel
    };
  })();

  return EventChannels;
})();
;// CONCATENATED MODULE: ./Extension/src/background/utils/workaround.js
/**
 * We collect here all workarounds and ugly hacks:)
 */
const workaround = function () {
  const WorkaroundUtils = {
    /**
     * Converts blocked counter to the badge text.
     * Workaround for FF - make 99 max.
     *
     * @param blocked Blocked requests count
     */
    getBlockedCountText(blocked) {
      let blockedText = blocked === '0' ? '' : blocked;

      if (blocked - 0 > 99) {
        blockedText = '\u221E';
      }

      return blockedText;
    }

  };
  return WorkaroundUtils;
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/i18n.js

/**
 * Simple i18n utils
 */

const i18n = function () {
  function isArrayElement(array, elem) {
    return array.indexOf(elem) >= 0;
  }

  function isObjectKey(object, key) {
    return key in object;
  }

  return {
    /**
     * Tries to find locale in the given collection of locales
     * @param locales Collection of locales (array or object)
     * @param locale Locale (e.g. en, en_GB, pt_BR)
     * @returns matched locale from the locales collection or null
     */
    normalize(locales, locale) {
      if (!locale) {
        return null;
      } // Transform Language-Country => Language_Country


      locale = locale.replace('-', '_');
      let search;

      if (collections.isArray(locales)) {
        search = isArrayElement;
      } else {
        search = isObjectKey;
      }

      if (search(locales, locale)) {
        return locale;
      } // Try to search by the language


      const parts = locale.split('_');
      const language = parts[0];

      if (search(locales, language)) {
        return language;
      }

      return null;
    }

  };
}();
;// CONCATENATED MODULE: ./Extension/src/common/constants.js
/**
 * Filter ids used in the code on the background page and filtering log page
 */
const ANTIBANNER_FILTERS_ID = {
  STEALTH_MODE_FILTER_ID: -1,
  USER_FILTER_ID: 0,
  RUSSIAN_FILTER_ID: 1,
  ENGLISH_FILTER_ID: 2,
  TRACKING_FILTER_ID: 3,
  SOCIAL_FILTER_ID: 4,
  SEARCH_AND_SELF_PROMO_FILTER_ID: 10,
  URL_TRACKING_FILTER_ID: 17,
  ALLOWLIST_FILTER_ID: 100,
  EASY_PRIVACY: 118,
  FANBOY_ANNOYANCES: 122,
  FANBOY_SOCIAL: 123,
  FANBOY_ENHANCED: 215,
  MOBILE_ADS_FILTER_ID: 11
};
/**
 * Group ids used in the code on the multiple entry points
 */

const ANTIBANNER_GROUPS_ID = {
  // custom filters group identifier
  CUSTOM_FILTERS_GROUP_ID: 0,
  PRIVACY_FILTERS_GROUP_ID: 2,
  // other filters group identifier
  OTHER_FILTERS_GROUP_ID: 6,
  // language-specific group identifier
  LANGUAGE_FILTERS_GROUP_ID: 7
};
/**
 * Stealth action bitwise masks used o the background page and on the filtering log page
 */

const STEALTH_ACTIONS = {
  HIDE_REFERRER: 1 << 0,
  HIDE_SEARCH_QUERIES: 1 << 1,
  BLOCK_CHROME_CLIENT_DATA: 1 << 2,
  SEND_DO_NOT_TRACK: 1 << 3,
  STRIPPED_TRACKING_URL: 1 << 4,
  FIRST_PARTY_COOKIES: 1 << 5,
  THIRD_PARTY_COOKIES: 1 << 6
};
/**
 * Message types used for message passing between background page and
 * other pages (popup, filtering log, content scripts)
 */

const MESSAGE_TYPES = {
  CREATE_EVENT_LISTENER: 'createEventListener',
  REMOVE_LISTENER: 'removeListener',
  OPEN_EXTENSION_STORE: 'openExtensionStore',
  ADD_AND_ENABLE_FILTER: 'addAndEnableFilter',
  APPLY_SETTINGS_JSON: 'applySettingsJson',
  OPEN_FILTERING_LOG: 'openFilteringLog',
  SET_FILTERING_LOG_WINDOW_STATE: 'setFilteringLogWindowState',
  OPEN_FULLSCREEN_USER_RULES: 'openFullscreenUserRules',
  RESET_BLOCKED_ADS_COUNT: 'resetBlockedAdsCount',
  RESET_SETTINGS: 'resetSettings',
  GET_USER_RULES: 'getUserRules',
  SAVE_USER_RULES: 'saveUserRules',
  GET_ALLOWLIST_DOMAINS: 'getAllowlistDomains',
  SAVE_ALLOWLIST_DOMAINS: 'saveAllowlistDomains',
  CHECK_ANTIBANNER_FILTERS_UPDATE: 'checkAntiBannerFiltersUpdate',
  DISABLE_FILTERS_GROUP: 'disableFiltersGroup',
  DISABLE_ANTIBANNER_FILTER: 'disableAntiBannerFilter',
  LOAD_CUSTOM_FILTER_INFO: 'loadCustomFilterInfo',
  SUBSCRIBE_TO_CUSTOM_FILTER: 'subscribeToCustomFilter',
  REMOVE_ANTIBANNER_FILTER: 'removeAntiBannerFilter',
  GET_TAB_INFO_FOR_POPUP: 'getTabInfoForPopup',
  CHANGE_APPLICATION_FILTERING_DISABLED: 'changeApplicationFilteringDisabled',
  OPEN_SETTINGS_TAB: 'openSettingsTab',
  OPEN_ASSISTANT: 'openAssistant',
  OPEN_ABUSE_TAB: 'openAbuseTab',
  OPEN_SITE_REPORT_TAB: 'openSiteReportTab',
  RESET_CUSTOM_RULES_FOR_PAGE: 'resetCustomRulesForPage',
  REMOVE_ALLOWLIST_DOMAIN: 'removeAllowlistDomainPopup',
  ADD_ALLOWLIST_DOMAIN_POPUP: 'addAllowlistDomainPopup',
  GET_STATISTICS_DATA: 'getStatisticsData',
  ON_OPEN_FILTERING_LOG_PAGE: 'onOpenFilteringLogPage',
  GET_FILTERING_LOG_DATA: 'getFilteringLogData',
  INITIALIZE_FRAME_SCRIPT: 'initializeFrameScript',
  ON_CLOSE_FILTERING_LOG_PAGE: 'onCloseFilteringLogPage',
  GET_FILTERING_INFO_BY_TAB_ID: 'getFilteringInfoByTabId',
  SYNCHRONIZE_OPEN_TABS: 'synchronizeOpenTabs',
  CLEAR_EVENTS_BY_TAB_ID: 'clearEventsByTabId',
  REFRESH_PAGE: 'refreshPage',
  OPEN_TAB: 'openTab',
  CONTENT_SCRIPT_ADD_USER_RULE: 'contentScriptAddUserRule',
  FILTERING_LOG_ADD_USER_RULE: 'filteringLogAddUserRule',
  DEVTOOLS_ADD_USER_RULE: 'devtoolsAddUserRule',
  UN_ALLOWLIST_FRAME: 'unAllowlistFrame',
  REMOVE_USER_RULE: 'removeUserRule',
  GET_TAB_FRAME_INFO_BY_ID: 'getTabFrameInfoById',
  ENABLE_FILTERS_GROUP: 'enableFiltersGroup',
  NOTIFY_LISTENERS: 'notifyListeners',
  ADD_LONG_LIVED_CONNECTION: 'addLongLivedConnection',
  GET_OPTIONS_DATA: 'getOptionsData',
  CHANGE_USER_SETTING: 'changeUserSetting',
  CHECK_REQUEST_FILTER_READY: 'checkRequestFilterReady',
  OPEN_THANKYOU_PAGE: 'openThankYouPage',
  OPEN_SAFEBROWSING_TRUSTED: 'openSafebrowsingTrusted',
  GET_SELECTORS_AND_SCRIPTS: 'getSelectorsAndScripts',
  CHECK_PAGE_SCRIPT_WRAPPER_REQUEST: 'checkPageScriptWrapperRequest',
  PROCESS_SHOULD_COLLAPSE: 'processShouldCollapse',
  PROCESS_SHOULD_COLLAPSE_MANY: 'processShouldCollapseMany',
  ADD_FILTERING_SUBSCRIPTION: 'addFilterSubscription',
  SET_NOTIFICATION_VIEWED: 'setNotificationViewed',
  SAVE_CSS_HITS_STATS: 'saveCssHitStats',
  GET_COOKIE_RULES: 'getCookieRules',
  SAVE_COOKIE_LOG_EVENT: 'saveCookieRuleEvent',
  LOAD_SETTINGS_JSON: 'loadSettingsJson',
  ADD_URL_TO_TRUSTED: 'addUrlToTrusted',
  SET_PRESERVE_LOG_STATE: 'setPreserveLogState',
  GET_USER_RULES_EDITOR_DATA: 'getUserRulesEditorData',
  GET_EDITOR_STORAGE_CONTENT: 'getEditorStorageContent',
  SET_EDITOR_STORAGE_CONTENT: 'setEditorStorageContent',
  CONVERT_RULES_TEXT: 'convertRulesText'
};
const NOTIFIER_TYPES = {
  ADD_RULES: 'event.add.rules',
  REMOVE_RULE: 'event.remove.rule',
  UPDATE_FILTER_RULES: 'event.update.filter.rules',
  FILTER_GROUP_ENABLE_DISABLE: 'filter.group.enable.disable',
  // enabled or disabled filter group
  FILTER_ENABLE_DISABLE: 'event.filter.enable.disable',
  // Enabled or disabled
  FILTER_ADD_REMOVE: 'event.filter.add.remove',
  // Added or removed
  ADS_BLOCKED: 'event.ads.blocked',
  START_DOWNLOAD_FILTER: 'event.start.download.filter',
  SUCCESS_DOWNLOAD_FILTER: 'event.success.download.filter',
  ERROR_DOWNLOAD_FILTER: 'event.error.download.filter',
  ENABLE_FILTER_SHOW_POPUP: 'event.enable.filter.show.popup',
  LOG_EVENT: 'event.log.track',
  UPDATE_TAB_BUTTON_STATE: 'event.update.tab.button.state',
  REQUEST_FILTER_UPDATED: 'event.request.filter.updated',
  APPLICATION_INITIALIZED: 'event.application.initialized',
  APPLICATION_UPDATED: 'event.application.updated',
  CHANGE_PREFS: 'event.change.prefs',
  UPDATE_FILTERS_SHOW_POPUP: 'event.update.filters.show.popup',
  USER_FILTER_UPDATED: 'event.user.filter.updated',
  UPDATE_ALLOWLIST_FILTER_RULES: 'event.update.allowlist.filter.rules',
  SETTING_UPDATED: 'event.update.setting.value',
  FILTERS_UPDATE_CHECK_READY: 'event.update.filters.check',
  // Log events
  TAB_ADDED: 'log.tab.added',
  TAB_CLOSE: 'log.tab.close',
  TAB_UPDATE: 'log.tab.update',
  TAB_RESET: 'log.tab.reset',
  LOG_EVENT_ADDED: 'log.event.added',
  // Sync events
  SETTINGS_UPDATED: 'event.sync.finished',
  // Fullscreen user rules events
  FULLSCREEN_USER_RULES_EDITOR_UPDATED: 'event.user.rules.editor.updated'
};
const FULLSCREEN_USER_RULES_EDITOR = 'fullscreen_user_rules_editor';
const FILTERING_LOG = 'filtering-log';
const NAVIGATION_TAGS = {
  REGULAR: 'regular',
  PARTY: 'party'
};
/**
 * Trusted tag for custom filters
 */

const TRUSTED_TAG = 'trusted';
/**
 * Custom filters group display number
 *
 * @type {number}
 */

const CUSTOM_FILTERS_GROUP_DISPLAY_NUMBER = 99;
/**
 * Custom filters identifiers starts from this number
 *
 * @type {number}
 */

const CUSTOM_FILTERS_START_ID = 1000; // Unnecessary characters that will be replaced

const WASTE_CHARACTERS = /[.*+?^${}()|[\]\\]/g; // Custom scrollbar width

const SCROLLBAR_WIDTH = 12;
;// CONCATENATED MODULE: ./Extension/src/background/utils/filters.js

/**
 * Util class for detect filter type. Includes various filter identifiers
 */

const filters = (() => {
  const FilterUtils = {
    isUserFilterRule(rule) {
      return rule.getFilterListId() === ANTIBANNER_FILTERS_ID.USER_FILTER_ID;
    },

    isAllowlistFilterRule(rule) {
      return rule.getFilterListId() === ANTIBANNER_FILTERS_ID.ALLOWLIST_FILTER_ID;
    }

  }; // Make accessible only constants without functions. They will be passed to content-page

  FilterUtils.ids = ANTIBANNER_FILTERS_ID; // Copy filter ids to api

  Object.keys(ANTIBANNER_FILTERS_ID).forEach(key => {
    FilterUtils[key] = ANTIBANNER_FILTERS_ID[key];
  });
  return FilterUtils;
})();
;// CONCATENATED MODULE: ./node_modules/punycode/punycode.es6.js


/** Highest positive signed 32-bit float value */
const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1

/** Bootstring parameters */
const base = 36;
const tMin = 1;
const tMax = 26;
const skew = 38;
const damp = 700;
const initialBias = 72;
const initialN = 128; // 0x80
const delimiter = '-'; // '\x2D'

/** Regular expressions */
const regexPunycode = /^xn--/;
const regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators

/** Error messages */
const errors = {
	'overflow': 'Overflow: input needs wider integers to process',
	'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
	'invalid-input': 'Invalid input'
};

/** Convenience shortcuts */
const baseMinusTMin = base - tMin;
const floor = Math.floor;
const stringFromCharCode = String.fromCharCode;

/*--------------------------------------------------------------------------*/

/**
 * A generic error utility function.
 * @private
 * @param {String} type The error type.
 * @returns {Error} Throws a `RangeError` with the applicable error message.
 */
function error(type) {
	throw new RangeError(errors[type]);
}

/**
 * A generic `Array#map` utility function.
 * @private
 * @param {Array} array The array to iterate over.
 * @param {Function} callback The function that gets called for every array
 * item.
 * @returns {Array} A new array of values returned by the callback function.
 */
function map(array, fn) {
	const result = [];
	let length = array.length;
	while (length--) {
		result[length] = fn(array[length]);
	}
	return result;
}

/**
 * A simple `Array#map`-like wrapper to work with domain name strings or email
 * addresses.
 * @private
 * @param {String} domain The domain name or email address.
 * @param {Function} callback The function that gets called for every
 * character.
 * @returns {Array} A new string of characters returned by the callback
 * function.
 */
function mapDomain(string, fn) {
	const parts = string.split('@');
	let result = '';
	if (parts.length > 1) {
		// In email addresses, only the domain name should be punycoded. Leave
		// the local part (i.e. everything up to `@`) intact.
		result = parts[0] + '@';
		string = parts[1];
	}
	// Avoid `split(regex)` for IE8 compatibility. See #17.
	string = string.replace(regexSeparators, '\x2E');
	const labels = string.split('.');
	const encoded = map(labels, fn).join('.');
	return result + encoded;
}

/**
 * Creates an array containing the numeric code points of each Unicode
 * character in the string. While JavaScript uses UCS-2 internally,
 * this function will convert a pair of surrogate halves (each of which
 * UCS-2 exposes as separate characters) into a single code point,
 * matching UTF-16.
 * @see `punycode.ucs2.encode`
 * @see <https://mathiasbynens.be/notes/javascript-encoding>
 * @memberOf punycode.ucs2
 * @name decode
 * @param {String} string The Unicode input string (UCS-2).
 * @returns {Array} The new array of code points.
 */
function ucs2decode(string) {
	const output = [];
	let counter = 0;
	const length = string.length;
	while (counter < length) {
		const value = string.charCodeAt(counter++);
		if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
			// It's a high surrogate, and there is a next character.
			const extra = string.charCodeAt(counter++);
			if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
				output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
			} else {
				// It's an unmatched surrogate; only append this code unit, in case the
				// next code unit is the high surrogate of a surrogate pair.
				output.push(value);
				counter--;
			}
		} else {
			output.push(value);
		}
	}
	return output;
}

/**
 * Creates a string based on an array of numeric code points.
 * @see `punycode.ucs2.decode`
 * @memberOf punycode.ucs2
 * @name encode
 * @param {Array} codePoints The array of numeric code points.
 * @returns {String} The new Unicode string (UCS-2).
 */
const ucs2encode = array => String.fromCodePoint(...array);

/**
 * Converts a basic code point into a digit/integer.
 * @see `digitToBasic()`
 * @private
 * @param {Number} codePoint The basic numeric code point value.
 * @returns {Number} The numeric value of a basic code point (for use in
 * representing integers) in the range `0` to `base - 1`, or `base` if
 * the code point does not represent a value.
 */
const basicToDigit = function(codePoint) {
	if (codePoint - 0x30 < 0x0A) {
		return codePoint - 0x16;
	}
	if (codePoint - 0x41 < 0x1A) {
		return codePoint - 0x41;
	}
	if (codePoint - 0x61 < 0x1A) {
		return codePoint - 0x61;
	}
	return base;
};

/**
 * Converts a digit/integer into a basic code point.
 * @see `basicToDigit()`
 * @private
 * @param {Number} digit The numeric value of a basic code point.
 * @returns {Number} The basic code point whose value (when used for
 * representing integers) is `digit`, which needs to be in the range
 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
 * used; else, the lowercase form is used. The behavior is undefined
 * if `flag` is non-zero and `digit` has no uppercase form.
 */
const digitToBasic = function(digit, flag) {
	//  0..25 map to ASCII a..z or A..Z
	// 26..35 map to ASCII 0..9
	return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
};

/**
 * Bias adaptation function as per section 3.4 of RFC 3492.
 * https://tools.ietf.org/html/rfc3492#section-3.4
 * @private
 */
const adapt = function(delta, numPoints, firstTime) {
	let k = 0;
	delta = firstTime ? floor(delta / damp) : delta >> 1;
	delta += floor(delta / numPoints);
	for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
		delta = floor(delta / baseMinusTMin);
	}
	return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
};

/**
 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
 * symbols.
 * @memberOf punycode
 * @param {String} input The Punycode string of ASCII-only symbols.
 * @returns {String} The resulting string of Unicode symbols.
 */
const decode = function(input) {
	// Don't use UCS-2.
	const output = [];
	const inputLength = input.length;
	let i = 0;
	let n = initialN;
	let bias = initialBias;

	// Handle the basic code points: let `basic` be the number of input code
	// points before the last delimiter, or `0` if there is none, then copy
	// the first basic code points to the output.

	let basic = input.lastIndexOf(delimiter);
	if (basic < 0) {
		basic = 0;
	}

	for (let j = 0; j < basic; ++j) {
		// if it's not a basic code point
		if (input.charCodeAt(j) >= 0x80) {
			error('not-basic');
		}
		output.push(input.charCodeAt(j));
	}

	// Main decoding loop: start just after the last delimiter if any basic code
	// points were copied; start at the beginning otherwise.

	for (let index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {

		// `index` is the index of the next character to be consumed.
		// Decode a generalized variable-length integer into `delta`,
		// which gets added to `i`. The overflow checking is easier
		// if we increase `i` as we go, then subtract off its starting
		// value at the end to obtain `delta`.
		let oldi = i;
		for (let w = 1, k = base; /* no condition */; k += base) {

			if (index >= inputLength) {
				error('invalid-input');
			}

			const digit = basicToDigit(input.charCodeAt(index++));

			if (digit >= base || digit > floor((maxInt - i) / w)) {
				error('overflow');
			}

			i += digit * w;
			const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);

			if (digit < t) {
				break;
			}

			const baseMinusT = base - t;
			if (w > floor(maxInt / baseMinusT)) {
				error('overflow');
			}

			w *= baseMinusT;

		}

		const out = output.length + 1;
		bias = adapt(i - oldi, out, oldi == 0);

		// `i` was supposed to wrap around from `out` to `0`,
		// incrementing `n` each time, so we'll fix that now:
		if (floor(i / out) > maxInt - n) {
			error('overflow');
		}

		n += floor(i / out);
		i %= out;

		// Insert `n` at position `i` of the output.
		output.splice(i++, 0, n);

	}

	return String.fromCodePoint(...output);
};

/**
 * Converts a string of Unicode symbols (e.g. a domain name label) to a
 * Punycode string of ASCII-only symbols.
 * @memberOf punycode
 * @param {String} input The string of Unicode symbols.
 * @returns {String} The resulting Punycode string of ASCII-only symbols.
 */
const encode = function(input) {
	const output = [];

	// Convert the input in UCS-2 to an array of Unicode code points.
	input = ucs2decode(input);

	// Cache the length.
	let inputLength = input.length;

	// Initialize the state.
	let n = initialN;
	let delta = 0;
	let bias = initialBias;

	// Handle the basic code points.
	for (const currentValue of input) {
		if (currentValue < 0x80) {
			output.push(stringFromCharCode(currentValue));
		}
	}

	let basicLength = output.length;
	let handledCPCount = basicLength;

	// `handledCPCount` is the number of code points that have been handled;
	// `basicLength` is the number of basic code points.

	// Finish the basic string with a delimiter unless it's empty.
	if (basicLength) {
		output.push(delimiter);
	}

	// Main encoding loop:
	while (handledCPCount < inputLength) {

		// All non-basic code points < n have been handled already. Find the next
		// larger one:
		let m = maxInt;
		for (const currentValue of input) {
			if (currentValue >= n && currentValue < m) {
				m = currentValue;
			}
		}

		// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
		// but guard against overflow.
		const handledCPCountPlusOne = handledCPCount + 1;
		if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
			error('overflow');
		}

		delta += (m - n) * handledCPCountPlusOne;
		n = m;

		for (const currentValue of input) {
			if (currentValue < n && ++delta > maxInt) {
				error('overflow');
			}
			if (currentValue == n) {
				// Represent delta as a generalized variable-length integer.
				let q = delta;
				for (let k = base; /* no condition */; k += base) {
					const t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
					if (q < t) {
						break;
					}
					const qMinusT = q - t;
					const baseMinusT = base - t;
					output.push(
						stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
					);
					q = floor(qMinusT / baseMinusT);
				}

				output.push(stringFromCharCode(digitToBasic(q, 0)));
				bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
				delta = 0;
				++handledCPCount;
			}
		}

		++delta;
		++n;

	}
	return output.join('');
};

/**
 * Converts a Punycode string representing a domain name or an email address
 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
 * it doesn't matter if you call it on a string that has already been
 * converted to Unicode.
 * @memberOf punycode
 * @param {String} input The Punycoded domain name or email address to
 * convert to Unicode.
 * @returns {String} The Unicode representation of the given Punycode
 * string.
 */
const toUnicode = function(input) {
	return mapDomain(input, function(string) {
		return regexPunycode.test(string)
			? decode(string.slice(4).toLowerCase())
			: string;
	});
};

/**
 * Converts a Unicode string representing a domain name or an email address to
 * Punycode. Only the non-ASCII parts of the domain name will be converted,
 * i.e. it doesn't matter if you call it with a domain that's already in
 * ASCII.
 * @memberOf punycode
 * @param {String} input The domain name or email address to convert, as a
 * Unicode string.
 * @returns {String} The Punycode representation of the given domain name or
 * email address.
 */
const toASCII = function(input) {
	return mapDomain(input, function(string) {
		return regexNonASCII.test(string)
			? 'xn--' + encode(string)
			: string;
	});
};

/*--------------------------------------------------------------------------*/

/** Define the public API */
const punycode = {
	/**
	 * A string representing the current Punycode.js version number.
	 * @memberOf punycode
	 * @type String
	 */
	'version': '2.1.0',
	/**
	 * An object of methods to convert from JavaScript's internal character
	 * representation (UCS-2) to Unicode code points, and back.
	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
	 * @memberOf punycode
	 * @type Object
	 */
	'ucs2': {
		'decode': ucs2decode,
		'encode': ucs2encode
	},
	'decode': decode,
	'encode': encode,
	'toASCII': toASCII,
	'toUnicode': toUnicode
};


/* harmony default export */ const punycode_es6 = (punycode);

;// CONCATENATED MODULE: ./Extension/src/background/utils/url.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable camelcase, no-control-regex, max-len */


const url = function () {
  const RE_V4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})$/i;
  const RE_V4_HEX = /^0x([0-9a-f]{8})$/i;
  const RE_V4_NUMERIC = /^[0-9]+$/;
  const RE_V4inV6 = /(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
  const RE_BAD_CHARACTERS = /([^0-9a-f:])/i;
  const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]$)/i;
  /**
   * Helper methods to work with URLs
   */

  const UrlUtils = {
    isHttpRequest(url) {
      return url && url.indexOf('http') === 0;
    },

    isHttpOrWsRequest(url) {
      return url && (url.indexOf('http') === 0 || url.indexOf('ws') === 0);
    },

    toPunyCode(domain) {
      if (!domain) {
        return '';
      }

      if (/^[\x00-\x7F]+$/.test(domain)) {
        return domain;
      }

      return punycode_es6.toASCII(domain);
    },

    /**
     * Retrieves hostname from URL
     */
    getHost(url) {
      if (!url) {
        return null;
      }

      let firstIdx = url.indexOf('//');

      if (firstIdx === -1) {
        /**
         * It's non hierarchical structured URL (e.g. stun: or turn:)
         * https://tools.ietf.org/html/rfc4395#section-2.2
         * https://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-08#appendix-B
         */
        firstIdx = url.indexOf(':');

        if (firstIdx === -1) {
          return null;
        }

        firstIdx -= 1;
      }

      const nextSlashIdx = url.indexOf('/', firstIdx + 2);
      const startParamsIdx = url.indexOf('?', firstIdx + 2);
      let lastIdx = nextSlashIdx;

      if (startParamsIdx > 0 && (startParamsIdx < nextSlashIdx || nextSlashIdx < 0)) {
        lastIdx = startParamsIdx;
      }

      let host = lastIdx === -1 ? url.substring(firstIdx + 2) : url.substring(firstIdx + 2, lastIdx);
      const portIndex = host.indexOf(':');
      host = portIndex === -1 ? host : host.substring(0, portIndex); // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1586

      const lastChar = host.charAt(host.length - 1);

      if (lastChar === '.') {
        host = host.slice(0, -1);
      }

      return host;
    },

    getDomainName(url) {
      const host = this.getHost(url);
      return this.getCroppedDomainName(host);
    },

    getCroppedDomainName(host) {
      return strings.startWith(host, 'www.') ? host.substring(4) : host;
    },

    isIpv4(address) {
      if (RE_V4.test(address)) {
        return true;
      }

      if (RE_V4_HEX.test(address)) {
        return true;
      }

      if (RE_V4_NUMERIC.test(address)) {
        return true;
      }

      return false;
    },

    isIpv6(address) {
      let a4addon = 0;
      const address4 = address.match(RE_V4inV6);

      if (address4) {
        const temp4 = address4[0].split('.');

        for (let i = 0; i < 4; i += 1) {
          if (/^0[0-9]+/.test(temp4[i])) {
            return false;
          }
        }

        address = address.replace(RE_V4inV6, '');

        if (/[0-9]$/.test(address)) {
          return false;
        }

        address += temp4.join(':');
        a4addon = 2;
      }

      if (RE_BAD_CHARACTERS.test(address)) {
        return false;
      }

      if (RE_BAD_ADDRESS.test(address)) {
        return false;
      }

      function count(string, substring) {
        return (string.length - string.replace(new RegExp(substring, 'g'), '').length) / substring.length;
      }

      const halves = count(address, '::');

      if (halves === 1 && count(address, ':') <= 6 + 2 + a4addon) {
        return true;
      }

      if (halves === 0 && count(address, ':') === 7 + a4addon) {
        return true;
      }

      return false;
    },

    urlEquals(u1, u2) {
      if (!u1 || !u2) {
        return false;
      } // eslint-disable-next-line prefer-destructuring


      u1 = u1.split(/[#?]/)[0]; // eslint-disable-next-line prefer-destructuring

      u2 = u2.split(/[#?]/)[0];
      return u1 === u2;
    }

  };
  return UrlUtils;
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/common.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */










/**
 * Background tab id in browsers is defined as -1
 */

const BACKGROUND_TAB_ID = -1;
/**
 * Main frame id is equal to 0
 */

const MAIN_FRAME_ID = 0;
/**
 * Utilities namespace
 */

const utils = {
  strings: strings,
  dates: dates,
  collections: collections,
  concurrent: concurrent,
  channels: channels,
  workaround: workaround,
  i18n: i18n,
  filters: filters,
  url: url
};
/**
 * Converts chrome tabs into tabs
 * https://developer.chrome.com/extensions/tabs#type-Tab
 * @param chromeTab
 * @returns tab
 */

function toTabFromChromeTab(chromeTab) {
  return {
    tabId: chromeTab.id,
    url: chromeTab.url,
    title: chromeTab.title,
    incognito: chromeTab.incognito,
    status: chromeTab.status
  };
}
/**
 * Unload handler. When extension is unload then 'fireUnload' is invoked.
 * You can add own handler with method 'when'
 * @type {{when, fireUnload}}
 */

const unload = function () {
  const unloadChannel = utils.channels.newChannel();

  const when = function (callback) {
    if (typeof callback !== 'function') {
      return;
    }

    unloadChannel.addListener(() => {
      try {
        callback();
      } catch (ex) {
        log.error('Error while invoke unload method');
        log.error(ex);
      }
    });
  };

  const fireUnload = function (reason) {
    log.info(`Unload is fired: ${reason}`);
    unloadChannel.notifyInReverseOrder(reason);
  };

  return {
    when,
    fireUnload
  };
}();
// EXTERNAL MODULE: ./node_modules/webextension-polyfill/dist/browser-polyfill.js
var browser_polyfill = __webpack_require__(3679);
var browser_polyfill_default = /*#__PURE__*/__webpack_require__.n(browser_polyfill);
;// CONCATENATED MODULE: ./Extension/src/background/extension-api/windows.js
/* eslint-disable no-unused-vars */

/**
 * This function patches if necessary browser.windows implementation for Firefox for Android
 */
const patchWindows = function (browser) {
  // Make compatible with Android WebExt
  if (typeof browser.windows === 'undefined') {
    browser.windows = function () {
      const defaultWindow = {
        id: 1,
        type: 'normal'
      };
      const emptyListener = {
        addListener() {// Doing nothing
        }

      };

      const create = function (createData) {
        return Promise.resolve(defaultWindow);
      };

      const update = function (windowId, data) {
        return Promise.resolve();
      };

      const getAll = function (query) {
        return Promise.resolve(defaultWindow);
      };

      const getLastFocused = function () {
        return Promise.resolve(defaultWindow);
      };

      return {
        onCreated: emptyListener,
        onRemoved: emptyListener,
        onFocusChanged: emptyListener,
        create,
        update,
        getAll,
        getLastFocused
      };
    }();
  }
};
;// CONCATENATED MODULE: ./Extension/src/background/extension-api/browser.js


patchWindows((browser_polyfill_default()));

;// CONCATENATED MODULE: ./Extension/src/common/common-script.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

const runtimeImpl = (() => {
  return {
    onMessage: (browser_polyfill_default()).runtime.onMessage,
    sendMessage: (browser_polyfill_default()).runtime.sendMessage
  };
})(); // eslint-disable-next-line prefer-destructuring

const common_script_i18n = (browser_polyfill_default()).i18n;
;// CONCATENATED MODULE: ./Extension/src/background/utils/lazy.js
/**
 * This function allows cache property in object. Use with javascript getter.
 *
 * var Object = {
 *
 *      get someProperty(){
 *          return lazyGet(Object, 'someProperty', function() {
 *              return calculateSomeProperty();
 *          });
 *      }
 * }
 *
 * @param object Object
 * @param prop Original property name
 * @param calculateFunc Calculation function
 * @returns {*}
 */
const lazyGet = function (object, prop, calculateFunc) {
  const cachedProp = `_${prop}`;

  if (cachedProp in object) {
    return object[cachedProp];
  }

  const value = calculateFunc.apply(object);
  object[cachedProp] = value;
  return value;
};
/**
 * Clear cached property
 * @param object Object
 * @param prop Original property name
 */

const lazyGetClear = function (object, prop) {
  delete object[`_${prop}`];
};
;// CONCATENATED MODULE: ./Extension/src/common/user-agent-utils.js
/**
 * Check if current browser is as given
 * @param {string} browserName
 * @returns {boolean}
 */
const isTargetBrowser = browserName => {
  var _navigator$userAgentD;

  let brand;
  let uaStringName;

  if (browserName === 'Chrome') {
    brand = 'Google Chrome';
    uaStringName = 'Chrome';
  } else if (browserName === 'Firefox') {
    uaStringName = 'Firefox';
  } else if (browserName === 'Safari') {
    uaStringName = 'Safari';
  } else if (browserName === 'Opera') {
    brand = 'Opera';
    uaStringName = 'OPR';
  } else if (browserName === 'YaBrowser') {
    brand = 'Yandex';
    uaStringName = 'YaBrowser';
  } else if (browserName === 'Edge') {
    uaStringName = 'edge';
  } else if (browserName === 'EdgeChromium') {
    brand = 'Microsoft Edge';
    uaStringName = 'edg';
  }

  const brandsData = (_navigator$userAgentD = navigator.userAgentData) === null || _navigator$userAgentD === void 0 ? void 0 : _navigator$userAgentD.brands;

  if (!brandsData || !brand) {
    return navigator.userAgent.indexOf(uaStringName) >= 0;
  } // eslint-disable-next-line no-restricted-syntax


  for (const data of brandsData) {
    if (data.brand === brand) {
      return true;
    }
  }

  return false;
};
/**
 * Check if current platform is as given
 * @param {string} platformName
 * @returns
 */


const isTargetPlatform = platformName => {
  var _navigator$userAgentD2;

  const platformString = (_navigator$userAgentD2 = navigator.userAgentData) === null || _navigator$userAgentD2 === void 0 ? void 0 : _navigator$userAgentD2.platform;
  return platformString ? platformString.toUpperCase().indexOf(platformName) >= 0 : navigator.userAgent.toUpperCase().indexOf(platformName) >= 0;
};
/**
 * Get browser version by name
 * @param {string} browserName
 * @returns {number|null}
 */


const getBrowserVersion = browserName => {
  var _navigator$userAgentD3;

  let brand;
  let uaStringMask;

  if (browserName === 'Chrome') {
    brand = 'Google Chrome';
    uaStringMask = /\sChrome\/(\d+)\./;
  } else if (browserName === 'Firefox') {
    uaStringMask = /\sFirefox\/(\d+)\./;
  }

  const brandsData = (_navigator$userAgentD3 = navigator.userAgentData) === null || _navigator$userAgentD3 === void 0 ? void 0 : _navigator$userAgentD3.brands;

  if (!brandsData || !brand) {
    const match = uaStringMask.exec(navigator.userAgent);
    return match === null ? null : Number.parseInt(match[1], 10);
  } // eslint-disable-next-line no-restricted-syntax


  for (const data of brandsData) {
    if (data.brand === brand) {
      const {
        version
      } = data;
      return Number.parseInt(version, 10);
    }
  }

  return null;
};

const isChrome = isTargetBrowser('Chrome');
const isFirefox = isTargetBrowser('Firefox');
const isOpera = isTargetBrowser('Opera');
const isYaBrowser = isTargetBrowser('YaBrowser');
const isEdge = isTargetBrowser('Edge');
const isEdgeChromium = isTargetBrowser('EdgeChromium');
const chromeVersion = getBrowserVersion('Chrome');
const firefoxVersion = getBrowserVersion('Firefox');
const isMacOs = isTargetPlatform('MAC');
const isWindowsOs = isTargetPlatform('WIN');
const isAndroid = isTargetPlatform('ANDROID');
;// CONCATENATED MODULE: ./Extension/src/background/prefs.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */



/**
 * Extension global preferences.
 */

const prefs = (() => {
  const Prefs = {
    get mobile() {
      return lazyGet(Prefs, 'mobile', () => isAndroid);
    },

    get platform() {
      return lazyGet(Prefs, 'platform', () => window.browser ? 'firefox' : 'chromium');
    },

    get browser() {
      return lazyGet(Prefs, 'browser', () => {
        let browser;

        if (isYaBrowser) {
          browser = 'YaBrowser';
        } else if (isEdge) {
          browser = 'Edge';
        } else if (isEdgeChromium) {
          browser = 'EdgeChromium';
        } else if (isOpera) {
          browser = 'Opera';
        } else if (isFirefox) {
          browser = 'Firefox';
        } else {
          browser = 'Chrome';
        }

        return browser;
      });
    },

    get chromeVersion() {
      return lazyGet(Prefs, 'chromeVersion', () => chromeVersion);
    },

    get firefoxVersion() {
      return lazyGet(Prefs, 'firefoxVersion', () => firefoxVersion);
    },

    /**
     * https://msdn.microsoft.com/ru-ru/library/hh869301(v=vs.85).aspx
     * @returns {*}
     */
    get edgeVersion() {
      return lazyGet(Prefs, 'edgeVersion', function () {
        if (this.browser === 'Edge') {
          const {
            userAgent
          } = navigator;
          const i = userAgent.indexOf('Edge/');

          if (i < 0) {
            return {
              rev: 0,
              build: 0
            };
          }

          const version = userAgent.substring(i + 'Edge/'.length);
          const parts = version.split('.');
          return {
            rev: Number.parseInt(parts[0], 10),
            build: Number.parseInt(parts[1], 10)
          };
        }
      });
    },

    /**
     * Makes sense in case of FF add-on only
     */
    speedupStartup() {
      return false;
    },

    get ICONS() {
      return lazyGet(Prefs, 'ICONS', () => ({
        ICON_GREEN: {
          '19': browser_polyfill_default().runtime.getURL('assets/icons/green-19.png'),
          '38': browser_polyfill_default().runtime.getURL('assets/icons/green-38.png')
        },
        ICON_GRAY: {
          '19': browser_polyfill_default().runtime.getURL('assets/icons/gray-19.png'),
          '38': browser_polyfill_default().runtime.getURL('assets/icons/gray-38.png')
        }
      }));
    },

    // interval 60 seconds in Firefox is set so big due to excessive IO operations on every storage save
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1006
    get statsSaveInterval() {
      return this.browser === 'Firefox' ? 1000 * 60 : 1000;
    }

  };
  /**
   * Collect browser specific features here
   */

  Prefs.features = function () {
    // Get the global extension object (browser for FF, chrome for Chromium)
    const browser = window.browser || window.chrome;
    const responseContentFilteringSupported = typeof browser !== 'undefined' && typeof browser.webRequest !== 'undefined' && typeof browser.webRequest.filterResponseData !== 'undefined';
    const canUseInsertCSSAndExecuteScript = // Blink engine based browsers
    (Prefs.browser === 'Chrome' || Prefs.browser === 'Opera' || Prefs.browser === 'YaBrowser' || Prefs.browser === 'EdgeChromium' // Support for tabs.insertCSS and tabs.executeScript on chrome
    // requires chrome version above or equal to 39,
    // as per documentation: https://developers.chrome.com/extensions/tabs
    // But due to a bug, it requires version >= 50
    // https://bugs.chromium.org/p/chromium/issues/detail?id=63979
    ) && Prefs.chromeVersion >= 50 || Prefs.browser === 'Firefox' && typeof browser !== 'undefined' && typeof browser.tabs !== 'undefined' && typeof browser.tabs.insertCSS !== 'undefined'; // Edge browser does not support `runAt` in options of tabs.insertCSS
    // and tabs.executeScript

    return {
      responseContentFilteringSupported,
      canUseInsertCSSAndExecuteScript,
      hasBackgroundTab: typeof browser !== 'undefined' // Background requests have sense only in case of webext

    };
  }();

  return Prefs;
})();
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.delete-all.js
var esnext_map_delete_all = __webpack_require__(3929);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.every.js
var esnext_map_every = __webpack_require__(7851);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.filter.js
var esnext_map_filter = __webpack_require__(3633);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.find.js
var esnext_map_find = __webpack_require__(1192);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.find-key.js
var esnext_map_find_key = __webpack_require__(7515);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.includes.js
var esnext_map_includes = __webpack_require__(8034);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.key-of.js
var esnext_map_key_of = __webpack_require__(1480);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.map-keys.js
var esnext_map_map_keys = __webpack_require__(9027);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.map-values.js
var esnext_map_map_values = __webpack_require__(5739);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.merge.js
var esnext_map_merge = __webpack_require__(9283);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.reduce.js
var esnext_map_reduce = __webpack_require__(4473);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.some.js
var esnext_map_some = __webpack_require__(989);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.map.update.js
var esnext_map_update = __webpack_require__(7194);
;// CONCATENATED MODULE: ./Extension/src/background/extension-api/iconsCache.js













const cache = new Map();
/**
 * Download image and convert it to ImageData
 *
 * @param {Number} size - icon size in px
 * @param {String} url - icon url
 * @returns {ImageData}
 */

const loadImageData = (size, url) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.src = url;

    img.onload = () => {
      const canvas = document.createElement('canvas');
      document.documentElement.appendChild(canvas);
      canvas.width = size;
      canvas.height = size;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      const data = ctx.getImageData(0, 0, size, size);
      canvas.remove();
      resolve(data);
    };

    img.onerror = reject;
  });
};
/**
 * Get ImageData for specific url
 *
 * @param {Number} size - icon size in px
 * @param {String} url - icon url
 * @returns {[size: Number, imageData: ImageData]} - key-value entry for browserAction.setIcon 'imageData' property
 */


const getImageData = async (size, url) => {
  const imageData = cache.get(url);

  if (!imageData) {
    const data = await loadImageData(size, url);
    cache.set(url, data);
    return [size, data];
  }

  return [size, imageData];
};
/**
 * Match urls from browserAction.setIcon 'path' property with cached ImageData values
 * and return 'imageData' object for this action.
 *
 * see: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction/setIcon
 *
 * @param {Object} path - browserAction.setIcon details 'path' property
 * @returns {Object} - browserAction.setIcon details 'imageData' property
 */


const getIconImageData = async path => {
  const imageDataEntriesPromises = Object.entries(path).map(([size, url]) => getImageData(size, url));
  const imageDataEntries = await Promise.all(imageDataEntriesPromises);
  const imageData = Object.fromEntries(imageDataEntries);
  return imageData;
};
;// CONCATENATED MODULE: ./Extension/src/background/extension-api/background-page.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */








const backgroundPage = (() => {
  const runtime = function () {
    const onMessage = {
      addListener(callback) {
        // https://developer.chrome.com/extensions/runtime#event-onMessage
        runtimeImpl.onMessage.addListener((message, sender) => {
          const senderOverride = Object.create(null);

          if (sender.tab) {
            senderOverride.tab = toTabFromChromeTab(sender.tab);
          }

          if (typeof sender.frameId !== 'undefined') {
            senderOverride.frameId = sender.frameId;
          }

          return callback(message, senderOverride);
        });
      }

    };
    return {
      setUninstallURL: (browser_polyfill_default()).runtime.setUninstallURL,
      reload: (browser_polyfill_default()).runtime.reload,
      onMessage,
      onConnect: (browser_polyfill_default()).runtime.onConnect,

      get lastError() {
        return (browser_polyfill_default()).runtime.lastError;
      }

    };
  }(); // Calculates scheme of this extension (e.g.: chrome-extension:// or moz-extension://)


  const extensionScheme = function () {
    const url = browser_polyfill_default().runtime.getURL('');

    if (!url) {
      return url;
    }

    const index = url.indexOf('://');

    if (index > 0) {
      return url.substring(0, index);
    }

    return url;
  }();
  /**
   * We are skipping requests to internal resources of extensions
   * (e.g. chrome-extension:// or moz-extension://... etc.)
   * @param details Request details
   * @returns {boolean}
   */


  function shouldSkipRequest(details) {
    return details.tabId === BACKGROUND_TAB_ID && details.url.indexOf(extensionScheme) === 0;
  }

  const linkHelper = document.createElement('a');
  /**
   * Fixing request type:
   * https://code.google.com/p/chromium/issues/detail?id=410382
   *
   * @param url Request url
   * @returns String Fixed object type
   */

  function parseRequestTypeFromUrl(url) {
    linkHelper.href = url;
    const path = linkHelper.pathname;
    let requestType = parseContentTypeFromUrlPath(path);

    if (requestType === null) {
      // https://code.google.com/p/chromium/issues/detail?id=410382
      requestType = RequestTypes.OBJECT;
    }

    return requestType;
  }
  /**
   * An array of HTTP headers.
   * Each header is represented as a dictionary containing the keys name
   * and either value or binaryValue.
   * https://developer.chrome.com/extensions/webRequest#type-HttpHeaders
   * @typedef HttpHeaders
   * @type {Array.<{ name: String, value: String, binaryValue }>}
   */

  /**
   * @typedef RequestDetails
   * @type {Object}
   * @property {String} requestUrl - request url
   * @property {String} referrerUrl - the origin where the request was initiated
   * @property {{tabId: Number}} tab - request tab with tabId in property
   * @property {Number} requestId - the ID of the request
   * @property {Number} statusCode - standard HTTP status code
   * @property {String} method - standard HTTP method
   * @property {Number} frameId - ID of current frame. Frame IDs are unique within a tab.
   * @property {Number} requestFrameId - ID of frame where request is executed
   * @property {Number} requestType - request type {@link RequestTypes}
   * @property {HttpHeaders} [requestHeaders] - the HTTP request headers
   * @property {HttpHeaders} [responseHeaders] - the HTTP response headers
   * @property {String} redirectUrl - new URL in onBeforeRedirect event
   */

  /**
   * Argument passed to the webRequest event listener.
   * Every webRequest event listener has its own object with request details.
   * To learn more see https://developer.chrome.com/extensions/webRequest or
   * https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest
   * @typedef {Object} WebRequestDetails
   */

  /**
   * Transforms raw request details from different browsers into unified format
   * @param {WebRequestDetails} details raw webRequest details
   * @returns {RequestDetails} prepared request details
   */


  function getRequestDetails(details) {
    const tab = {
      tabId: details.tabId
    };
    /**
     * FF sends http instead of ws protocol at the http-listeners layer
     * Although this is expected, as the Upgrade request is indeed an HTTP request,
     * we use a chromium based approach in this case.
     */

    if (details.type === 'websocket' && details.url.indexOf('http') === 0) {
      details.url = details.url.replace(/^http(s)?:/, 'ws$1:');
    } // https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest


    const requestDetails = {
      requestUrl: details.url,
      // request url
      url: details.url,
      tab,
      // request tab,
      tabId: details.tabId,
      requestId: details.requestId,
      statusCode: details.statusCode,
      method: details.method
    };
    let frameId = 0; // id of this frame (only for main_frame and sub_frame types)

    let requestFrameId = 0; // id of frame where request is executed

    let requestType; // request type

    switch (details.type) {
      case 'main_frame':
        frameId = 0;
        requestType = RequestTypes.DOCUMENT;
        break;

      case 'sub_frame':
        frameId = details.frameId; // for sub_frame use parentFrameId as id of frame that wraps this frame

        requestFrameId = details.parentFrameId;
        requestType = RequestTypes.SUBDOCUMENT;
        break;

      default:
        requestFrameId = details.frameId;
        requestType = details.type.toUpperCase();
        break;
    } // Relate request to main_frame


    if (requestFrameId === -1) {
      requestFrameId = 0;
    }

    if (requestType === 'IMAGESET') {
      requestType = RequestTypes.IMAGE;
    }

    if (requestType === RequestTypes.OTHER) {
      requestType = parseRequestTypeFromUrl(details.url);
    }
    /**
     * ping type is 'ping' in Chrome
     * but Firefox considers it as 'beacon'
     */


    if (requestType === 'BEACON') {
      requestType = RequestTypes.PING;
    }
    /**
     * Use `OTHER` type as a fallback
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/777
     */


    if (!(requestType in RequestTypes)) {
      requestType = RequestTypes.OTHER;
    }

    requestDetails.frameId = frameId;
    requestDetails.requestFrameId = requestFrameId;
    requestDetails.requestType = requestType;

    if (details.requestHeaders) {
      requestDetails.requestHeaders = details.requestHeaders;
    }

    if (details.responseHeaders) {
      requestDetails.responseHeaders = details.responseHeaders;
    }

    if (details.requestBody) {
      requestDetails.requestBody = details.requestBody;
    }

    if (details.tabId === BACKGROUND_TAB_ID) {
      // In case of background request, its details contains referrer url
      // Chrome uses `initiator`: https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest
      // FF uses `originUrl`: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onBeforeRequest#Additional_objects
      requestDetails.referrerUrl = details.originUrl || details.initiator;
    }

    requestDetails.originUrl = details.originUrl || details.initiator;
    requestDetails.thirdParty = tsurlfilter_browser.isThirdPartyRequest(requestDetails.requestUrl, requestDetails.originUrl);
    return requestDetails;
  }

  const onBeforeRequest = {
    /**
     * Wrapper for webRequest.onBeforeRequest event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {String} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     * @param {string[]} types
     * @param {string[]} extraInfoSpecsDirty
     */
    addListener(callback, urls, types, extraInfoSpecsDirty) {
      const filters = {};

      if (urls) {
        filters.urls = urls;
      }

      if (types) {
        filters.types = types;
      }

      const extraInfoSpec = ['blocking'];

      if (extraInfoSpecsDirty && extraInfoSpecsDirty.length > 0) {
        extraInfoSpecsDirty.forEach(spec => {
          extraInfoSpec.push(spec);
        });
      } // https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest


      browser_polyfill_default().webRequest.onBeforeRequest.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        return callback(requestDetails);
      }, filters, extraInfoSpec);
    }

  };
  /**
   * Apply 'extraHeaders' option for request/response headers access/change. See:
   * https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/vYIaeezZwfQ
   * https://chromium-review.googlesource.com/c/chromium/src/+/1338165
   */

  const onBeforeSendHeadersExtraInfoSpec = ['requestHeaders', 'blocking'];
  const onHeadersReceivedExtraInfoSpec = ['responseHeaders', 'blocking'];

  if (typeof (browser_polyfill_default()).webRequest.OnBeforeSendHeadersOptions !== 'undefined' && browser_polyfill_default().webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) {
    onBeforeSendHeadersExtraInfoSpec.push('extraHeaders');
  }

  if (typeof (browser_polyfill_default()).webRequest.OnHeadersReceivedOptions !== 'undefined' && browser_polyfill_default().webRequest.OnHeadersReceivedOptions.hasOwnProperty('EXTRA_HEADERS')) {
    onHeadersReceivedExtraInfoSpec.push('extraHeaders');
  }

  const onHeadersReceived = {
    /**
     * Wrapper for webRequest.onHeadersReceived event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {Array.<String>} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      browser_polyfill_default().webRequest.onHeadersReceived.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        const result = callback(requestDetails);

        if (result) {
          return 'responseHeaders' in result ? {
            responseHeaders: result.responseHeaders
          } : {};
        }
      }, urls ? {
        urls
      } : {}, onHeadersReceivedExtraInfoSpec);
    }

  };
  const onBeforeSendHeaders = {
    /**
     * Wrapper for webRequest.onBeforeSendHeaders event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {Array.<String>} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      let requestFilter = {};
      /**
       * Sometimes extraHeaders option of onBeforeSendHeaders handler is blocking network
       * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1634
       * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1644
       * https://bugs.chromium.org/p/chromium/issues/detail?id=938560
       * https://bugs.chromium.org/p/chromium/issues/detail?id=1075905
       * This issue was fixed in the Canary v85.0.4178.0 and would be fixed
       * in the Chrome with the same version
       * Until v85 we have decided to filter requests with types:
       * 'stylesheet', 'script', 'media'
       */

      if (prefs.browser === 'Chrome' && prefs.chromeVersion < 85) {
        const allTypes = ['main_frame', 'sub_frame', 'stylesheet', 'script', 'image', 'font', 'object', 'xmlhttprequest', 'ping', 'csp_report', 'media', 'websocket', 'other']; // this request types block requests, if use them with extraHeaders and blocking options

        const nonExtraHeadersTypes = ['stylesheet', 'script', 'media'];
        const extraHeadersTypes = allTypes.filter(type => !nonExtraHeadersTypes.includes(type)); // Assign instead of spread used because FF begin to support them from v55
        // https://caniuse.com/#feat=mdn-javascript_operators_spread_spread_in_object_literals

        requestFilter = Object.assign(requestFilter, {
          types: extraHeadersTypes
        });
      }

      if (urls) {
        // Assign instead of spread used because FF begin to support them from v55
        // https://caniuse.com/#feat=mdn-javascript_operators_spread_spread_in_object_literals
        requestFilter = Object.assign(requestFilter, {
          urls
        });
      }

      browser_polyfill_default().webRequest.onBeforeSendHeaders.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        const result = callback(requestDetails);

        if (result) {
          return 'requestHeaders' in result ? {
            requestHeaders: result.requestHeaders
          } : {};
        }
      }, requestFilter, onBeforeSendHeadersExtraInfoSpec);
    }

  };
  const onResponseStarted = {
    /**
     * Wrapper for webRequest.onResponseStarted event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {String} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      browser_polyfill_default().webRequest.onResponseStarted.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        return callback(requestDetails);
      }, urls ? {
        urls
      } : {}, ['responseHeaders']);
    }

  };
  const onErrorOccurred = {
    /**
     * Wrapper for webRequest.onErrorOccurred event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {String} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      browser_polyfill_default().webRequest.onErrorOccurred.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        return callback(requestDetails);
      }, urls ? {
        urls
      } : {});
    }

  };
  const onCompleted = {
    /**
     * Wrapper for webRequest.onCompleted event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {String} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      browser_polyfill_default().webRequest.onCompleted.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        return callback(requestDetails);
      }, urls ? {
        urls
      } : {}, ['responseHeaders']);
    }

  };
  const onBeforeRedirect = {
    /**
     * Wrapper for webRequest.onBeforeRedirect event
     * It prepares requestDetails and passes them to the callback
     * @param callback callback function receives {RequestDetails} and handles event
     * @param {Array.<String>} urls url match pattern https://developer.chrome.com/extensions/match_patterns
     */
    addListener(callback, urls) {
      browser_polyfill_default().webRequest.onBeforeRedirect.addListener(details => {
        if (shouldSkipRequest(details)) {
          return;
        }

        const requestDetails = getRequestDetails(details);
        requestDetails.redirectUrl = details.redirectUrl;
        return callback(requestDetails);
      }, urls ? {
        urls
      } : {});
    }

  };
  /**
   * Gets URL of a file that belongs to our extension
   * https://developer.chrome.com/apps/runtime#method-getURL
   */
  // eslint-disable-next-line prefer-destructuring

  const getURL = (browser_polyfill_default()).runtime.getURL;
  const app = {
    /**
     * Extension ID
     */
    getId() {
      return (browser_polyfill_default()).runtime.id;
    },

    /**
     * Gets extension scheme
     * @returns "chrome-extension" for Chrome," ms-browser-extension" for Edge
     */
    getUrlScheme() {
      const url = backgroundPage.getURL('test.html');
      const index = url.indexOf('://');
      return url.substring(0, index);
    },

    /**
     * Extension version
     */
    getVersion() {
      return browser_polyfill_default().runtime.getManifest().version;
    },

    /**
     * Extension UI locale
     */
    getLocale() {
      return browser_polyfill_default().i18n.getUILanguage();
    },

    /**
     * Returns extension's full url
     */
    getExtensionUrl() {
      const url = getURL('');
      return url.substring(0, url.length - 1);
    },

    /**
     * If referrer of request contains full url of extension,
     * then this request is considered as extension's own request
     * (e.g. request for filter downloading)
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1437
     * @param referrerUrl
     * @returns {boolean}
     */
    isOwnRequest(referrerUrl) {
      return referrerUrl && referrerUrl.indexOf(this.getExtensionUrl()) === 0;
    }

  };
  const webRequest = {
    onBeforeRequest,
    handlerBehaviorChanged: (browser_polyfill_default()).webRequest.handlerBehaviorChanged,
    onCompleted,
    onErrorOccurred,
    onHeadersReceived,
    onBeforeSendHeaders,
    onResponseStarted,
    onBeforeRedirect,
    webSocketSupported: typeof (browser_polyfill_default()).webRequest.ResourceType !== 'undefined' && (browser_polyfill_default()).webRequest.ResourceType.WEBSOCKET === 'websocket',
    filterResponseData: (browser_polyfill_default()).webRequest.filterResponseData
  };
  const onCreatedNavigationTarget = {
    addListener(callback) {
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webNavigation/onCreatedNavigationTarget#Browser_compatibility
      if (typeof (browser_polyfill_default()).webNavigation.onCreatedNavigationTarget === 'undefined') {
        return;
      }

      browser_polyfill_default().webNavigation.onCreatedNavigationTarget.addListener(details => {
        if (details.tabId === BACKGROUND_TAB_ID) {
          return;
        }

        callback({
          tabId: details.tabId,
          sourceTabId: details.sourceTabId,
          url: details.url
        });
      });
    }

  };
  const onCommitted = {
    /**
     * Wrapper for webNavigation.onCommitted event
     * It prepares webNavigation details and passes them to the callback
     * @param callback callback function receives object similar to {RequestDetails}
     * and handles event
     */
    addListener(callback) {
      // https://developer.chrome.com/extensions/webNavigation#event-onCommitted
      browser_polyfill_default().webNavigation.onCommitted.addListener(details => {
        // makes webNavigation.onCommitted details similar to webRequestDetails
        details.requestType = details.frameId === 0 ? RequestTypes.DOCUMENT : RequestTypes.SUBDOCUMENT;
        details.tab = {
          tabId: details.tabId
        };
        details.requestUrl = details.url;
        callback(details);
      }, {
        url: [{
          urlPrefix: 'http'
        }, {
          urlPrefix: 'https'
        }]
      });
    }

  }; // https://developer.chrome.com/extensions/webNavigation

  const webNavigation = {
    onCreatedNavigationTarget,
    onCommitted,
    onDOMContentLoaded: (browser_polyfill_default()).webNavigation.onDOMContentLoaded
  };
  const browserActionSupported = typeof (browser_polyfill_default()).browserAction.setIcon !== 'undefined';
  const browserAction = {
    /* eslint-disable-next-line no-unused-vars */
    async setBrowserAction(tab, icon, badge, badgeColor, title) {
      if (!browserActionSupported) {
        return;
      }

      const {
        tabId
      } = tab;

      const onIconReady = async () => {
        try {
          await browser_polyfill_default().browserAction.setBadgeText({
            tabId,
            text: badge
          });
        } catch (e) {
          log.debug(new Error(e.message));
          return;
        }

        if (badge) {
          try {
            await browser_polyfill_default().browserAction.setBadgeBackgroundColor({
              tabId,
              color: badgeColor
            });
          } catch (e) {
            log.debug(new Error(e.message));
          }
        } // title setup via manifest.json file
        // chrome.browserAction.setTitle({tabId: tabId, title: title});

      };
      /**
       * Workaround for MS Edge.
       * For some reason Edge changes the inner state of the "icon"
       * object and adds a tabId property inside.
       */


      delete icon.tabId;

      if ((browser_polyfill_default()).runtime.lastError) {
        return;
      }

      try {
        await browser_polyfill_default().browserAction.setIcon({
          tabId,
          imageData: await getIconImageData(icon)
        });
      } catch (e) {
        log.debug(new Error(e.message));
        return;
      }

      onIconReady();
    },

    setPopup() {// Do nothing. Popup is already installed in manifest file
    },

    resize() {// Do nothing
    },

    close() {// Do nothing
    }

  }; // eslint-disable-next-line prefer-destructuring

  const contextMenus = (browser_polyfill_default()).contextMenus; // eslint-disable-next-line prefer-destructuring

  const i18n = (browser_polyfill_default()).i18n;
  return {
    runtime,
    getURL,
    app,
    webRequest,
    webNavigation,
    browserAction,
    contextMenus,
    i18n
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/utils/local-storage.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 * Local storage implementation for chromium-based browsers
 */

const localStorageImpl = function () {
  const ADGUARD_SETTINGS_PROP = 'adguard-settings';
  let values = null;
  /**
   * Reads data from storage.local
   * @param path Path
   */

  async function read(path) {
    const results = await browser_polyfill_default().storage.local.get(path);
    return results ? results[path] : null;
  }
  /**
   * Writes data to storage.local
   * @param path Path
   * @param data Data to write
   */


  async function write(path, data) {
    const item = {};
    item[path] = data;
    await browser_polyfill_default().storage.local.set(item);
  }
  /**
   * Due to async initialization of storage, we have to check it before accessing values object
   * @returns {boolean}
   */


  function isInitialized() {
    return values !== null;
  }
  /**
   * Retrieves value by key from cached values
   * @param key
   * @returns {*}
   */


  function getItem(key) {
    if (!isInitialized()) {
      return null;
    }

    return values[key];
  }

  function setItem(key, value) {
    if (!isInitialized()) {
      return;
    }

    values[key] = value;
    write(ADGUARD_SETTINGS_PROP, values);
  }

  function removeItem(key) {
    if (!isInitialized()) {
      return;
    }

    delete values[key];
    write(ADGUARD_SETTINGS_PROP, values);
  }

  function hasItem(key) {
    if (!isInitialized()) {
      return false;
    }

    return key in values;
  }
  /**
   * We can't use localStorage object anymore and we've decided to store all data into storage.local
   * localStorage is affected by cleaning tools: https://github.com/AdguardTeam/AdguardBrowserExtension/issues/681
   * storage.local has async nature and we have to preload all key-values pairs into memory on extension startup
   */


  async function init() {
    if (isInitialized()) {
      // Already initialized
      return;
    }

    let items;

    try {
      items = await read(ADGUARD_SETTINGS_PROP);
    } catch (e) {
      log.error(e);
    }

    values = items || Object.create(null);
  }

  return {
    getItem,
    setItem,
    removeItem,
    hasItem,
    init,
    isInitialized
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/rules-storage/rules-storage.chrome.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Filter rules storage implementation
 */

const chromeRulesStorageImpl = (() => {
  const read = async path => {
    const results = await browser_polyfill_default().storage.local.get(path);
    let lines = [];

    if (results && results[path] instanceof Array) {
      lines = results[path];
    }

    return lines;
  };

  const write = async (path, data) => {
    const item = {};
    item[path] = data;
    await browser_polyfill_default().storage.local.set(item);
  };

  const remove = async path => {
    await browser_polyfill_default().storage.local.remove(path);
  };

  return {
    read,
    write,
    remove
  };
})();

/* harmony default export */ const rules_storage_chrome = (chromeRulesStorageImpl);
;// CONCATENATED MODULE: ./Extension/src/background/rules-storage/index.js
// !IMPORTANT!
// './rules-storage.__ABSTRACT_BROWSER__' is replaced during webpack compilation
// with NormalModuleReplacementPlugin to proper browser implementation
// './rules-storage.chrome' or ./rules-storage.firefox


;// CONCATENATED MODULE: ./Extension/src/background/storage.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */



/**
 * This class manages local storage
 */

const storage_localStorage = function (localStorageImpl) {
  const getItem = function (key) {
    return localStorageImpl.getItem(key);
  };

  const setItem = function (key, value) {
    try {
      localStorageImpl.setItem(key, value);
    } catch (ex) {
      log.error(`Error while saving item ${key} to the localStorage: ${ex}`);
    }
  };

  const removeItem = function (key) {
    localStorageImpl.removeItem(key);
  };

  const hasItem = function (key) {
    return localStorageImpl.hasItem(key);
  };

  const init = async function () {
    if (typeof localStorageImpl.init === 'function') {
      await localStorageImpl.init();
    }
  };

  const isInitialized = function () {
    // WebExtension storage has async initialization
    if (typeof localStorageImpl.isInitialized === 'function') {
      return localStorageImpl.isInitialized();
    }

    return true;
  };

  return {
    getItem,
    setItem,
    removeItem,
    hasItem,
    init,
    isInitialized
  };
}(localStorageImpl);
/**
 * This class manages storage for filters.
 */

const rulesStorage = (rulesStorageImpl => {
  function getFilePath(filterId) {
    return `filterrules_${filterId}.txt`;
  }
  /**
   * Loads filter from the storage
   *
   * @param filterId  Filter identifier
   */


  const read = async filterId => {
    const filePath = getFilePath(filterId);
    let rules;

    try {
      rules = await rulesStorageImpl.read(filePath);
    } catch (e) {
      log.error(`Error while reading rules from file ${filePath} cause: ${e}`);
    }

    return rules;
  };
  /**
   * Saves filter rules to storage
   *
   * @param filterId      Filter identifier
   * @param filterRules   Filter rules
   */


  const write = async (filterId, filterRules) => {
    const filePath = getFilePath(filterId);

    try {
      await rulesStorageImpl.write(filePath, filterRules);
    } catch (e) {
      log.error(`Error writing filters to file ${filePath}. Cause: ${e}`);
    }
  };
  /**
   * Removes filter from storage
   * @param filterId
   */


  const remove = async filterId => {
    const filePath = getFilePath(filterId);

    try {
      await rulesStorageImpl.remove(filePath);
    } catch (e) {
      log.error(`Error removing filter ${filePath}. Cause: ${e}`);
    }
  };
  /**
   * IndexedDB implementation of the rules storage requires async initialization.
   * Also in some cases IndexedDB isn't supported, so we have to replace implementation
   * with the browser.storage
   */


  const init = async () => {
    if (typeof rulesStorageImpl.init === 'function') {
      const api = await rulesStorageImpl.init();
      rulesStorageImpl = api;
    }
  };

  return {
    read,
    write,
    remove,
    init
  };
})(rules_storage_chrome);
;// CONCATENATED MODULE: ./Extension/src/background/notifier.js
/* eslint-disable no-plusplus */

/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 * Simple mediator
 */

const listeners = (() => {
  const EventNotifierEventsMap = Object.create(null);
  const EventNotifier = {
    listenersMap: Object.create(null),
    listenersEventsMap: Object.create(null),
    listenerId: 0,

    /**
     * Subscribes listener to the specified events
     *
     * @param events    List of event types listener will be notified of
     * @param listener  Listener object
     * @returns Index of the listener
     */
    addSpecifiedListener(events, listener) {
      if (typeof listener !== 'function') {
        throw new Error('Illegal listener');
      }

      const listenerId = this.listenerId++;
      this.listenersMap[listenerId] = listener;
      this.listenersEventsMap[listenerId] = events;
      return listenerId;
    },

    /**
     * Subscribe specified listener to all events
     *
     * @param listener Listener
     * @returns Index of the listener
     */
    addListener(listener) {
      if (typeof listener !== 'function') {
        throw new Error('Illegal listener');
      }

      const listenerId = this.listenerId++;
      this.listenersMap[listenerId] = listener;
      return listenerId;
    },

    /**
     * Unsubscribe listener
     * @param listenerId Index of listener to unsubscribe
     */
    removeListener(listenerId) {
      delete this.listenersMap[listenerId];
      delete this.listenersEventsMap[listenerId];
    },

    /**
     * Notifies listeners about the events passed as arguments of this function.
     */
    notifyListeners(...args) {
      const [event] = args;

      if (!event || !(event in EventNotifierEventsMap)) {
        throw new Error(`Illegal event: ${event}`);
      }

      Object.entries(this.listenersMap).forEach(([listenerId, listener]) => {
        const events = this.listenersEventsMap[listenerId];

        if (events && events.length > 0 && events.indexOf(event) < 0) {
          return;
        }

        try {
          listener.apply(listener, args);
        } catch (ex) {
          log.error('Error invoking listener for {0} cause: {1}', event, ex);
        }
      });
    },

    /**
     * Asynchronously notifies all listeners about the events passed as arguments of this function.
     * Some events should be dispatched asynchronously, for instance this is very important for Safari:
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/251
     */
    notifyListenersAsync(...args) {
      setTimeout(() => {
        EventNotifier.notifyListeners(...args);
      }, 500);
    }

  }; // Make accessible only constants without functions. They will be passed to content-page

  EventNotifier.events = NOTIFIER_TYPES; // Copy global properties

  Object.entries(NOTIFIER_TYPES).forEach(([key, event]) => {
    EventNotifier[key] = event;

    if (event in EventNotifierEventsMap) {
      throw new Error(`Duplicate event:  ${event}`);
    }

    EventNotifierEventsMap[event] = key;
  });
  return EventNotifier;
})();
;// CONCATENATED MODULE: ./Extension/src/background/extension-api/tabs.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */





/**
 * Chromium tabs implementation
 * @type {{onCreated, onRemoved, onUpdated, onActivated, create, remove, activate, reload, sendMessage, getAll, getActive, fromChromeTab}}
 */

const tabsImpl = function () {
  /**
   * tabId parameter must be integer
   * @param tabId
   */
  function tabIdToInt(tabId) {
    return Number.parseInt(tabId, 10);
  }

  function logOperationError(operation, e) {
    log.error('Error while executing operation{1}: {0}', e, operation ? ` '${operation}'` : '');
  }
  /**
   * Returns id of active tab
   * @returns {Promise<number|null>}
   */


  const getActive = async function () {
    /**
     * lastFocusedWindow parameter isn't supported by Opera
     * But seems currentWindow has the same effect in our case.
     * See for details:
     * https://developer.chrome.com/extensions/windows#current-window
     * https://dev.opera.com/extensions/tab-window/#accessing-the-current-tab
     * https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/query
     */
    let tabs;

    try {
      tabs = await browser_polyfill_default().tabs.query({
        currentWindow: true,
        active: true
      });
    } catch (e) {
      log.debug(new Error(e.message));
    }

    if (tabs && tabs.length > 0) {
      return tabs[0].id;
    }

    return null;
  }; // https://developer.chrome.com/extensions/tabs#event-onCreated


  const onCreatedChannel = utils.channels.newChannel();
  browser_polyfill_default().tabs.onCreated.addListener(chromeTab => {
    onCreatedChannel.notify(toTabFromChromeTab(chromeTab));
  }); // https://developer.chrome.com/extensions/tabs#event-onCreated

  const onRemovedChannel = utils.channels.newChannel();
  browser_polyfill_default().tabs.onRemoved.addListener(tabId => {
    onRemovedChannel.notify(tabId);
  });
  const onUpdatedChannel = utils.channels.newChannel(); // https://developer.chrome.com/extensions/tabs#event-onUpdated

  browser_polyfill_default().tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    onUpdatedChannel.notify(toTabFromChromeTab(tab));
  }); // https://developer.chrome.com/extensions/tabs#event-onActivated

  const onActivatedChannel = utils.channels.newChannel();
  browser_polyfill_default().tabs.onActivated.addListener(activeInfo => {
    onActivatedChannel.notify(activeInfo.tabId);
  }); // https://developer.chrome.com/extensions/windows#event-onFocusChanged

  browser_polyfill_default().windows.onFocusChanged.addListener(async windowId => {
    if (windowId === (browser_polyfill_default()).windows.WINDOW_ID_NONE) {
      return;
    }

    const tabId = await getActive();

    if (tabId) {
      onActivatedChannel.notify(tabId);
    }
  });
  /**
   * Give focus to a window
   * @param tabId Tab identifier
   * @param windowId Window identifier
   */

  async function focusWindow(tabId, windowId) {
    /**
     * Updating already focused window produces bug in Edge browser
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/675
     */
    const activeTabId = await getActive();

    if (activeTabId && tabId !== activeTabId) {
      // Focus window
      try {
        await browser_polyfill_default().windows.update(windowId, {
          focused: true
        });
      } catch (e) {
        logOperationError(`Update window ${windowId}`, e);
      }
    }
  }
  /**
   * Creates new tab
   * @param createData
   */


  const create = async function (createData) {
    const {
      url,
      inNewWindow,
      width,
      height,
      top,
      left,
      isFullscreen
    } = createData;
    const active = createData.active === true;

    if (createData.type === 'popup' // Does not work properly in Anniversary builds
    && !browserUtils.isEdgeBeforeCreatorsUpdate() // Isn't supported by Android WebExt
    && !prefs.mobile) {
      // https://developer.chrome.com/extensions/windows#method-create
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/windows/create
      const windowState = isFullscreen ? {
        state: 'fullscreen'
      } : {
        width: width || 1000,
        height: height || 650,
        top: top || 0,
        left: left || 0
      };
      const {
        id
      } = await browser_polyfill_default().windows.create({
        url,
        type: 'popup',
        ...windowState
      }); // Firefox currently can't .create with top and left due to bug
      // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows/create
      // https://bugzilla.mozilla.org/show_bug.cgi?id=1271047

      if (browserUtils.isFirefoxBrowser() && typeof windowState.top === 'number') {
        await browser_polyfill_default().windows.update(id, windowState);
      }

      return;
    }

    const isHttp = url.indexOf('http') === 0;

    async function onWindowFound(win) {
      // https://developer.chrome.com/extensions/tabs#method-create
      const chromeTab = await browser_polyfill_default().tabs.create({
        /**
         * In the Firefox browser for Android there is not concept of windows
         * There is only one window whole time
         * That's why if we try to provide windowId, method fails with error.
         */
        windowId: !prefs.mobile ? win.id : undefined,
        url,
        active
      });

      if (active) {
        await focusWindow(chromeTab.id, chromeTab.windowId);
      }

      return toTabFromChromeTab(chromeTab);
    }

    const onWindowCreatedWithTab = async win => {
      const [tab] = win.tabs;

      if (active) {
        await focusWindow(tab.id, tab.windowId);
      }

      return toTabFromChromeTab(tab);
    };

    function isAppropriateWindow(win) {
      // We can't open not-http (e.g. 'chrome-extension://') urls in incognito mode
      return win.type === 'normal' && (isHttp || !win.incognito);
    }

    if (!inNewWindow) {
      // https://developer.chrome.com/extensions/windows#method-create
      // https://developer.chrome.com/extensions/windows#method-getLastFocused
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/windows/create
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/windows/getLastFocused
      const win = await browser_polyfill_default().windows.getLastFocused();

      if (isAppropriateWindow(win)) {
        return onWindowFound(win);
      } // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/569


      const wins = await browser_polyfill_default().windows.getAll({});

      if (wins) {
        for (let i = 0; i < wins.length; i += 1) {
          const win = wins[i];

          if (isAppropriateWindow(win)) {
            return onWindowFound(win);
          }
        }
      } // Create new window


      const newWin = await browser_polyfill_default().windows.create();
      return onWindowFound(newWin);
    } // if inNewWindow
    // we open window with "url" to avoid empty new tab creation


    const newWin = await browser_polyfill_default().windows.create({
      url
    });
    return onWindowCreatedWithTab(newWin);
  };

  const remove = async tabId => {
    // https://developer.chrome.com/extensions/tabs#method-remove
    // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/remove
    try {
      await browser_polyfill_default().tabs.remove(tabIdToInt(tabId));
    } catch (e) {
      return;
    }

    return tabId;
  };

  const activate = async function (tabId) {
    try {
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/update
      const chromeTab = await browser_polyfill_default().tabs.update(tabIdToInt(tabId), {
        active: true
      });
      await focusWindow(tabId, chromeTab.windowId);
      return tabId;
    } catch (e) {
      logOperationError('Before tab update', e);
    }
  };
  /**
   * Sends message to tabs
   * @param tabId
   * @param message
   * @param options
   * @returns {Promise<*>}
   */


  const sendMessage = async (tabId, message, options) => {
    // https://developer.chrome.com/extensions/tabs#method-sendMessage
    // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/sendMessage
    const args = [tabIdToInt(tabId), message];

    if (typeof options === 'object') {
      args.push(options);
    }

    try {
      const response = await browser_polyfill_default().tabs.sendMessage(...args);
      return response;
    } catch (e) {
      log.debug(e.message);
    }
  };

  const reload = async (tabId, url) => {
    if (url) {
      if (browserUtils.isEdgeBrowser()) {
        /**
         * For security reasons, in Firefox and Edge, this may not be a privileged URL.
         * So passing any of the following URLs will fail, with runtime.lastError being set to an error message:
         * chrome: URLs
         * javascript: URLs
         * data: URLs
         * privileged about: URLs (for example, about:config, about:addons, about:debugging).
         *
         * Non-privileged URLs (about:home, about:newtab, about:blank) are allowed.
         *
         * So we use a content script instead.
         */

        /**
         * Content script may not have been loaded at this point yet.
         * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/580
         */
        setTimeout(() => {
          sendMessage(tabId, {
            type: 'update-tab-url',
            url
          });
        }, 100);
      } else {
        try {
          await browser_polyfill_default().tabs.update(tabIdToInt(tabId), {
            url
          });
        } catch (e) {
          logOperationError('Tab update', e);
        }
      } // https://developer.chrome.com/extensions/tabs#method-reload
      // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/reload#Browser_compatibility

    } else if ((browser_polyfill_default()).tabs.reload) {
      try {
        await browser_polyfill_default().tabs.reload(tabIdToInt(tabId), {
          bypassCache: true
        });
      } catch (e) {
        logOperationError('Tab reload', e);
      }
    } else {
      // Reload page without cache via content script
      sendMessage(tabId, {
        type: 'no-cache-reload'
      });
    }
  };

  const getAll = async () => {
    // https://developer.chrome.com/extensions/tabs#method-query
    // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/query
    const chromeTabs = await browser_polyfill_default().tabs.query({});
    const result = [];

    for (let i = 0; i < chromeTabs.length; i += 1) {
      const chromeTab = chromeTabs[i];
      result.push(toTabFromChromeTab(chromeTab));
    }

    return result;
  };
  /**
   * Gets tab by id
   * @param tabId Tab identifier
   */


  const get = async tabId => {
    try {
      const chromeTab = await browser_polyfill_default().tabs.get(tabIdToInt(tabId));
      return toTabFromChromeTab(chromeTab);
    } catch (e) {
      logOperationError('Get tab', e);
    }
  };
  /**
   * Updates tab url
   * @param {number} tabId
   * @param {string} url
   */


  const updateUrl = async (tabId, url) => {
    if (tabId === 0) {
      return;
    }

    try {
      await browser_polyfill_default().tabs.update(tabId, {
        url
      });
    } catch (e) {
      log.error(new Error(e.message));
    }
  };
  /**
   * True if `browser.tabs.insertCSS` supports `cssOrigin: "user"`.
   */


  let userCSSSupport = true;
  /**
   * Inserts CSS using the `browser.tabs.insertCSS` under the hood.
   * This method always injects CSS using `runAt: document_start`/
   *
   * @param {number} tabId Tab id or null if you want to inject into the active tab
   * @param {number} requestFrameId Target frame id (CSS will be inserted into that frame)
   * @param {number} code CSS code to insert
   */

  const insertCssCode = !(browser_polyfill_default()).tabs.insertCSS ? undefined : async (tabId, requestFrameId, code) => {
    const injectDetails = {
      code,
      runAt: 'document_start',
      frameId: requestFrameId,
      matchAboutBlank: true
    };

    if (userCSSSupport) {
      // If this is set for not supporting browser, it will throw an error.
      injectDetails.cssOrigin = 'user';
    }

    try {
      await browser_polyfill_default().tabs.insertCSS(tabId, injectDetails);
    } catch (e) {
      // e.message in edge is undefined
      const errorMessage = e.message || e; // Some browsers do not support user css origin // TODO which one?

      if (/\bcssOrigin\b/.test(errorMessage)) {
        userCSSSupport = false;
      }
    }
  };
  /**
   * Executes the specified JS code using `browser.tabs.executeScript` under the hood.
   * This method forces `runAt: document_start`.
   *
   * @param {number} tabId Tab id or null if you want to inject into the active tab
   * @param {requestFrameId} requestFrameId Target frame id (script will be injected into that frame)
   * @param {requestFrameId} code Javascript code to execute
   */

  const executeScriptCode = !(browser_polyfill_default()).tabs.executeScript ? undefined : async (tabId, requestFrameId, code) => {
    try {
      await browser_polyfill_default().tabs.executeScript(tabId, {
        code,
        frameId: requestFrameId,
        runAt: 'document_start',
        matchAboutBlank: true
      });
    } catch (e) {
      log.debug(new Error(e.message));
    }
  };
  /**
   * Executes the specified javascript file in the top frame of the specified tab.
   * This method forces `runAt: document_start`.
   *
   * @param {number} tabId Tab id or null if you want to inject into the active tab
   * @param {Object} options
   * @param {string} options.file - Path to the javascript file
   * @param {number} [options.frameId=0] - id of the frame, default to the 0;
   * @param {function} callback Called when the script injection is complete
   */

  const executeScriptFile = !(browser_polyfill_default()).tabs.executeScript ? undefined : async (tabId, options) => {
    const {
      file,
      frameId = 0
    } = options;
    const executeScriptOptions = {
      file,
      runAt: 'document_start'
    }; // Chrome 49 throws an exception if browser.tabs.executeScript is called
    // with a frameId equal to 0

    if (frameId !== 0) {
      executeScriptOptions.frameId = frameId;
    }

    try {
      await browser_polyfill_default().tabs.executeScript(tabId, executeScriptOptions);
    } catch (e) {
      log.debug(new Error(e.message));
    }
  };
  return {
    onCreated: onCreatedChannel,
    onRemoved: onRemovedChannel,
    onUpdated: onUpdatedChannel,
    onActivated: onActivatedChannel,
    create,
    remove,
    activate,
    reload,
    sendMessage,
    getAll,
    getActive,
    get,
    updateUrl,
    insertCssCode,
    executeScriptCode,
    executeScriptFile
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/tabs/tabs-api.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */



const tabsApi = (tabsImpl => {
  const tabs = Object.create(null); // Fired when a tab is created. Note that the tab's URL may not be set at the time
  // this event fired, but you can listen to onUpdated events to be notified when a URL is set.

  const onCreatedChannel = utils.channels.newChannel(); // Fired when a tab is closed.

  const onRemovedChannel = utils.channels.newChannel(); // Fired when a tab is updated.

  const onUpdatedChannel = utils.channels.newChannel(); // Fires when the active tab in a window changes.

  const onActivatedChannel = utils.channels.newChannel();
  /**
   * Saves tab to collection and notify listeners
   * @param aTab
   */

  function onTabCreated(aTab) {
    const tab = tabs[aTab.tabId];

    if (tab) {
      // Tab has been already synchronized
      return;
    }

    tabs[aTab.tabId] = aTab;
    onCreatedChannel.notify(aTab);
  } // Synchronize opened tabs


  (async () => {
    const aTabs = await tabsImpl.getAll();

    for (let i = 0; i < aTabs.length; i += 1) {
      const aTab = aTabs[i];
      tabs[aTab.tabId] = aTab;
    }
  })();

  tabsImpl.onCreated.addListener(onTabCreated);
  tabsImpl.onRemoved.addListener(tabId => {
    const tab = tabs[tabId];

    if (tab) {
      onRemovedChannel.notify(tab);
      delete tabs[tabId];
    }
  });
  tabsImpl.onUpdated.addListener(aTab => {
    const tab = tabs[aTab.tabId];

    if (tab) {
      tab.url = aTab.url;
      tab.title = aTab.title;
      tab.status = aTab.status; // If the tab was updated it means that it wasn't used to send requests in the background

      tab.synthetic = false;
      onUpdatedChannel.notify(tab);
    }
  });
  tabsImpl.onActivated.addListener(tabId => {
    const tab = tabs[tabId];

    if (tab) {
      onActivatedChannel.notify(tab);
    }
  }); // --------- Actions ---------
  // Creates a new tab.

  const create = async details => {
    return tabsImpl.create(details);
  }; // Closes tab.


  const remove = async tabId => {
    return tabsImpl.remove(tabId);
  }; // Activates tab (Also makes tab's window in focus).


  const activate = function (tabId) {
    return tabsImpl.activate(tabId);
  }; // Reloads tab.


  const reload = async (tabId, url) => {
    await tabsImpl.reload(tabId, url);
  }; // Updates tab url


  const updateUrl = (tabId, url) => {
    tabsImpl.updateUrl(tabId, url);
  }; // Sends message to tab


  const sendMessage = function (tabId, message, options) {
    return tabsImpl.sendMessage(tabId, message, options);
  };
  /**
   * Sometimes chrome does not return url and title on tab update events,
   * but returns tabs with urls when tabs are requested by tabs api
   * That is why during getting tabs we sync their urls with actual values
   */


  const syncTabs = (targetTabs, actualTab) => {
    const {
      tabId
    } = actualTab;
    const tab = targetTabs[tabId];

    if (!tab) {
      targetTabs[tabId] = actualTab;
      return actualTab;
    }

    if (!tab.url && actualTab.url) {
      tab.url = actualTab.url;
    }

    if (!tab.title && actualTab.title) {
      tab.title = actualTab.title;
    } // update tab state in the target tabs array


    targetTabs[tabId] = tab;
    return tab;
  }; // Gets all opened tabs


  const getAll = async () => {
    const aTabs = await tabsImpl.getAll();
    const result = [];

    for (let i = 0; i < aTabs.length; i += 1) {
      const aTab = aTabs[i];
      const tab = syncTabs(tabs, aTab);
      result.push(tab);
    }

    return result;
  }; // Calls callback with each tab


  const forEach = function (callback) {
    (async () => {
      const aTabs = await tabsImpl.getAll();

      for (let i = 0; i < aTabs.length; i += 1) {
        const aTab = aTabs[i];
        let tab = tabs[aTab.tabId];

        if (!tab) {
          // Synchronize state
          tabs[aTab.tabId] = aTab;
          tab = aTab;
        }

        callback(tab);
      }
    })();
  }; // Gets active tab


  const getActive = async tabId => {
    if (!tabId) {
      tabId = await tabsImpl.getActive();
    }

    if (!tabId) {
      return null;
    }

    let tab = tabs[tabId];

    if (tab) {
      if (!tab.url || !tab.title) {
        const aTab = await tabsImpl.get(tabId);

        if (aTab) {
          syncTabs(tabs, aTab);
        }
      }

      return tab;
    } // Tab not found in the local state, but we are sure that this tab exists. Sync...
    // TODO[Edge]: Relates to Edge Bug https://github.com/AdguardTeam/AdguardBrowserExtension/issues/481


    tab = await tabsImpl.get(tabId);
    onTabCreated(tab);
    return tab;
  };

  const isIncognito = function (tabId) {
    const tab = tabs[tabId];
    return tab && tab.incognito === true;
  }; // Records tab's frame


  const recordTabFrame = function (tabId, frameId, url, domainName) {
    let tab = tabs[tabId];

    if (!tab && frameId === 0) {
      // Sync tab for that 'onCreated' event was missed.
      // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/481
      tab = {
        tabId,
        url,
        status: 'loading',
        // We mark this tabs as synthetic because actually they may not exists
        synthetic: true
      };
      onTabCreated(tab);
    }

    if (tab) {
      if (!tab.frames) {
        tab.frames = Object.create(null);
      }

      tab.frames[frameId] = {
        url,
        domainName
      };
    }
  };

  const clearTabFrames = function (tabId) {
    const tab = tabs[tabId];

    if (tab) {
      tab.frames = null;
    }
  }; // Gets tab's frame by id


  const getTabFrame = function (tabId, frameId) {
    const tab = tabs[tabId];

    if (tab && tab.frames) {
      return tab.frames[frameId || 0];
    }

    return null;
  };
  /**
   * Checks if the tab is new tab for popup or not
   * May be false positive for FF at least because new tab url in FF is "about:blank" too
   * @param tabId
   * @returns {boolean}
   */


  const isNewPopupTab = tabId => {
    const tab = tabs[tabId];

    if (!tab) {
      return false;
    }

    return !!(tab.url === '' || tab.url === 'about:blank');
  }; // Update tab metadata


  const updateTabMetadata = function (tabId, values) {
    const tab = tabs[tabId];

    if (tab) {
      if (!tab.metadata) {
        tab.metadata = Object.create(null);
      } // eslint-disable-next-line no-restricted-syntax


      for (const key in values) {
        if (values.hasOwnProperty && values.hasOwnProperty(key)) {
          tab.metadata[key] = values[key];
        }
      }
    }
  }; // Gets tab metadata


  const getTabMetadata = (tabId, key) => {
    const tab = tabs[tabId];

    if (tab && tab.metadata) {
      return tab.metadata[key];
    }

    return null;
  };

  const clearTabMetadata = tabId => {
    const tab = tabs[tabId];

    if (tab) {
      tab.metadata = null;
    }
  }; // Injecting resources to tabs


  const {
    insertCssCode
  } = tabsImpl;
  const {
    executeScriptCode
  } = tabsImpl;
  const {
    executeScriptFile
  } = tabsImpl;
  return {
    // Events
    onCreated: onCreatedChannel,
    onRemoved: onRemovedChannel,
    onUpdated: onUpdatedChannel,
    onActivated: onActivatedChannel,
    // Actions
    create,
    remove,
    activate,
    reload,
    sendMessage,
    getAll,
    forEach,
    getActive,
    isIncognito,
    updateUrl,
    // Frames
    recordTabFrame,
    clearTabFrames,
    getTabFrame,
    isNewPopupTab,
    // Other
    updateTabMetadata,
    getTabMetadata,
    clearTabMetadata,
    insertCssCode,
    executeScriptCode,
    executeScriptFile
  };
})(tabsImpl);


;// CONCATENATED MODULE: ./Extension/src/background/utils/browser-utils.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







const browserUtils = function () {
  /**
   * Extension version (x.x.x)
   * @param version
   * @constructor
   */
  const Version = function (version) {
    this.version = Object.create(null);
    const parts = String(version || '').split('.');

    function parseVersionPart(part) {
      if (Number.isNaN(part)) {
        return 0;
      }

      return Math.max(part - 0, 0);
    }

    for (let i = 3; i >= 0; i -= 1) {
      this.version[i] = parseVersionPart(parts[i]);
    }
  };
  /**
   * Compares with other version
   * @param o
   * @returns {number}
   */


  Version.prototype.compare = function (o) {
    for (let i = 0; i < 4; i += 1) {
      if (this.version[i] > o.version[i]) {
        return 1;
      }

      if (this.version[i] < o.version[i]) {
        return -1;
      }
    }

    return 0;
  };

  const browserUtils = {
    getClientId() {
      let clientId = storage_localStorage.getItem('client-id');

      if (!clientId) {
        const result = [];
        const suffix = Date.now() % 1e8;
        const symbols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890';

        for (let i = 0; i < 8; i += 1) {
          const symbol = symbols[Math.floor(Math.random() * symbols.length)];
          result.push(symbol);
        }

        clientId = result.join('') + suffix;
        storage_localStorage.setItem('client-id', clientId);
      }

      return clientId;
    },

    /**
     * Checks if version matches simple (without labels) semantic versioning scheme
     * https://semver.org/
     * @param {string} version
     * @return {boolean}
     */
    isSemver(version) {
      const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
      return semverRegex.test(version);
    },

    /**
     * Checks if left version is greater than the right version
     */
    isGreaterVersion(leftVersion, rightVersion) {
      const left = new Version(leftVersion);
      const right = new Version(rightVersion);
      return left.compare(right) > 0;
    },

    isGreaterOrEqualsVersion(leftVersion, rightVersion) {
      const left = new Version(leftVersion);
      const right = new Version(rightVersion);
      return left.compare(right) >= 0;
    },

    /**
     * Returns major number of version
     *
     * @param version
     */
    getMajorVersionNumber(version) {
      const v = new Version(version);
      return v.version[0];
    },

    /**
     * Returns minor number of version
     *
     * @param version
     */
    getMinorVersionNumber(version) {
      const v = new Version(version);
      return v.version[1];
    },

    /**
     * @returns Extension version
     */
    getAppVersion() {
      return storage_localStorage.getItem('app-version');
    },

    setAppVersion(version) {
      storage_localStorage.setItem('app-version', version);
    },

    isYaBrowser() {
      return prefs.browser === 'YaBrowser';
    },

    isOperaBrowser() {
      return prefs.browser === 'Opera';
    },

    isEdgeBrowser() {
      return prefs.browser === 'Edge';
    },

    isEdgeChromiumBrowser() {
      return prefs.browser === 'EdgeChromium';
    },

    isFirefoxBrowser() {
      return prefs.browser === 'Firefox';
    },

    isChromeBrowser() {
      return prefs.browser === 'Chrome';
    },

    isChromium() {
      return prefs.platform === 'chromium';
    },

    isWindowsOs() {
      return isWindowsOs;
    },

    isMacOs() {
      return isMacOs;
    },

    /**
     * Finds header object by header name (case insensitive)
     * @param headers Headers collection
     * @param headerName Header name
     * @returns {*}
     */
    findHeaderByName(headers, headerName) {
      if (headers) {
        for (let i = 0; i < headers.length; i += 1) {
          const header = headers[i];

          if (header.name.toLowerCase() === headerName.toLowerCase()) {
            return header;
          }
        }
      }

      return null;
    },

    /**
     * Finds header value by name (case insensitive)
     * @param headers Headers collection
     * @param headerName Header name
     * @returns {null}
     */
    getHeaderValueByName(headers, headerName) {
      const header = this.findHeaderByName(headers, headerName);
      return header ? header.value : null;
    },

    /**
     * Set header value. Only for Chrome
     * @param headers
     * @param headerName
     * @param headerValue
     */
    setHeaderValue(headers, headerName, headerValue) {
      if (!headers) {
        headers = [];
      }

      const header = this.findHeaderByName(headers, headerName);

      if (header) {
        header.value = headerValue;
      } else {
        headers.push({
          name: headerName,
          value: headerValue
        });
      }

      return headers;
    },

    /**
     * Removes header from headers by name
     *
     * @param {Array} headers
     * @param {String} headerName
     * @return {boolean} True if header were removed
     */
    removeHeader(headers, headerName) {
      let removed = false;

      if (headers) {
        for (let i = headers.length - 1; i >= 0; i -= 1) {
          const header = headers[i];

          if (header.name.toLowerCase() === headerName.toLowerCase()) {
            headers.splice(i, 1);
            removed = true;
          }
        }
      }

      return removed;
    },

    getSafebrowsingBackUrl(tab) {
      // https://code.google.com/p/chromium/issues/detail?id=11854
      const previousUrl = tabsApi.getTabMetadata(tab.tabId, 'previousUrl');

      if (previousUrl && previousUrl.indexOf('http') === 0) {
        return previousUrl;
      }

      const referrerUrl = tabsApi.getTabMetadata(tab.tabId, 'referrerUrl');

      if (referrerUrl && referrerUrl.indexOf('http') === 0) {
        return referrerUrl;
      }

      return 'about:newtab';
    },

    /**
     * Retrieve languages from navigator
     * @param {number} [limit] Limit of preferred languages
     * @returns {Array}
     */
    getNavigatorLanguages(limit) {
      let languages = []; // https://developer.mozilla.org/ru/docs/Web/API/NavigatorLanguage/languages

      if (collections.isArray(navigator.languages)) {
        // get all languages if 'limit' is not specified
        const langLimit = limit || navigator.languages.length;
        languages = navigator.languages.slice(0, langLimit);
      } else if (navigator.language) {
        languages.push(navigator.language); // .language is first in .languages
      }

      return languages;
    },

    /**
     * Affected issues:
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/602
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/566
     * 'Popup' window
     * Creators update is not yet released, so we use Insider build 15063 instead.
     */
    EDGE_CREATORS_UPDATE: 15063,

    isEdgeBeforeCreatorsUpdate() {
      return this.isEdgeBrowser() && prefs.edgeVersion.build < this.EDGE_CREATORS_UPDATE;
    },

    /**
     * Returns extension params: clientId, version and locale
     */
    getExtensionParams() {
      const clientId = encodeURIComponent(this.getClientId());
      const locale = encodeURIComponent(backgroundPage.app.getLocale());
      const version = encodeURIComponent(backgroundPage.app.getVersion());
      const id = encodeURIComponent(backgroundPage.app.getId());
      const params = [];
      params.push(`v=${version}`);
      params.push(`cid=${clientId}`);
      params.push(`lang=${locale}`);
      params.push(`id=${id}`);
      return params;
    },

    /**
     * @typedef PermissionsObj
     * A Permissions object represents a collection of permissions
     * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/permissions/Permissions
     * @property {Array<string>} permissions
     * @property {Array<string>} [origins]
     */

    /**
     * Checks if extension has required permissions
     * @param {PermissionsObj} permissions
     * @returns {Promise<boolean>}
     */
    containsPermissions: permissions => {
      return browser_polyfill_default().permissions.contains(permissions);
    },

    /**
     * Requests required permissions
     * @param {PermissionsObj} permissions
     * @returns {Promise<boolean>}
     */
    requestPermissions: permissions => {
      return browser_polyfill_default().permissions.request(permissions);
    },

    /**
     * Removes required permissions
     * @param {PermissionsObj} permissions
     * @returns {Promise<boolean>}
     */
    removePermission: permissions => {
      return browser_polyfill_default().permissions.remove(permissions);
    }
  };
  return browserUtils;
}();
;// CONCATENATED MODULE: ./Extension/src/pages/constants.js
/* eslint-disable max-len */
const PRIVACY_URL = 'https://adguard.com/forward.html?action=privacy&from=options_screen&app=browser_extension';
const ACKNOWLEDGMENTS_URL = 'https://adguard.com/forward.html?action=acknowledgments&from=options_screen&app=browser_extension';
const GITHUB_URL = 'https://adguard.com/forward.html?action=github_options&from=options_screen&app=browser_extension';
const WEBSITE_URL = 'https://adguard.com/forward.html?action=adguard_site&from=options_screen_footer&app=browser_extension';
const DISCUSS_URL = 'https://adguard.com/forward.html?action=discuss&from=options_screen&app=browser_extension';
const COMPARE_URL = 'https://adguard.com/forward.html?action=compare&from=options_screen&app=browser_extension';
const CHANGELOG_URL = 'https://adguard.com/forward.html?action=github_version_popup&from=options_screen&app=browser_extension';
const GLOBAL_PRIVACY_CONTROL_URL = 'https://adguard.com/forward.html?action=global_privacy_control&from=options_screen&app=browser_extension';
const DO_NOT_TRACK_URL = 'https://adguard.com/forward.html?action=do_not_track&from=options_screen&app=browser_extension';
const HOW_TO_CREATE_RULES_URL = 'https://adguard.com/forward.html?action=userfilter_description&from=options&app=browser_extension';
const DEFAULT_FIRST_PARTY_COOKIES_SELF_DESTRUCT_MIN = 4320;
const DEFAULT_THIRD_PARTY_COOKIES_SELF_DESTRUCT_MIN = 2880;
const APPEARANCE_THEMES = {
  SYSTEM: 'system',
  DARK: 'dark',
  LIGHT: 'light'
};
;// CONCATENATED MODULE: ./Extension/src/background/settings/user-settings.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */








/**
 * Object that manages user settings.
 * @constructor
 */

const settings = (() => {
  const DEFAULT_FILTERS_UPDATE_PERIOD = -1;
  const settings = {
    DISABLE_DETECT_FILTERS: 'detect-filters-disabled',
    DISABLE_SHOW_PAGE_STATS: 'disable-show-page-statistic',

    /* flag used to show link to comparison of desktop and browser adblocker versions */
    DISABLE_SHOW_ADGUARD_PROMO_INFO: 'show-info-about-adguard-disabled',
    DISABLE_SAFEBROWSING: 'safebrowsing-disabled',
    DISABLE_FILTERING: 'adguard-disabled',
    DISABLE_COLLECT_HITS: 'hits-count-disabled',
    DISABLE_SHOW_CONTEXT_MENU: 'context-menu-disabled',
    USE_OPTIMIZED_FILTERS: 'use-optimized-filters',
    DEFAULT_ALLOWLIST_MODE: 'default-whitelist-mode',
    ALLOWLIST_ENABLED: 'allowlist-enabled',
    DISABLE_SHOW_APP_UPDATED_NOTIFICATION: 'show-app-updated-disabled',
    FILTERS_UPDATE_PERIOD: 'filters-update-period',
    APPEARANCE_THEME: 'appearance-theme',

    /* User filter */
    USER_FILTER_ENABLED: 'user-filter-enabled',

    /* STEALTH MODE */
    DISABLE_STEALTH_MODE: 'stealth_disable_stealth_mode',
    HIDE_REFERRER: 'stealth-hide-referrer',
    HIDE_SEARCH_QUERIES: 'stealth-hide-search-queries',
    SEND_DO_NOT_TRACK: 'stealth-send-do-not-track',
    BLOCK_CHROME_CLIENT_DATA: 'stealth-remove-x-client',
    BLOCK_WEBRTC: 'stealth-block-webrtc',
    SELF_DESTRUCT_THIRD_PARTY_COOKIES: 'stealth-block-third-party-cookies',
    SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME: 'stealth-block-third-party-cookies-time',
    SELF_DESTRUCT_FIRST_PARTY_COOKIES: 'stealth-block-first-party-cookies',
    SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME: 'stealth-block-first-party-cookies-time',

    /* UI misc */
    HIDE_RATE_BLOCK: 'hide-rate-block',
    USER_RULES_EDITOR_WRAP: 'user-rules-editor-wrap'
  };
  const properties = Object.create(null);
  const propertyUpdateChannel = utils.channels.newChannel();
  /**
   * Lazy default properties
   */

  const defaultProperties = {
    get defaults() {
      return lazyGet(this, 'defaults', () => {
        // Initialize default properties
        const defaults = Object.fromEntries(Object.keys(settings).map(name => [name, false]));
        defaults[settings.DISABLE_SHOW_ADGUARD_PROMO_INFO] = !browserUtils.isWindowsOs() && !browserUtils.isMacOs() || browserUtils.isEdgeBrowser();
        defaults[settings.DISABLE_SAFEBROWSING] = true;
        defaults[settings.DISABLE_COLLECT_HITS] = true;
        defaults[settings.DEFAULT_ALLOWLIST_MODE] = true;
        defaults[settings.ALLOWLIST_ENABLED] = true;
        defaults[settings.USE_OPTIMIZED_FILTERS] = prefs.mobile;
        defaults[settings.DISABLE_DETECT_FILTERS] = false;
        defaults[settings.DISABLE_SHOW_APP_UPDATED_NOTIFICATION] = false;
        defaults[settings.FILTERS_UPDATE_PERIOD] = DEFAULT_FILTERS_UPDATE_PERIOD;
        defaults[settings.DISABLE_STEALTH_MODE] = true;
        defaults[settings.HIDE_REFERRER] = true;
        defaults[settings.HIDE_SEARCH_QUERIES] = true;
        defaults[settings.SEND_DO_NOT_TRACK] = true;
        defaults[settings.BLOCK_CHROME_CLIENT_DATA] = !!browserUtils.isChromeBrowser();
        defaults[settings.BLOCK_WEBRTC] = false;
        defaults[settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES] = true;
        defaults[settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME] = DEFAULT_THIRD_PARTY_COOKIES_SELF_DESTRUCT_MIN;
        defaults[settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES] = false;
        defaults[settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME] = DEFAULT_FIRST_PARTY_COOKIES_SELF_DESTRUCT_MIN;
        defaults[settings.APPEARANCE_THEME] = APPEARANCE_THEMES.SYSTEM;
        defaults[settings.USER_FILTER_ENABLED] = true;
        defaults[settings.HIDE_RATE_BLOCK] = false;
        defaults[settings.USER_RULES_EDITOR_WRAP] = false;
        return defaults;
      });
    }

  };

  const getProperty = function (propertyName) {
    if (propertyName in properties) {
      return properties[propertyName];
    }
    /**
     * Don't cache values in case of uninitialized storage
     */


    if (!storage_localStorage.isInitialized()) {
      return defaultProperties.defaults[propertyName];
    }

    let propertyValue = null;

    if (storage_localStorage.hasItem(propertyName)) {
      try {
        propertyValue = JSON.parse(storage_localStorage.getItem(propertyName));
      } catch (ex) {
        log.error('Error get property {0}, cause: {1}', propertyName, ex);
      }
    } else if (propertyName in defaultProperties.defaults) {
      propertyValue = defaultProperties.defaults[propertyName];
    }

    properties[propertyName] = propertyValue;
    return propertyValue;
  };

  const setProperty = (propertyName, propertyValue) => {
    storage_localStorage.setItem(propertyName, JSON.stringify(propertyValue));
    properties[propertyName] = propertyValue;
    propertyUpdateChannel.notify(propertyName, propertyValue);
    listeners.notifyListeners(listeners.SETTING_UPDATED, {
      propertyName,
      propertyValue
    });
  };

  const getAllSettings = function () {
    const result = {
      names: Object.create(null),
      values: Object.create(null),
      defaultValues: Object.create(null)
    };
    Object.entries(settings).forEach(([key, value]) => {
      const setting = settings[key];
      result.names[key] = setting;
      result.values[value] = getProperty(setting);
      result.defaultValues[value] = defaultProperties.defaults[setting];
    });
    return result;
  };
  /**
   * True if filtering is disabled globally.
   *
   * @returns {boolean} true if disabled
   */


  const isFilteringDisabled = function () {
    return getProperty(settings.DISABLE_FILTERING);
  };

  const changeFilteringDisabled = function (disabled) {
    setProperty(settings.DISABLE_FILTERING, disabled);
  };

  const isAutodetectFilters = function () {
    return !getProperty(settings.DISABLE_DETECT_FILTERS);
  };

  const changeAutodetectFilters = function (enabled, options) {
    setProperty(settings.DISABLE_DETECT_FILTERS, !enabled, options);
  };

  const showPageStatistic = function () {
    return !getProperty(settings.DISABLE_SHOW_PAGE_STATS);
  };

  const changeShowPageStatistic = function (enabled, options) {
    setProperty(settings.DISABLE_SHOW_PAGE_STATS, !enabled, options);
  };

  const isShowInfoAboutAdguardFullVersion = function () {
    return !getProperty(settings.DISABLE_SHOW_ADGUARD_PROMO_INFO);
  };

  const changeShowInfoAboutAdguardFullVersion = function (show, options) {
    setProperty(settings.DISABLE_SHOW_ADGUARD_PROMO_INFO, !show, options);
  };

  const isShowAppUpdatedNotification = function () {
    return !getProperty(settings.DISABLE_SHOW_APP_UPDATED_NOTIFICATION);
  };

  const isHideRateBlock = function () {
    return getProperty(settings.HIDE_RATE_BLOCK);
  };

  const isUserRulesEditorWrap = function () {
    return getProperty(settings.USER_RULES_EDITOR_WRAP);
  };

  const changeShowAppUpdatedNotification = function (show, options) {
    setProperty(settings.DISABLE_SHOW_APP_UPDATED_NOTIFICATION, !show, options);
  };

  const changeHideRateBlock = function (hide, options) {
    setProperty(settings.HIDE_RATE_BLOCK, hide, options);
  };

  const changeUserRulesEditorWrap = function (enabled, options) {
    setProperty(settings.USER_RULES_EDITOR_WRAP, enabled, options);
  };

  const changeEnableSafebrowsing = function (enabled, options) {
    setProperty(settings.DISABLE_SAFEBROWSING, !enabled, options);
  };

  const safebrowsingInfoEnabled = function () {
    return !getProperty(settings.DISABLE_SAFEBROWSING);
  };

  const collectHitsCount = function () {
    return !getProperty(settings.DISABLE_COLLECT_HITS);
  };

  const changeCollectHitsCount = function (enabled, options) {
    setProperty(settings.DISABLE_COLLECT_HITS, !enabled, options);
  };

  const showContextMenu = function () {
    return !getProperty(settings.DISABLE_SHOW_CONTEXT_MENU);
  };

  const changeShowContextMenu = function (enabled, options) {
    setProperty(settings.DISABLE_SHOW_CONTEXT_MENU, !enabled, options);
  };

  const isDefaultAllowlistMode = function () {
    return getProperty(settings.DEFAULT_ALLOWLIST_MODE);
  };

  const isUseOptimizedFiltersEnabled = function () {
    return getProperty(settings.USE_OPTIMIZED_FILTERS);
  };

  const changeUseOptimizedFiltersEnabled = function (enabled, options) {
    setProperty(settings.USE_OPTIMIZED_FILTERS, !!enabled, options);
  };

  const changeDefaultAllowlistMode = function (enabled) {
    setProperty(settings.DEFAULT_ALLOWLIST_MODE, enabled);
  };

  const setAllowlistEnabledState = enabled => {
    setProperty(settings.ALLOWLIST_ENABLED, enabled);
  };

  const getAllowlistEnabledState = () => {
    return getProperty(settings.ALLOWLIST_ENABLED);
  };
  /**
   * Sets filters update period after conversion in number
   * @param period
   */


  const setFiltersUpdatePeriod = function (period) {
    let parsed = Number.parseInt(period, 10);

    if (Number.isNaN(parsed)) {
      parsed = DEFAULT_FILTERS_UPDATE_PERIOD;
    }

    setProperty(settings.FILTERS_UPDATE_PERIOD, parsed);
  };
  /**
   * Returns filter update period, converted in number
   * @returns {number}
   */


  const getFiltersUpdatePeriod = function () {
    const value = getProperty(settings.FILTERS_UPDATE_PERIOD);
    let parsed = Number.parseInt(value, 10);

    if (Number.isNaN(parsed)) {
      parsed = DEFAULT_FILTERS_UPDATE_PERIOD;
    }

    return parsed;
  };

  const disableShowAdguardPromoInfo = function () {
    setProperty(settings.DISABLE_SHOW_ADGUARD_PROMO_INFO, true);
  };

  const isDisableShowAdguardPromoInfo = function () {
    return getProperty(settings.DISABLE_SHOW_ADGUARD_PROMO_INFO);
  };

  const getDisableStealthMode = () => getProperty(settings.DISABLE_STEALTH_MODE);

  const getSelfDestructThirdPartyCookies = () => getProperty(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES);

  const getSelfDestructThirdPartyCookiesTime = () => getProperty(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME);

  const getSelfDestructFirstPartyCookies = () => getProperty(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES);

  const getSelfDestructFirstPartyCookiesTime = () => getProperty(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME);

  const getHideReferrer = () => getProperty(settings.HIDE_REFERRER);

  const getHideSearchQueries = () => getProperty(settings.HIDE_SEARCH_QUERIES);

  const getSendDoNotTrack = () => getProperty(settings.SEND_DO_NOT_TRACK);

  const isWebRTCDisabled = () => getProperty(settings.BLOCK_WEBRTC);

  const isRemoveXClientData = () => getProperty(settings.BLOCK_CHROME_CLIENT_DATA);

  const getAppearanceTheme = () => getProperty(settings.APPEARANCE_THEME);

  const setDisableStealthMode = value => {
    setProperty(settings.DISABLE_STEALTH_MODE, value);
  };

  const setSelfDestructThirdPartyCookies = value => {
    setProperty(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES, value);
  };

  const setSelfDestructThirdPartyCookiesTime = value => {
    setProperty(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME, value);
  };

  const setSelfDestructFirstPartyCookies = value => {
    setProperty(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES, value);
  };

  const setSelfDestructFirstPartyCookiesTime = value => {
    setProperty(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME, value);
  };

  const setHideReferrer = value => {
    setProperty(settings.HIDE_REFERRER, value);
  };

  const setHideSearchQueries = value => {
    setProperty(settings.HIDE_SEARCH_QUERIES, value);
  };

  const setSendDoNotTrack = value => {
    setProperty(settings.SEND_DO_NOT_TRACK, value);
  };

  const setWebRTCDisabled = value => {
    setProperty(settings.BLOCK_WEBRTC, value);
  };

  const setRemoveXClientData = value => {
    setProperty(settings.BLOCK_CHROME_CLIENT_DATA, value);
  };

  const setAppearanceTheme = theme => {
    const isExistingTheme = Object.values(APPEARANCE_THEMES).some(t => t === theme);

    if (!isExistingTheme) {
      setProperty(settings.APPEARANCE_THEME, defaultProperties.defaults[settings.APPEARANCE_THEME]);
    } else {
      setProperty(settings.APPEARANCE_THEME, theme);
    }
  };

  const getUserFilterEnabled = () => {
    return getProperty(settings.USER_FILTER_ENABLED);
  };

  const setUserFilterEnabled = state => {
    setProperty(settings.USER_FILTER_ENABLED, state);
  };

  const api = { ...settings
  };
  api.getProperty = getProperty;
  api.setProperty = setProperty;
  api.getAllSettings = getAllSettings;
  api.onUpdated = propertyUpdateChannel;
  api.isFilteringDisabled = isFilteringDisabled;
  api.changeFilteringDisabled = changeFilteringDisabled;
  api.isAutodetectFilters = isAutodetectFilters;
  api.changeAutodetectFilters = changeAutodetectFilters;
  api.showPageStatistic = showPageStatistic;
  api.changeShowPageStatistic = changeShowPageStatistic;
  api.isShowInfoAboutAdguardFullVersion = isShowInfoAboutAdguardFullVersion;
  api.changeShowInfoAboutAdguardFullVersion = changeShowInfoAboutAdguardFullVersion;
  api.isShowAppUpdatedNotification = isShowAppUpdatedNotification;
  api.isHideRateBlock = isHideRateBlock;
  api.isUserRulesEditorWrap = isUserRulesEditorWrap;
  api.changeShowAppUpdatedNotification = changeShowAppUpdatedNotification;
  api.changeHideRateBlock = changeHideRateBlock;
  api.changeUserRulesEditorWrap = changeUserRulesEditorWrap;
  api.changeEnableSafebrowsing = changeEnableSafebrowsing;
  api.safebrowsingInfoEnabled = safebrowsingInfoEnabled;
  api.collectHitsCount = collectHitsCount;
  api.changeCollectHitsCount = changeCollectHitsCount;
  api.showContextMenu = showContextMenu;
  api.changeShowContextMenu = changeShowContextMenu;
  api.isDefaultAllowlistMode = isDefaultAllowlistMode;
  api.isUseOptimizedFiltersEnabled = isUseOptimizedFiltersEnabled;
  api.changeUseOptimizedFiltersEnabled = changeUseOptimizedFiltersEnabled;
  api.changeDefaultAllowlistMode = changeDefaultAllowlistMode;
  api.setAllowlistEnabledState = setAllowlistEnabledState;
  api.getAllowlistEnabledState = getAllowlistEnabledState;
  api.getFiltersUpdatePeriod = getFiltersUpdatePeriod;
  api.setFiltersUpdatePeriod = setFiltersUpdatePeriod;
  api.disableShowAdguardPromoInfo = disableShowAdguardPromoInfo;
  api.isDisableShowAdguardPromoInfo = isDisableShowAdguardPromoInfo;
  api.DEFAULT_FILTERS_UPDATE_PERIOD = DEFAULT_FILTERS_UPDATE_PERIOD;
  api.getDisableStealthMode = getDisableStealthMode;
  api.getSelfDestructThirdPartyCookies = getSelfDestructThirdPartyCookies;
  api.getSelfDestructThirdPartyCookiesTime = getSelfDestructThirdPartyCookiesTime;
  api.getSelfDestructFirstPartyCookies = getSelfDestructFirstPartyCookies;
  api.getSelfDestructFirstPartyCookiesTime = getSelfDestructFirstPartyCookiesTime;
  api.getHideReferrer = getHideReferrer;
  api.getHideSearchQueries = getHideSearchQueries;
  api.getSendDoNotTrack = getSendDoNotTrack;
  api.isWebRTCDisabled = isWebRTCDisabled;
  api.isRemoveXClientData = isRemoveXClientData;
  api.setDisableStealthMode = setDisableStealthMode;
  api.setSelfDestructThirdPartyCookies = setSelfDestructThirdPartyCookies;
  api.setSelfDestructThirdPartyCookiesTime = setSelfDestructThirdPartyCookiesTime;
  api.setSelfDestructFirstPartyCookies = setSelfDestructFirstPartyCookies;
  api.setSelfDestructFirstPartyCookiesTime = setSelfDestructFirstPartyCookiesTime;
  api.setHideReferrer = setHideReferrer;
  api.setHideSearchQueries = setHideSearchQueries;
  api.setSendDoNotTrack = setSendDoNotTrack;
  api.setWebRTCDisabled = setWebRTCDisabled;
  api.setRemoveXClientData = setRemoveXClientData; // Appearance mode methods

  api.setAppearanceTheme = setAppearanceTheme;
  api.getAppearanceTheme = getAppearanceTheme; // User filter settings

  api.getUserFilterEnabled = getUserFilterEnabled;
  api.setUserFilterEnabled = setUserFilterEnabled; // Default properties

  api.defaultProperties = defaultProperties.defaults;
  return api;
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/allowlist.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







/**
 * Read domains and initialize filters in a lazy manner
 */

class DomainsHolder {
  constructor(storageKey) {
    this.storageKey = storageKey;
  }
  /**
   * Retrieves domains from local storage
   * @param prop
   * @returns {string[]}
   */


  static getDomainsFromLocalStorage(prop) {
    let domains = [];

    try {
      const json = storage_localStorage.getItem(prop);

      if (json) {
        domains = JSON.parse(json);
      }
    } catch (ex) {
      log.error('Error retrieving the allowlist domains {0}, cause {1}', prop, ex);
    }

    return domains;
  }

  get domains() {
    return lazyGet(this, 'domains', () => {
      return DomainsHolder.getDomainsFromLocalStorage(this.storageKey);
    });
  }

  add(domain) {
    if (this.domains.indexOf(domain) < 0) {
      this.domains.push(domain);
    }
  }

  includes(domain) {
    return this.domains.some(d => {
      return d === domain || utils.url.getCroppedDomainName(d) === domain;
    });
  }

}

const allowlist = (() => {
  const ALLOWLIST_DOMAINS_LS_PROP = 'white-list-domains';
  const BLOCKLIST_DOMAINS_LS_PROP = 'block-list-domains';
  /**
   * Rule which is returned, when allowlist is inverted
   * @type {NetworkRule}
   */

  const allowAllAllowlistRule = new tsurlfilter_browser.NetworkRule('@@allowlist-all$document', utils.filters.ALLOWLIST_FILTER_ID);
  /**
   * Returns allowlist mode
   * In default mode the filtering is enabled for all sites
   * In inverted model the filtering is disabled for all sites
   */

  function isDefaultAllowlistMode() {
    return settings.isDefaultAllowlistMode();
  }

  const allowlistDomainsHolder = new DomainsHolder(ALLOWLIST_DOMAINS_LS_PROP);
  const blocklistDomainsHolder = new DomainsHolder(BLOCKLIST_DOMAINS_LS_PROP);

  function notifyAllowlistUpdated() {
    listeners.notifyListeners(listeners.UPDATE_ALLOWLIST_FILTER_RULES);
  }
  /**
   * Create allowlist rule from input text
   * @param domain Domain
   * @returns {*}
   * @private
   */


  function createAllowlistRule(domain) {
    if (utils.strings.isEmpty(domain)) {
      return null;
    }

    return new tsurlfilter_browser.NetworkRule(`@@//${domain}$document`, utils.filters.ALLOWLIST_FILTER_ID);
  }
  /**
   * Adds domain to array of allowlist domains
   * @param domain
   */


  function addDomainToAllowlist(domain) {
    if (!domain) {
      return;
    }

    if (isDefaultAllowlistMode()) {
      allowlistDomainsHolder.add(domain);
    } else {
      blocklistDomainsHolder.add(domain);
    }
  }
  /**
   * Remove domain form allowlist domains
   * @param domain
   */


  function removeDomainFromAllowlist(domain) {
    if (!domain) {
      return;
    }
    /**
     * Match domains from collection if they equal exactly do domain
     * and if they equal to domain after removing www
     */


    const predicate = domainFromCollection => {
      return domainFromCollection === domain || utils.url.getCroppedDomainName(domainFromCollection) === domain;
    };

    if (isDefaultAllowlistMode()) {
      utils.collections.removeBy(allowlistDomainsHolder.domains, predicate);
    } else {
      utils.collections.removeBy(blocklistDomainsHolder.domains, predicate);
    }
  }
  /**
   * Save domains to local storage
   */


  function saveDomainsToLocalStorage() {
    storage_localStorage.setItem(ALLOWLIST_DOMAINS_LS_PROP, JSON.stringify(allowlistDomainsHolder.domains));
    storage_localStorage.setItem(BLOCKLIST_DOMAINS_LS_PROP, JSON.stringify(blocklistDomainsHolder.domains));
  }
  /**
   * Remove domain from allowlist
   * @param domain
   */


  function removeFromAllowlist(domain) {
    removeDomainFromAllowlist(domain);
    saveDomainsToLocalStorage();
    notifyAllowlistUpdated();
  }
  /**
   * Adds domain to allowlist
   * @param domain
   */


  function addToAllowlist(domain) {
    if (utils.strings.isEmpty(domain)) {
      return;
    }

    addDomainToAllowlist(domain);
    saveDomainsToLocalStorage();
    notifyAllowlistUpdated();
  }
  /**
   * Search for allowlist rule by url.
   */


  const findAllowlistRule = function (url) {
    if (!url) {
      return null;
    }

    const host = utils.url.getDomainName(url);
    const allowlistEnabled = settings.getAllowlistEnabledState();

    if (isDefaultAllowlistMode()) {
      if (allowlistEnabled && allowlistDomainsHolder.includes(host)) {
        return createAllowlistRule(host);
      }

      return null;
    } // condition for inverted mode


    if (allowlistEnabled && blocklistDomainsHolder.includes(host)) {
      // filtering is enabled on this website
      return null;
    }

    return allowAllAllowlistRule;
  };
  /**
   * Changes allowlist mode
   * @param defaultMode
   */


  const changeDefaultAllowlistMode = function (defaultMode) {
    settings.changeDefaultAllowlistMode(defaultMode);
    notifyAllowlistUpdated();
  };
  /**
   * Stop (or start in case of inverted mode) filtration for url
   * @param url
   */


  const allowlistUrl = function (url) {
    const domain = utils.url.getDomainName(url);

    if (isDefaultAllowlistMode()) {
      addToAllowlist(domain);
    } else {
      removeFromAllowlist(domain);
    }
  };
  /**
   * Start (or stop in case of inverted mode) filtration for url
   * @param url
   */


  const unAllowlistUrl = function (url) {
    const domain = utils.url.getDomainName(url);

    if (isDefaultAllowlistMode()) {
      removeFromAllowlist(domain);
    } else {
      addToAllowlist(domain);
    }
  };
  /**
   * Clear allowlisted only
   */


  const clearAllowlisted = function () {
    storage_localStorage.removeItem(ALLOWLIST_DOMAINS_LS_PROP);
    lazyGetClear(allowlistDomainsHolder, 'domains');
  };
  /**
   * Add domains to allowlist
   * @param domains
   */


  const addAllowlisted = function (domains) {
    if (!domains) {
      return;
    }

    for (let i = 0; i < domains.length; i += 1) {
      const domain = domains[i];
      allowlistDomainsHolder.add(domain);
    }

    saveDomainsToLocalStorage();
  };
  /**
   * Clear blocklisted only
   */


  const clearBlocklisted = function () {
    storage_localStorage.removeItem(BLOCKLIST_DOMAINS_LS_PROP);
    lazyGetClear(blocklistDomainsHolder, 'domains');
  };
  /**
   * Add domains to blocklist
   * @param domains
   */


  const addBlocklisted = function (domains) {
    if (!domains) {
      return;
    }

    for (let i = 0; i < domains.length; i += 1) {
      const domain = domains[i];
      blocklistDomainsHolder.add(domain);
    }

    saveDomainsToLocalStorage();
  };
  /**
   * Updates domains in allowlist
   * @param domains
   */


  const updateAllowlistDomains = function (domains) {
    domains = domains || [];

    if (isDefaultAllowlistMode()) {
      clearAllowlisted();
      addAllowlisted(domains);
    } else {
      clearBlocklisted();
      addBlocklisted(domains);
    }

    notifyAllowlistUpdated();
  };
  /**
   * Configures allowlist service
   * @param allowlist Allowlist domains
   * @param blocklist Blocklist domains
   * @param allowlistMode Allowlist mode
   */


  const configure = function ({
    allowlist,
    blocklist,
    mode,
    enabled
  }) {
    clearAllowlisted();
    clearBlocklisted();
    addAllowlisted(allowlist || []);
    addBlocklisted(blocklist || []);
    settings.changeDefaultAllowlistMode(mode);
    settings.setAllowlistEnabledState(enabled);
    notifyAllowlistUpdated();
  };
  /**
   * Returns the array of allowlist domains
   */


  const getAllowlistDomains = function () {
    if (isDefaultAllowlistMode()) {
      return allowlistDomainsHolder.domains;
    }

    return blocklistDomainsHolder.domains;
  };
  /**
   * Returns the array of allowlisted domains
   */


  const getAllowlistedDomains = function () {
    return allowlistDomainsHolder.domains;
  };
  /**
   * Returns the array of blocklisted domains, inverted mode
   */


  const getBlocklistedDomains = function () {
    return blocklistDomainsHolder.domains;
  };
  /**
   * Initializes allowlist filter
   */


  const init = function () {
    /**
     * Access to allowlist/blacklist domains before the proper initialization of localStorage
     * leads to wrong caching of its values
     * To prevent it we should clear cached values
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/933
     */
    lazyGetClear(allowlistDomainsHolder, 'domains');
    lazyGetClear(blocklistDomainsHolder, 'domains');
  };

  return {
    init,
    configure,
    getAllowlistDomains,
    getAllowlistedDomains,
    getBlocklistedDomains,
    updateAllowlistDomains,
    findAllowlistRule,
    allowlistUrl,
    unAllowlistUrl,
    isDefaultMode: isDefaultAllowlistMode,
    changeDefaultAllowlistMode
  };
})();
;// CONCATENATED MODULE: ./node_modules/nanoid/index.browser.js

let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))
let customRandom = (alphabet, defaultSize, getRandom) => {
  let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1
  let step = -~((1.6 * mask * defaultSize) / alphabet.length)
  return (size = defaultSize) => {
    let id = ''
    while (true) {
      let bytes = getRandom(step)
      let j = step
      while (j--) {
        id += alphabet[bytes[j] & mask] || ''
        if (id.length === size) return id
      }
    }
  }
}
let customAlphabet = (alphabet, size = 21) =>
  customRandom(alphabet, size, random)
let nanoid = (size = 21) => {
  let id = ''
  let bytes = crypto.getRandomValues(new Uint8Array(size))
  while (size--) {
    let byte = bytes[size] & 63
    if (byte < 36) {
      id += byte.toString(36)
    } else if (byte < 62) {
      id += (byte - 26).toString(36).toUpperCase()
    } else if (byte < 63) {
      id += '_'
    } else {
      id += '-'
    }
  }
  return id
}


;// CONCATENATED MODULE: ./node_modules/@adguard/translate/dist/index.esm.js
function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }

  return obj;
}

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

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

function _createClass(Constructor, protoProps, staticProps) {
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  if (staticProps) _defineProperties(Constructor, staticProps);
  return Constructor;
}

function _arrayLikeToArray(arr, len) {
  if (len == null || len > arr.length) len = arr.length;

  for (var i = 0, arr2 = new Array(len); i < len; i++) {
    arr2[i] = arr[i];
  }

  return arr2;
}

function _arrayWithoutHoles(arr) {
  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}

function _iterableToArray(iter) {
  if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}

function _unsupportedIterableToArray(o, minLen) {
  if (!o) return;
  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
  var n = Object.prototype.toString.call(o).slice(8, -1);
  if (n === "Object" && o.constructor) n = o.constructor.name;
  if (n === "Map" || n === "Set") return Array.from(o);
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}

function _nonIterableSpread() {
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}

function _toConsumableArray(arr) {
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}

var NODE_TYPES;

(function (NODE_TYPES) {
  NODE_TYPES["PLACEHOLDER"] = "placeholder";
  NODE_TYPES["TEXT"] = "text";
  NODE_TYPES["TAG"] = "tag";
  NODE_TYPES["VOID_TAG"] = "void_tag";
})(NODE_TYPES || (NODE_TYPES = {}));

var isTextNode = function isTextNode(node) {
  return node.type === NODE_TYPES.TEXT;
};
var isTagNode = function isTagNode(node) {
  return node.type === NODE_TYPES.TAG;
};
var isPlaceholderNode = function isPlaceholderNode(node) {
  return node.type === NODE_TYPES.PLACEHOLDER;
};
var isVoidTagNode = function isVoidTagNode(node) {
  return node.type === NODE_TYPES.VOID_TAG;
};
var placeholderNode = function placeholderNode(value) {
  return {
    type: NODE_TYPES.PLACEHOLDER,
    value: value
  };
};
var textNode = function textNode(str) {
  return {
    type: NODE_TYPES.TEXT,
    value: str
  };
};
var tagNode = function tagNode(tagName, children) {
  var value = tagName.trim();
  return {
    type: NODE_TYPES.TAG,
    value: value,
    children: children
  };
};
var voidTagNode = function voidTagNode(tagName) {
  var value = tagName.trim();
  return {
    type: NODE_TYPES.VOID_TAG,
    value: value
  };
};
/**
 * Checks if target is node
 * @param target
 */

var isNode = function isNode(target) {
  if (typeof target === 'string') {
    return false;
  }

  return !!target.type;
};

var STATE;

(function (STATE) {
  /**
   * Parser function switches to the text state when parses simple text,
   * or content between open and close tags
   */
  STATE["TEXT"] = "text";
  /**
   * Parser function switches to the tag state when meets open tag brace ("<"), and switches back,
   * when meets closing tag brace (">")
   */

  STATE["TAG"] = "tag";
  /**
   * Parser function switches to the placeholder state when meets in the text
   * open placeholders brace ("{") and switches back to the text state,
   * when meets close placeholder brace ("}")
   */

  STATE["PLACEHOLDER"] = "placeholder";
})(STATE || (STATE = {}));

var CONTROL_CHARS = {
  TAG_OPEN_BRACE: '<',
  TAG_CLOSE_BRACE: '>',
  CLOSING_TAG_MARK: '/',
  PLACEHOLDER_MARK: '%'
};
/**
 * Checks if text length is enough to create text node
 * If text node created, then if stack is not empty it is pushed into stack,
 * otherwise into result
 * @param context
 */

var createTextNodeIfPossible = function createTextNodeIfPossible(context) {
  var text = context.text;

  if (text.length > 0) {
    var node = textNode(text);

    if (context.stack.length > 0) {
      context.stack.push(node);
    } else {
      context.result.push(node);
    }
  }

  context.text = '';
};
/**
 * Checks if lastFromStack tag has any attributes
 * @param lastFromStack
 */


var hasAttributes = function hasAttributes(lastFromStack) {
  // e.g. "a class" or "a href='#'"
  var tagStrParts = lastFromStack.split(' ');
  return tagStrParts.length > 1;
};
/**
 * Handles text state
 */


var textStateHandler = function textStateHandler(context) {
  var currChar = context.currChar,
      currIdx = context.currIdx; // switches to the tag state

  if (currChar === CONTROL_CHARS.TAG_OPEN_BRACE) {
    context.lastTextStateChangeIdx = currIdx;
    return STATE.TAG;
  } // switches to the placeholder state


  if (currChar === CONTROL_CHARS.PLACEHOLDER_MARK) {
    context.lastTextStateChangeIdx = currIdx;
    return STATE.PLACEHOLDER;
  } // remains in the text state


  context.text += currChar;
  return STATE.TEXT;
};
/**
 * Handles placeholder state
 * @param context
 */


var placeholderStateHandler = function placeholderStateHandler(context) {
  var currChar = context.currChar,
      currIdx = context.currIdx,
      lastTextStateChangeIdx = context.lastTextStateChangeIdx,
      placeholder = context.placeholder,
      stack = context.stack,
      result = context.result,
      str = context.str;

  if (currChar === CONTROL_CHARS.PLACEHOLDER_MARK) {
    // if distance between current index and last state change equal to 1,
    // it means that placeholder mark was escaped by itself e.g. "%%",
    // so we return to the text state
    if (currIdx - lastTextStateChangeIdx === 1) {
      context.text += str.substring(lastTextStateChangeIdx, currIdx);
      return STATE.TEXT;
    }

    createTextNodeIfPossible(context);
    var node = placeholderNode(placeholder); // push node to the appropriate stack

    if (stack.length > 0) {
      stack.push(node);
    } else {
      result.push(node);
    }

    context.placeholder = '';
    return STATE.TEXT;
  }

  context.placeholder += currChar;
  return STATE.PLACEHOLDER;
};
/**
 * Switches current state to the tag state and returns tag state handler
 */


var tagStateHandler = function tagStateHandler(context) {
  var currChar = context.currChar,
      text = context.text,
      stack = context.stack,
      result = context.result,
      lastTextStateChangeIdx = context.lastTextStateChangeIdx,
      currIdx = context.currIdx,
      str = context.str;
  var tag = context.tag; // if found tag end ">"

  if (currChar === CONTROL_CHARS.TAG_CLOSE_BRACE) {
    // if the tag is close tag e.g. </a>
    if (tag.indexOf(CONTROL_CHARS.CLOSING_TAG_MARK) === 0) {
      // remove slash from tag
      tag = tag.substring(1);
      var children = [];

      if (text.length > 0) {
        children.push(textNode(text));
        context.text = '';
      }

      var pairTagFound = false; // looking for the pair to the close tag

      while (!pairTagFound && stack.length > 0) {
        var lastFromStack = stack.pop(); // if tag from stack equal to close tag

        if (lastFromStack === tag) {
          // create tag node
          var node = tagNode(tag, children); // and add it to the appropriate stack

          if (stack.length > 0) {
            stack.push(node);
          } else {
            result.push(node);
          }

          children = [];
          pairTagFound = true;
        } else if (isNode(lastFromStack)) {
          // add nodes between close tag and open tag to the children
          children.unshift(lastFromStack);
        } else {
          if (typeof lastFromStack === 'string' && hasAttributes(lastFromStack)) {
            throw new Error("Tags in string should not have attributes: ".concat(str));
          } else {
            throw new Error("String has unbalanced tags: ".concat(str));
          }
        }

        if (stack.length === 0 && children.length > 0) {
          throw new Error("String has unbalanced tags: ".concat(str));
        }
      }

      context.tag = '';
      return STATE.TEXT;
    } // if the tag is void tag e.g. <img/>


    if (tag.lastIndexOf(CONTROL_CHARS.CLOSING_TAG_MARK) === tag.length - 1) {
      tag = tag.substring(0, tag.length - 1);
      createTextNodeIfPossible(context);

      var _node = voidTagNode(tag); // add node to the appropriate stack


      if (stack.length > 0) {
        stack.push(_node);
      } else {
        result.push(_node);
      }

      context.tag = '';
      return STATE.TEXT;
    }

    createTextNodeIfPossible(context);
    stack.push(tag);
    context.tag = '';
    return STATE.TEXT;
  } // If we meet open tag "<" it means that we wrongly moved into tag state


  if (currChar === CONTROL_CHARS.TAG_OPEN_BRACE) {
    context.text += str.substring(lastTextStateChangeIdx, currIdx);
    context.lastTextStateChangeIdx = currIdx;
    context.tag = '';
    return STATE.TAG;
  }

  context.tag += currChar;
  return STATE.TAG;
};
/**
 * Parses string into AST (abstract syntax tree) and returns it
 * e.g.
 * parse("String to <a>translate</a>") ->
 * ```
 *      [
 *           { type: 'text', value: 'String to ' },
 *           { type: 'tag', value: 'a', children: [{ type: 'text', value: 'translate' }] }
 *      ];
 * ```
 * Empty string is parsed into empty AST (abstract syntax tree): "[]"
 * If founds unbalanced tags, it throws error about it
 *
 * @param {string} str - message in simplified ICU like syntax without plural support
 */


var parser = function parser() {
  var _STATE_HANDLERS;

  var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var context = {
    /**
     * Stack is used to keep and search nested tag nodes
     */
    stack: [],

    /**
     * Result is stack where function allocates nodes
     */
    result: [],

    /**
     * Current char index
     */
    currIdx: 0,

    /**
     * Saves index of the last state change from the text state,
     * used to restore parsed text if we moved into other state wrongly
     */
    lastTextStateChangeIdx: 0,

    /**
     * Accumulated tag value
     */
    tag: '',

    /**
     * Accumulated text value
     */
    text: '',

    /**
     * Accumulated placeholder value
     */
    placeholder: '',

    /**
     * Parsed string
     */
    str: str
  };
  var STATE_HANDLERS = (_STATE_HANDLERS = {}, _defineProperty(_STATE_HANDLERS, STATE.TEXT, textStateHandler), _defineProperty(_STATE_HANDLERS, STATE.PLACEHOLDER, placeholderStateHandler), _defineProperty(_STATE_HANDLERS, STATE.TAG, tagStateHandler), _STATE_HANDLERS); // Start from text state

  var currentState = STATE.TEXT;

  while (context.currIdx < str.length) {
    context.currChar = str[context.currIdx];
    var currentStateHandler = STATE_HANDLERS[currentState];
    currentState = currentStateHandler(context);
    context.currIdx += 1;
  }

  var result = context.result,
      text = context.text,
      stack = context.stack,
      lastTextStateChangeIdx = context.lastTextStateChangeIdx; // Means that tag or placeholder nodes were not closed, so we consider them as text

  if (currentState !== STATE.TEXT) {
    var restText = str.substring(lastTextStateChangeIdx);

    if ((restText + text).length > 0) {
      result.push(textNode(text + restText));
    }
  } else {
    // eslint-disable-next-line no-lonely-if
    if (text.length > 0) {
      result.push(textNode(text));
    }
  }

  if (stack.length > 0) {
    throw new Error("String has unbalanced tags: ".concat(context.str));
  }

  return result;
};

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
 * Helper functions used by default to assemble strings from tag nodes
 * @param tagName
 * @param children
 */

var createStringElement = function createStringElement(tagName, children) {
  if (children) {
    return "<".concat(tagName, ">").concat(children, "</").concat(tagName, ">");
  }

  return "<".concat(tagName, "/>");
};
/**
 * Creates map with default values for tag converters
 */


var createDefaultValues = function createDefaultValues() {
  return {
    p: function p(children) {
      return createStringElement('p', children);
    },
    b: function b(children) {
      return createStringElement('b', children);
    },
    strong: function strong(children) {
      return createStringElement('strong', children);
    },
    tt: function tt(children) {
      return createStringElement('tt', children);
    },
    s: function s(children) {
      return createStringElement('s', children);
    },
    i: function i(children) {
      return createStringElement('i', children);
    }
  };
};
/**
 * This function accepts an AST (abstract syntax tree) which is a result
 * of the parser function call, and converts tree nodes into array of strings replacing node
 * values with provided values.
 * Values is a map with functions or strings, where each key is related to placeholder value
 * or tag value
 * e.g.
 * string "text <tag>tag text</tag> %placeholder%" is parsed into next AST
 *
 *      [
 *          { type: 'text', value: 'text ' },
 *          {
 *              type: 'tag',
 *              value: 'tag',
 *              children: [{ type: 'text', value: 'tag text' }],
 *          },
 *          { type: 'text', value: ' ' },
 *          { type: 'placeholder', value: 'placeholder' }
 *      ];
 *
 * this AST after format and next values
 *
 *      {
 *          // here used template strings, but it can be react components as well
 *          tag: (chunks) => `<b>${chunks}</b>`,
 *          placeholder: 'placeholder text'
 *      }
 *
 * will return next array
 *
 * [ 'text ', '<b>tag text</b>', ' ', 'placeholder text' ]
 *
 * as you can see, <tag> was replaced by <b>, and placeholder was replaced by placeholder text
 *
 * @param ast - AST (abstract syntax tree)
 * @param values
 */


var format = function format() {
  var ast = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  var result = [];

  var tmplValues = _objectSpread(_objectSpread({}, createDefaultValues()), values);

  var i = 0;

  while (i < ast.length) {
    var currentNode = ast[i]; // if current node is text node, there is nothing to change, append value to the result

    if (isTextNode(currentNode)) {
      result.push(currentNode.value);
    } else if (isTagNode(currentNode)) {
      var children = _toConsumableArray(format(currentNode.children, tmplValues));

      var value = tmplValues[currentNode.value];

      if (value) {
        // TODO consider using strong typing
        if (typeof value === 'function') {
          result.push(value(children.join('')));
        } else {
          result.push(value);
        }
      } else {
        throw new Error("Value ".concat(currentNode.value, " wasn't provided"));
      }
    } else if (isVoidTagNode(currentNode)) {
      var _value = tmplValues[currentNode.value]; // TODO consider using strong typing

      if (_value && typeof _value === 'string') {
        result.push(_value);
      } else {
        throw new Error("Value ".concat(currentNode.value, " wasn't provided"));
      }
    } else if (isPlaceholderNode(currentNode)) {
      var _value2 = tmplValues[currentNode.value]; // TODO consider using strong typing

      if (_value2 && typeof _value2 === 'string') {
        result.push(_value2);
      } else {
        throw new Error("Value ".concat(currentNode.value, " wasn't provided"));
      }
    }

    i += 1;
  }

  return result;
};
/**
 * Function gets AST (abstract syntax tree) or string and formats messages,
 * replacing values accordingly
 * e.g.
 *      const message = formatter('<a>some text</a>', {
 *          a: (chunks) => `<a href="#">${chunks}</a>`,
 *      });
 *      console.log(message); // ['<a href="#">some text</a>']
 * @param message
 * @param [values]
 */


var formatter = function formatter(message, values) {
  var ast = parser(message);
  var preparedValues = {}; // convert values to strings if not a function

  if (values) {
    Object.keys(values).forEach(function (key) {
      var value = values[key]; // TODO consider using strong typing

      if (typeof value === 'function') {
        preparedValues[key] = value;
      } else {
        preparedValues[key] = String(value);
      }
    });
  }

  return format(ast, preparedValues);
};

var _pluralFormsCount;

var AvailableLocales;

(function (AvailableLocales) {
  AvailableLocales["az"] = "az";
  AvailableLocales["bo"] = "bo";
  AvailableLocales["dz"] = "dz";
  AvailableLocales["id"] = "id";
  AvailableLocales["ja"] = "ja";
  AvailableLocales["jv"] = "jv";
  AvailableLocales["ka"] = "ka";
  AvailableLocales["km"] = "km";
  AvailableLocales["kn"] = "kn";
  AvailableLocales["ko"] = "ko";
  AvailableLocales["ms"] = "ms";
  AvailableLocales["th"] = "th";
  AvailableLocales["tr"] = "tr";
  AvailableLocales["vi"] = "vi";
  AvailableLocales["zh"] = "zh";
  AvailableLocales["af"] = "af";
  AvailableLocales["bn"] = "bn";
  AvailableLocales["bg"] = "bg";
  AvailableLocales["ca"] = "ca";
  AvailableLocales["da"] = "da";
  AvailableLocales["de"] = "de";
  AvailableLocales["el"] = "el";
  AvailableLocales["en"] = "en";
  AvailableLocales["eo"] = "eo";
  AvailableLocales["es"] = "es";
  AvailableLocales["et"] = "et";
  AvailableLocales["eu"] = "eu";
  AvailableLocales["fa"] = "fa";
  AvailableLocales["fi"] = "fi";
  AvailableLocales["fo"] = "fo";
  AvailableLocales["fur"] = "fur";
  AvailableLocales["fy"] = "fy";
  AvailableLocales["gl"] = "gl";
  AvailableLocales["gu"] = "gu";
  AvailableLocales["ha"] = "ha";
  AvailableLocales["he"] = "he";
  AvailableLocales["hu"] = "hu";
  AvailableLocales["is"] = "is";
  AvailableLocales["it"] = "it";
  AvailableLocales["ku"] = "ku";
  AvailableLocales["lb"] = "lb";
  AvailableLocales["ml"] = "ml";
  AvailableLocales["mn"] = "mn";
  AvailableLocales["mr"] = "mr";
  AvailableLocales["nah"] = "nah";
  AvailableLocales["nb"] = "nb";
  AvailableLocales["ne"] = "ne";
  AvailableLocales["nl"] = "nl";
  AvailableLocales["nn"] = "nn";
  AvailableLocales["no"] = "no";
  AvailableLocales["oc"] = "oc";
  AvailableLocales["om"] = "om";
  AvailableLocales["or"] = "or";
  AvailableLocales["pa"] = "pa";
  AvailableLocales["pap"] = "pap";
  AvailableLocales["ps"] = "ps";
  AvailableLocales["pt"] = "pt";
  AvailableLocales["so"] = "so";
  AvailableLocales["sq"] = "sq";
  AvailableLocales["sv"] = "sv";
  AvailableLocales["sw"] = "sw";
  AvailableLocales["ta"] = "ta";
  AvailableLocales["te"] = "te";
  AvailableLocales["tk"] = "tk";
  AvailableLocales["ur"] = "ur";
  AvailableLocales["zu"] = "zu";
  AvailableLocales["am"] = "am";
  AvailableLocales["bh"] = "bh";
  AvailableLocales["fil"] = "fil";
  AvailableLocales["fr"] = "fr";
  AvailableLocales["gun"] = "gun";
  AvailableLocales["hi"] = "hi";
  AvailableLocales["hy"] = "hy";
  AvailableLocales["ln"] = "ln";
  AvailableLocales["mg"] = "mg";
  AvailableLocales["nso"] = "nso";
  AvailableLocales["xbr"] = "xbr";
  AvailableLocales["ti"] = "ti";
  AvailableLocales["wa"] = "wa";
  AvailableLocales["be"] = "be";
  AvailableLocales["bs"] = "bs";
  AvailableLocales["hr"] = "hr";
  AvailableLocales["ru"] = "ru";
  AvailableLocales["sr"] = "sr";
  AvailableLocales["uk"] = "uk";
  AvailableLocales["cs"] = "cs";
  AvailableLocales["sk"] = "sk";
  AvailableLocales["ga"] = "ga";
  AvailableLocales["lt"] = "lt";
  AvailableLocales["sl"] = "sl";
  AvailableLocales["mk"] = "mk";
  AvailableLocales["mt"] = "mt";
  AvailableLocales["lv"] = "lv";
  AvailableLocales["pl"] = "pl";
  AvailableLocales["cy"] = "cy";
  AvailableLocales["ro"] = "ro";
  AvailableLocales["ar"] = "ar";
})(AvailableLocales || (AvailableLocales = {}));

var getPluralFormId = function getPluralFormId(locale, number) {
  var _supportedForms;

  if (number === 0) {
    return 0;
  }

  var slavNum = number % 10 === 1 && number % 100 !== 11 ? 1 : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 10 || number % 100 >= 20) ? 2 : 3;
  var supportedForms = (_supportedForms = {}, _defineProperty(_supportedForms, AvailableLocales.az, 1), _defineProperty(_supportedForms, AvailableLocales.bo, 1), _defineProperty(_supportedForms, AvailableLocales.dz, 1), _defineProperty(_supportedForms, AvailableLocales.id, 1), _defineProperty(_supportedForms, AvailableLocales.ja, 1), _defineProperty(_supportedForms, AvailableLocales.jv, 1), _defineProperty(_supportedForms, AvailableLocales.ka, 1), _defineProperty(_supportedForms, AvailableLocales.km, 1), _defineProperty(_supportedForms, AvailableLocales.kn, 1), _defineProperty(_supportedForms, AvailableLocales.ko, 1), _defineProperty(_supportedForms, AvailableLocales.ms, 1), _defineProperty(_supportedForms, AvailableLocales.th, 1), _defineProperty(_supportedForms, AvailableLocales.tr, 1), _defineProperty(_supportedForms, AvailableLocales.vi, 1), _defineProperty(_supportedForms, AvailableLocales.zh, 1), _defineProperty(_supportedForms, AvailableLocales.af, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.bn, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.bg, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ca, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.da, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.de, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.el, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.en, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.eo, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.es, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.et, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.eu, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.fa, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.fi, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.fo, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.fur, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.fy, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.gl, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.gu, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ha, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.he, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.hu, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.is, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.it, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ku, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.lb, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ml, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.mn, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.mr, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.nah, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.nb, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ne, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.nl, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.nn, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.no, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.oc, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.om, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.or, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.pa, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.pap, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ps, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.pt, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.so, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.sq, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.sv, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.sw, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ta, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.te, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.tk, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.ur, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.zu, number === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.am, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.bh, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.fil, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.fr, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.gun, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.hi, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.hy, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.ln, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.mg, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.nso, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.xbr, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.ti, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.wa, number === 0 || number === 1 ? 0 : 1), _defineProperty(_supportedForms, AvailableLocales.be, slavNum), _defineProperty(_supportedForms, AvailableLocales.bs, slavNum), _defineProperty(_supportedForms, AvailableLocales.hr, slavNum), _defineProperty(_supportedForms, AvailableLocales.ru, slavNum), _defineProperty(_supportedForms, AvailableLocales.sr, slavNum), _defineProperty(_supportedForms, AvailableLocales.uk, slavNum), _defineProperty(_supportedForms, AvailableLocales.cs, number === 1 ? 1 : number >= 2 && number <= 4 ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.sk, number === 1 ? 1 : number >= 2 && number <= 4 ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.ga, number === 1 ? 1 : number === 2 ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.lt, number % 10 === 1 && number % 100 !== 11 ? 1 : number % 10 >= 2 && (number % 100 < 10 || number % 100 >= 20) ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.sl, number % 100 === 1 ? 1 : number % 100 === 2 ? 2 : number % 100 === 3 || number % 100 === 4 ? 3 : 4), _defineProperty(_supportedForms, AvailableLocales.mk, number % 10 === 1 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.mt, number === 1 ? 1 : number === 0 || number % 100 > 1 && number % 100 < 11 ? 2 : number % 100 > 10 && number % 100 < 20 ? 3 : 4), _defineProperty(_supportedForms, AvailableLocales.lv, number === 0 ? 0 : number % 10 === 1 && number % 100 !== 11 ? 1 : 2), _defineProperty(_supportedForms, AvailableLocales.pl, number === 1 ? 1 : number % 10 >= 2 && number % 10 <= 4 && (number % 100 < 12 || number % 100 > 14) ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.cy, number === 1 ? 0 : number === 2 ? 1 : number === 8 || number === 11 ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.ro, number === 1 ? 1 : number === 1 || number % 100 > 0 && number % 100 < 20 ? 2 : 3), _defineProperty(_supportedForms, AvailableLocales.ar, number === 0 ? 0 : number === 1 ? 1 : number === 2 ? 2 : number % 100 >= 3 && number % 100 <= 10 ? 3 : number % 100 >= 11 && number % 100 <= 99 ? 4 : 5), _supportedForms);
  return supportedForms[locale];
};

var pluralFormsCount = (_pluralFormsCount = {}, _defineProperty(_pluralFormsCount, AvailableLocales.az, 2), _defineProperty(_pluralFormsCount, AvailableLocales.bo, 2), _defineProperty(_pluralFormsCount, AvailableLocales.dz, 2), _defineProperty(_pluralFormsCount, AvailableLocales.id, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ja, 2), _defineProperty(_pluralFormsCount, AvailableLocales.jv, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ka, 2), _defineProperty(_pluralFormsCount, AvailableLocales.km, 2), _defineProperty(_pluralFormsCount, AvailableLocales.kn, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ko, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ms, 2), _defineProperty(_pluralFormsCount, AvailableLocales.th, 2), _defineProperty(_pluralFormsCount, AvailableLocales.tr, 2), _defineProperty(_pluralFormsCount, AvailableLocales.vi, 2), _defineProperty(_pluralFormsCount, AvailableLocales.zh, 2), _defineProperty(_pluralFormsCount, AvailableLocales.af, 3), _defineProperty(_pluralFormsCount, AvailableLocales.bn, 3), _defineProperty(_pluralFormsCount, AvailableLocales.bg, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ca, 3), _defineProperty(_pluralFormsCount, AvailableLocales.da, 3), _defineProperty(_pluralFormsCount, AvailableLocales.de, 3), _defineProperty(_pluralFormsCount, AvailableLocales.el, 3), _defineProperty(_pluralFormsCount, AvailableLocales.en, 3), _defineProperty(_pluralFormsCount, AvailableLocales.eo, 3), _defineProperty(_pluralFormsCount, AvailableLocales.es, 3), _defineProperty(_pluralFormsCount, AvailableLocales.et, 3), _defineProperty(_pluralFormsCount, AvailableLocales.eu, 3), _defineProperty(_pluralFormsCount, AvailableLocales.fa, 3), _defineProperty(_pluralFormsCount, AvailableLocales.fi, 3), _defineProperty(_pluralFormsCount, AvailableLocales.fo, 3), _defineProperty(_pluralFormsCount, AvailableLocales.fur, 3), _defineProperty(_pluralFormsCount, AvailableLocales.fy, 3), _defineProperty(_pluralFormsCount, AvailableLocales.gl, 3), _defineProperty(_pluralFormsCount, AvailableLocales.gu, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ha, 3), _defineProperty(_pluralFormsCount, AvailableLocales.he, 3), _defineProperty(_pluralFormsCount, AvailableLocales.hu, 3), _defineProperty(_pluralFormsCount, AvailableLocales.is, 3), _defineProperty(_pluralFormsCount, AvailableLocales.it, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ku, 3), _defineProperty(_pluralFormsCount, AvailableLocales.lb, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ml, 3), _defineProperty(_pluralFormsCount, AvailableLocales.mn, 3), _defineProperty(_pluralFormsCount, AvailableLocales.mr, 3), _defineProperty(_pluralFormsCount, AvailableLocales.nah, 3), _defineProperty(_pluralFormsCount, AvailableLocales.nb, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ne, 3), _defineProperty(_pluralFormsCount, AvailableLocales.nl, 3), _defineProperty(_pluralFormsCount, AvailableLocales.nn, 3), _defineProperty(_pluralFormsCount, AvailableLocales.no, 3), _defineProperty(_pluralFormsCount, AvailableLocales.oc, 3), _defineProperty(_pluralFormsCount, AvailableLocales.om, 3), _defineProperty(_pluralFormsCount, AvailableLocales.or, 3), _defineProperty(_pluralFormsCount, AvailableLocales.pa, 3), _defineProperty(_pluralFormsCount, AvailableLocales.pap, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ps, 3), _defineProperty(_pluralFormsCount, AvailableLocales.pt, 3), _defineProperty(_pluralFormsCount, AvailableLocales.so, 3), _defineProperty(_pluralFormsCount, AvailableLocales.sq, 3), _defineProperty(_pluralFormsCount, AvailableLocales.sv, 3), _defineProperty(_pluralFormsCount, AvailableLocales.sw, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ta, 3), _defineProperty(_pluralFormsCount, AvailableLocales.te, 3), _defineProperty(_pluralFormsCount, AvailableLocales.tk, 3), _defineProperty(_pluralFormsCount, AvailableLocales.ur, 3), _defineProperty(_pluralFormsCount, AvailableLocales.zu, 3), _defineProperty(_pluralFormsCount, AvailableLocales.am, 2), _defineProperty(_pluralFormsCount, AvailableLocales.bh, 2), _defineProperty(_pluralFormsCount, AvailableLocales.fil, 2), _defineProperty(_pluralFormsCount, AvailableLocales.fr, 2), _defineProperty(_pluralFormsCount, AvailableLocales.gun, 2), _defineProperty(_pluralFormsCount, AvailableLocales.hi, 2), _defineProperty(_pluralFormsCount, AvailableLocales.hy, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ln, 2), _defineProperty(_pluralFormsCount, AvailableLocales.mg, 2), _defineProperty(_pluralFormsCount, AvailableLocales.nso, 2), _defineProperty(_pluralFormsCount, AvailableLocales.xbr, 2), _defineProperty(_pluralFormsCount, AvailableLocales.ti, 2), _defineProperty(_pluralFormsCount, AvailableLocales.wa, 2), _defineProperty(_pluralFormsCount, AvailableLocales.be, 4), _defineProperty(_pluralFormsCount, AvailableLocales.bs, 4), _defineProperty(_pluralFormsCount, AvailableLocales.hr, 4), _defineProperty(_pluralFormsCount, AvailableLocales.ru, 4), _defineProperty(_pluralFormsCount, AvailableLocales.sr, 4), _defineProperty(_pluralFormsCount, AvailableLocales.uk, 4), _defineProperty(_pluralFormsCount, AvailableLocales.cs, 4), _defineProperty(_pluralFormsCount, AvailableLocales.sk, 4), _defineProperty(_pluralFormsCount, AvailableLocales.ga, 4), _defineProperty(_pluralFormsCount, AvailableLocales.lt, 4), _defineProperty(_pluralFormsCount, AvailableLocales.sl, 5), _defineProperty(_pluralFormsCount, AvailableLocales.mk, 3), _defineProperty(_pluralFormsCount, AvailableLocales.mt, 5), _defineProperty(_pluralFormsCount, AvailableLocales.lv, 3), _defineProperty(_pluralFormsCount, AvailableLocales.pl, 4), _defineProperty(_pluralFormsCount, AvailableLocales.cy, 4), _defineProperty(_pluralFormsCount, AvailableLocales.ro, 4), _defineProperty(_pluralFormsCount, AvailableLocales.ar, 6), _pluralFormsCount);
var PLURAL_STRING_DELIMITER = '|';

var checkForms = function checkForms(str, locale, key) {
  var forms = str.split(PLURAL_STRING_DELIMITER);

  if (forms.length !== pluralFormsCount[locale]) {
    throw new Error("Invalid plural string \"".concat(key, "\" for locale ").concat(locale, ": ").concat(forms.length, " given; need: ").concat(pluralFormsCount[locale]));
  }
};
/**
 * Checks if plural forms are valid
 * @param str - message string
 * @param locale - message locale
 * @param key - message key, used for clearer log message
 */


var isPluralFormValid = function isPluralFormValid(str, locale, key) {
  try {
    checkForms(str, locale, key);
    return true;
  } catch (error) {
    return false;
  }
};
/**
 * Returns plural form corresponding to number
 * @param str
 * @param number
 * @param locale - current locale
 * @param key - message key
 */

var getForm = function getForm(str, number, locale, key) {
  checkForms(str, locale, key);
  var forms = str.split(PLURAL_STRING_DELIMITER);
  var currentForm = getPluralFormId(locale, number);
  return forms[currentForm].trim();
};

function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

var defaultMessageConstructor = function defaultMessageConstructor(formatted) {
  return formatted.join('');
};

var Translator = /*#__PURE__*/function () {
  function Translator(i18n, messageConstructor, values) {
    _classCallCheck(this, Translator);

    this.i18n = i18n;
    this.messageConstructor = messageConstructor || defaultMessageConstructor;
    this.values = values || {};
  }
  /**
   * Retrieves message and translates it, substituting parameters where necessary
   * @param key - translation message key
   * @param params - values used to substitute placeholders and tags
   */


  _createClass(Translator, [{
    key: "getMessage",
    value: function getMessage(key) {
      var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      var message = this.i18n.getMessage(key);

      if (!message) {
        message = this.i18n.getBaseMessage(key);

        if (!message) {
          throw new Error("Was unable to find message for key: \"".concat(key, "\""));
        }
      }

      var formatted = formatter(message, _objectSpread$1(_objectSpread$1({}, this.values), params));
      return this.messageConstructor(formatted);
    }
    /**
     * Retrieves correct plural form and translates it
     * @param key - translation message key
     * @param number - plural form number
     * @param params - values used to substitute placeholders or tags if necessary,
     * if params has "count" property it will be overridden by number (plural form number)
     */

  }, {
    key: "getPlural",
    value: function getPlural(key, number) {
      var params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      var message = this.i18n.getMessage(key);
      var language = this.i18n.getUILanguage();

      if (!message) {
        message = this.i18n.getBaseMessage(key);

        if (!message) {
          throw new Error("Was unable to find message for key: \"".concat(key, "\""));
        }

        language = this.i18n.getBaseUILanguage();
      }

      var form = getForm(message, number, language, key);
      var formatted = formatter(form, _objectSpread$1(_objectSpread$1(_objectSpread$1({}, this.values), params), {}, {
        count: number
      }));
      return this.messageConstructor(formatted);
    }
  }]);

  return Translator;
}();

function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
 * Creates translation function for strings used in the React components
 * We do not import React directly, because translator module can be used
 * in the modules without React too
 *
 * e.g.
 * const translateReact = createReactTranslator(getMessage, React);
 * in locales folder you should have messages.json file
 * ```
 * message:
 *     "popup_auth_agreement_consent": {
 *          "message": "You agree to our <eula>EULA</eula>",
 *      },
 * ```
 *
 * this message can be retrieved and translated into react components next way:
 *
 * const component = translateReact('popup_auth_agreement_consent', {
 *          eula: (chunks) => (
 *              <button
 *                  className="auth__privacy-link"
 *                  onClick={handleEulaClick}
 *              >
 *                  {chunks}
 *              </button>
 *          ),
 *       });
 *
 * Note how functions in the values argument can be used with handlers
 *
 * @param i18n - object with methods which get translated message by key and return current locale
 * @param React - instance of react library
 */

var createReactTranslator = function createReactTranslator(i18n, react, defaults) {
  /**
   * Helps to build nodes without values
   *
   * @param tagName
   * @param children
   */
  var createReactElement = function createReactElement(tagName, children) {
    if (children) {
      return react.createElement(tagName, null, react.Children.toArray(children));
    }

    return react.createElement(tagName, null);
  };
  /**
   * Function creates default values to be used if user didn't provide function values for tags
   */


  var createDefaultValues = function createDefaultValues() {
    var externalDefaults = {};

    if (defaults) {
      defaults.tags.forEach(function (t) {
        externalDefaults[t.key] = function (children) {
          return createReactElement(t.createdTag, children);
        };
      });
    }

    if (defaults !== null && defaults !== void 0 && defaults.override) {
      return externalDefaults;
    }

    return _objectSpread$2({
      p: function p(children) {
        return createReactElement('p', children);
      },
      b: function b(children) {
        return createReactElement('b', children);
      },
      strong: function strong(children) {
        return createReactElement('strong', children);
      },
      tt: function tt(children) {
        return createReactElement('tt', children);
      },
      s: function s(children) {
        return createReactElement('s', children);
      },
      i: function i(children) {
        return createReactElement('i', children);
      }
    }, externalDefaults);
  };

  var reactMessageConstructor = function reactMessageConstructor(formatted) {
    var reactChildren = react.Children.toArray(formatted); // if there is only strings in the array we join them

    if (reactChildren.every(function (child) {
      return typeof child === 'string';
    })) {
      return reactChildren.join('');
    }

    return reactChildren;
  };

  var defaultValues = createDefaultValues();
  return new Translator(i18n, reactMessageConstructor, defaultValues);
};

var r,
    f;

function A(n, l) {
  return l = l || [], null == n || "boolean" == typeof n || (Array.isArray(n) ? n.some(function (n) {
    A(n, l);
  }) : l.push(n)), l;
}

r = "function" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, f = 0;

function ownKeys$3(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread$3(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$3(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$3(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
 * Creates translation function for strings used in the Preact components
 * We do not import Preact directly, because translator module can be used
 * in the modules without Preact too
 *
 * e.g.
 * const translatePreact = createPreactTranslator(getMessage, Preact);
 * in locales folder you should have messages.json file
 * ```
 * message:
 *     "popup_auth_agreement_consent": {
 *          "message": "You agree to our <eula>EULA</eula>",
 *      },
 * ```
 *
 * this message can be retrieved and translated into preact components next way:
 *
 * const component = translatePreact('popup_auth_agreement_consent', {
 *          eula: (chunks) => (
 *              <button
 *                  className="auth__privacy-link"
 *                  onClick={handleEulaClick}
 *              >
 *                  {chunks}
 *              </button>
 *          ),
 *       });
 *
 * Note how functions in the values argument can be used with handlers
 *
 * @param i18n - object with methods which get translated message by key and return current locale
 * @param Preact - instance of preact library
 */

var createPreactTranslator = function createPreactTranslator(i18n, preact, defaults) {
  /**
   * Helps to build nodes without values
   *
   * @param tagName
   * @param children
   */
  var createPreactElement = function createPreactElement(tagName, children) {
    if (children) {
      return preact.createElement(tagName, null, A(children));
    }

    return preact.createElement(tagName, null);
  };
  /**
   * Function creates default values to be used if user didn't provide function values for tags
   */


  var createDefaultValues = function createDefaultValues() {
    var externalDefaults = {};

    if (defaults) {
      defaults.tags.forEach(function (t) {
        externalDefaults[t.key] = function (children) {
          return createPreactElement(t.createdTag, children);
        };
      });
    }

    if (defaults !== null && defaults !== void 0 && defaults.override) {
      return externalDefaults;
    }

    return _objectSpread$3({
      p: function p(children) {
        return createPreactElement('p', children);
      },
      b: function b(children) {
        return createPreactElement('b', children);
      },
      strong: function strong(children) {
        return createPreactElement('strong', children);
      },
      tt: function tt(children) {
        return createPreactElement('tt', children);
      },
      s: function s(children) {
        return createPreactElement('s', children);
      },
      i: function i(children) {
        return createPreactElement('i', children);
      }
    }, externalDefaults);
  };

  var preactMessageConstructor = function preactMessageConstructor(formatted) {
    var preactChildren = A(formatted); // if there is only strings in the array we join them

    if (preactChildren.every(function (child) {
      return typeof child === 'string';
    })) {
      return preactChildren.join('');
    }

    return preactChildren;
  };

  var defaultValues = createDefaultValues();
  return new Translator(i18n, preactMessageConstructor, defaultValues);
};

/**
 * Creates translator instance strings, by default for simple strings
 * @param i18n - function which returns translated message by key
 * @param messageConstructor - function that will collect messages
 * @param values - map with default values for tag converters
 */

var createTranslator = function createTranslator(i18n, messageConstructor, values) {
  return new Translator(i18n, messageConstructor, values);
};

var translate = {
  createTranslator: createTranslator,
  createReactTranslator: createReactTranslator,
  createPreactTranslator: createPreactTranslator
};

function _typeof(obj) {
  "@babel/helpers - typeof";

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

  return _typeof(obj);
}

/**
 * Compares two AST (abstract syntax tree) structures,
 * view tests for examples
 * @param baseAst
 * @param targetAst
 */

var areAstStructuresSame = function areAstStructuresSame(baseAst, targetAst) {
  var textNodeFilter = function textNodeFilter(node) {
    return !isTextNode(node);
  };

  var filteredBaseAst = baseAst.filter(textNodeFilter);
  var filteredTargetAst = targetAst.filter(textNodeFilter); // if AST structures have different lengths, they are not equal

  if (filteredBaseAst.length !== filteredTargetAst.length) {
    return false;
  }

  var _loop = function _loop(i) {
    var baseNode = filteredBaseAst[i];
    var targetNode = filteredTargetAst.find(function (node) {
      return node.type === baseNode.type && node.value === baseNode.value;
    });

    if (!targetNode) {
      return {
        v: false
      };
    }

    if (targetNode.children && baseNode.children) {
      var areChildrenSame = areAstStructuresSame(baseNode.children, targetNode.children);

      if (!areChildrenSame) {
        return {
          v: false
        };
      }
    }
  };

  for (var i = 0; i < filteredBaseAst.length; i += 1) {
    var _ret = _loop(i);

    if (_typeof(_ret) === "object") return _ret.v;
  }

  return true;
};
/**
 * Validates translation against base string by AST (abstract syntax tree) structure
 * @param baseMessage - base message
 * @param translatedMessage - translated message
 */


var isTranslationValid = function isTranslationValid(baseMessage, translatedMessage) {
  var baseMessageAst = parser(baseMessage);
  var translatedMessageAst = parser(translatedMessage);
  return areAstStructuresSame(baseMessageAst, translatedMessageAst);
};
var validator = {
  isTranslationValid: isTranslationValid,
  isPluralFormValid: isPluralFormValid
};



;// CONCATENATED MODULE: ./Extension/src/common/translators/i18n.js

const i18n_i18n = {
  getMessage: (browser_polyfill_default()).i18n.getMessage,
  getUILanguage: (browser_polyfill_default()).i18n.getUILanguage,
  getBaseMessage: key => key,
  getBaseUILanguage: () => 'en'
};
;// CONCATENATED MODULE: ./Extension/src/common/translators/translator.js


/**
 * Retrieves localised message by key, formats it and converts into string
 */

const translator = translate.createTranslator(i18n_i18n);
;// CONCATENATED MODULE: ./Extension/src/background/filter/userrules.js














/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */






/**
 * Class for manage user rules
 */

const userrules = function () {
  /**
   * Synthetic user filter
   */
  const userFilter = {
    filterId: utils.filters.USER_FILTER_ID
  };
  /**
   * Adds list of rules to the user filter
   *
   * @param rulesText List of rules to add
   */

  const addRules = function (rulesText) {
    listeners.notifyListeners(listeners.ADD_RULES, userFilter, rulesText);
  };
  /**
   * Removes all user's custom rules
   */


  const clearRules = function () {
    listeners.notifyListeners(listeners.UPDATE_FILTER_RULES, userFilter, []);
  };
  /**
   * Removes user's custom rule
   *
   * @param ruleText Rule text
   */


  const removeRule = function (ruleText) {
    listeners.notifyListeners(listeners.REMOVE_RULE, userFilter, [ruleText]);
  };
  /**
   * Save user rules text to storage
   * @param content Rules text
   */


  const updateUserRulesText = function (content) {
    const lines = content.length > 0 ? content.split(/\n/) : [];
    listeners.notifyListeners(listeners.UPDATE_FILTER_RULES, userFilter, lines);
  };
  /**
   * Loads user rules text from storage
   */


  const getUserRulesText = async function () {
    const rulesText = await rulesStorage.read(utils.filters.USER_FILTER_ID);
    const content = (rulesText || []).join('\n');
    return content;
  };

  const unAllowlistFrame = function (frameInfo) {
    if (frameInfo.frameRule) {
      if (frameInfo.frameRule.filterId === utils.filters.ALLOWLIST_FILTER_ID) {
        allowlist.unAllowlistUrl(frameInfo.url);
      } else {
        removeRule(frameInfo.frameRule.ruleText);
      }
    }
  };
  /**
   * Removes user rules by url
   * @param {string} url
   * @return {Promise<void>}
   */


  const removeRulesByUrl = async url => {
    const userRulesText = await getUserRulesText();
    const userRulesStrings = userRulesText.split('\n');
    const updatedUserRulesText = userRulesStrings.filter(userRuleString => {
      return !tsurlfilter_browser.RuleSyntaxUtils.isRuleForUrl(userRuleString, url);
    }).join('\n');
    updateUserRulesText(updatedUserRulesText);
  };
  /**
   * Checks if user rules have rules matching by url
   * @param {string} url
   * @return {Promise<boolean>}
   */


  const hasRulesForUrl = async url => {
    const userRulesText = await getUserRulesText();
    const userRulesStrings = userRulesText.split('\n');
    return userRulesStrings.some(userRuleString => tsurlfilter_browser.RuleSyntaxUtils.isRuleForUrl(userRuleString, url));
  };
  /**
   * Map rules conversion result
   * key is a result,
   * value is a source rule
   *
   * @type {Map<String, String>}
   */


  const conversionMap = new Map();
  /**
   * Converts rules text lines with conversion map
   *
   * @param rulesLines
   * @return {[String]}
   */

  const convertRules = rulesLines => {
    conversionMap.clear();
    const result = [];

    for (let i = 0; i < rulesLines.length; i += 1) {
      const line = rulesLines[i];
      const converted = tsurlfilter_browser.RuleConverter.convertRule(line);
      result.push(...converted);

      if (converted.length > 0) {
        if (converted.length > 1 || converted[0] !== line) {
          // Fill the map only for converted rules
          converted.forEach(x => {
            conversionMap.set(x, line);
          });
        }
      }
    }

    log.debug('Converted {0} rules to {1} for user filter', rulesLines.length, result.length);
    return result;
  };
  /**
   * Returns source rule text if the rule has been converted
   *
   * @param ruleText
   * @return {String}
   */


  const getSourceRule = ruleText => {
    return conversionMap.get(ruleText);
  };

  return {
    addRules,
    clearRules,
    removeRule,
    updateUserRulesText,
    getUserRulesText,
    unAllowlistFrame,
    removeRulesByUrl,
    hasRulesForUrl,
    convertRules,
    getSourceRule
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filtering-log/filtering-log.browsers.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */











/**
 * Object for log http requests
 */

const browsersFilteringLog = function () {
  const REQUESTS_SIZE_PER_TAB = 1000;
  const backgroundTabId = BACKGROUND_TAB_ID;
  const backgroundTab = {
    tabId: backgroundTabId,
    title: translator.getMessage('background_tab_title')
  };
  const tabsInfoMap = Object.create(null);
  let openedFilteringLogsPage = 0;
  /**
   * Keep preserve log state on background page
   * @type {boolean}
   */

  let preserveLogEnabled = false; // Force to add background tab if it's defined

  if (prefs.features.hasBackgroundTab) {
    tabsInfoMap[backgroundTabId] = backgroundTab;
  }
  /**
   * Checks if filtering log page is open
   * @return {boolean}
   */


  const isOpen = function () {
    return openedFilteringLogsPage > 0;
  };
  /**
   * We collect filtering events if opened at least one page of log
   */


  const onOpenFilteringLogPage = function () {
    openedFilteringLogsPage += 1;
  };
  /**
   * Cleanup when last page of log closes
   */


  const onCloseFilteringLogPage = function () {
    openedFilteringLogsPage = Math.max(openedFilteringLogsPage - 1, 0);

    if (openedFilteringLogsPage === 0) {
      // Clear events
      Object.keys(tabsInfoMap).forEach(tabId => {
        const tabInfo = tabsInfoMap[tabId];
        delete tabInfo.filteringEvents;
      });
    }
  };
  /**
   * Get filtering info for tab
   * @param tabId
   */


  const getFilteringInfoByTabId = tabId => {
    return tabsInfoMap[tabId];
  };
  /**
   * Updates tab info (title and url)
   * @param tab
   */


  const updateTabInfo = tab => {
    const tabInfo = tabsInfoMap[tab.tabId] || Object.create(null);
    tabInfo.tabId = tab.tabId;
    tabInfo.title = tab.title;
    tabInfo.isExtensionTab = tab.url && tab.url.indexOf(backgroundPage.app.getExtensionUrl()) === 0;
    tabsInfoMap[tab.tabId] = tabInfo;
    return tabInfo;
  };
  /**
   * Adds tab
   * @param tab
   */


  const addTab = tab => {
    // Background tab can't be added
    // Synthetic tabs are used to send initial requests from new tab in chrome
    if (tab.tabId === backgroundTabId || tab.synthetic) {
      return;
    }

    const tabInfo = updateTabInfo(tab);

    if (tabInfo) {
      listeners.notifyListeners(listeners.TAB_ADDED, tabInfo);
    }
  };
  /**
   * Removes tab
   * @param tabId
   */


  const removeTabById = tabId => {
    // Background tab can't be removed
    if (tabId === backgroundTabId) {
      return;
    }

    const tabInfo = tabsInfoMap[tabId];

    if (tabInfo) {
      listeners.notifyListeners(listeners.TAB_CLOSE, tabInfo);
    }

    delete tabsInfoMap[tabId];
  };
  /**
   * Updates tab
   * @param tab
   */


  const updateTab = tab => {
    // Background tab can't be updated
    if (tab.tabId === backgroundTabId) {
      return;
    }

    const tabInfo = updateTabInfo(tab);

    if (tabInfo) {
      listeners.notifyListeners(listeners.TAB_UPDATE, tabInfo);
    }
  };
  /**
   * Copy some properties from source rule to destination rule
   * @param destinationRuleDTO
   * @param sourceRule
   */


  const copyRuleProperties = (destinationRuleDTO, sourceRule) => {
    if (!destinationRuleDTO || !sourceRule) {
      return;
    }

    destinationRuleDTO.filterId = sourceRule.getFilterListId();
    destinationRuleDTO.ruleText = sourceRule.getText();

    if (sourceRule instanceof tsurlfilter_browser.NetworkRule) {
      if (sourceRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Important)) {
        destinationRuleDTO.isImportant = true;
      }

      if (sourceRule.isDocumentLevelAllowlistRule()) {
        destinationRuleDTO.documentLevelRule = true;
      }

      if (sourceRule.getFilterListId() === ANTIBANNER_FILTERS_ID.STEALTH_MODE_FILTER_ID) {
        destinationRuleDTO.isStealthModeRule = true;
      }

      destinationRuleDTO.allowlistRule = sourceRule.isAllowlist();
      destinationRuleDTO.cspRule = sourceRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Csp);
      destinationRuleDTO.modifierValue = sourceRule.getAdvancedModifierValue();
      destinationRuleDTO.cookieRule = sourceRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Cookie);
    } else if (sourceRule instanceof tsurlfilter_browser.CosmeticRule) {
      const ruleType = sourceRule.getType();

      if (ruleType === tsurlfilter_browser.CosmeticRuleType.Html) {
        destinationRuleDTO.contentRule = true; // eslint-disable-next-line max-len
      } else if (ruleType === tsurlfilter_browser.CosmeticRuleType.ElementHiding || ruleType === tsurlfilter_browser.CosmeticRuleType.Css) {
        destinationRuleDTO.cssRule = true;
      } else if (ruleType === tsurlfilter_browser.CosmeticRuleType.Js) {
        destinationRuleDTO.scriptRule = true;
      }
    }

    if (sourceRule.getFilterListId() === ANTIBANNER_FILTERS_ID.USER_FILTER_ID) {
      const originalRule = userrules.getSourceRule(sourceRule.getText());

      if (originalRule) {
        destinationRuleDTO.ruleText = originalRule;
        destinationRuleDTO.appliedRuleText = sourceRule.getText();
      }
    }
  };
  /**
   * Checks if event can be added
   * @param tabId
   */


  const canAddEvent = tabId => {
    if (!isOpen()) {
      return false;
    }

    return !!getFilteringInfoByTabId(tabId);
  };
  /**
   * Writes to filtering event some useful properties from the request rule
   * @param filteringEvent
   * @param rule
   */


  const addRuleToFilteringEvent = (filteringEvent, rule) => {
    if (!rule) {
      return;
    }

    filteringEvent.requestRule = {};
    copyRuleProperties(filteringEvent.requestRule, rule);
  };
  /**
   * Adds filtering event to log
   * @param tabId Tab id
   * @param filteringEvent Event to add
   */


  const pushFilteringEvent = (tabId, filteringEvent) => {
    const tabInfo = getFilteringInfoByTabId(tabId);

    if (!tabInfo) {
      return;
    }

    if (!tabInfo.filteringEvents) {
      tabInfo.filteringEvents = [];
    } // if event doesn't have eventId, generate it manually
    // to manage filtering events on the filtering log page later


    if (!filteringEvent.eventId) {
      filteringEvent.eventId = nanoid();
    }

    tabInfo.filteringEvents.push(filteringEvent);

    if (tabInfo.filteringEvents.length > REQUESTS_SIZE_PER_TAB) {
      // don't remove first item, cause it's request to main frame
      tabInfo.filteringEvents.splice(1, 1);
    }

    listeners.notifyListeners(listeners.LOG_EVENT_ADDED, tabInfo, filteringEvent);
  };
  /**
   * Add request to log
   * @param {Object} params - params object
   * @param params.tab
   * @param params.requestUrl
   * @param params.frameUrl
   * @param params.requestType
   * @param params.requestRule
   * @param {number} params.timestamp - Request UTC timestamp
   * @param params.eventId
   */


  const addHttpRequestEvent = function ({
    tab,
    requestUrl,
    frameUrl,
    requestType,
    requestRule,
    timestamp,
    eventId,
    method
  }) {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const requestDomain = utils.url.getDomainName(requestUrl);
    const frameDomain = utils.url.getDomainName(frameUrl);
    const filteringEvent = {
      eventId,
      requestUrl,
      requestDomain,
      frameUrl,
      frameDomain,
      requestType,
      timestamp,
      requestThirdParty: tsurlfilter_browser.isThirdPartyRequest(requestUrl, frameUrl),
      method
    };
    addRuleToFilteringEvent(filteringEvent, requestRule);
    pushFilteringEvent(tab.tabId, filteringEvent);
  };
  /**
   * Add event to log with the corresponding rule
   * @param {Object} params - params object
   * @param {{tabId: Number}} params.tab - Tab object with one of properties tabId
   * @param {(string|Element)} params.element - String presentation of element or NodeElement
   * @param {String} papams.frameUrl - Frame url
   * @param {String} params.requestType - Request type
   * @param {number} params.timestamp - Request UTC timestamp
   * @param {{ruleText: String, filterId: Number, isInjectRule: Boolean}} params.requestRule - Request rule
   */


  const addCosmeticEvent = function ({
    tab,
    element,
    frameUrl,
    requestType,
    timestamp,
    requestRule
  }) {
    if (!requestRule || !canAddEvent(tab.tabId)) {
      return;
    }

    const frameDomain = utils.url.getDomainName(frameUrl);
    const filteringEvent = {
      element: typeof element === 'string' ? element : utils.strings.elementToString(element),
      frameUrl,
      frameDomain,
      requestType,
      timestamp
    };
    addRuleToFilteringEvent(filteringEvent, requestRule);
    pushFilteringEvent(tab.tabId, filteringEvent);
  };
  /**
   * Add script event to log with the corresponding rule
   * @param {Object} params - params object
   * @param {{tabId: Number}} params.tab - Tab object with one of properties tabId
   * @param {String} params.frameUrl - Frame url
   * @param {String} params.requestType - Request type
   * @param {Object} params.rule - script rule
   * @param {number} params.timestamp - Request UTC timestamp
   */


  const addScriptInjectionEvent = ({
    tab,
    frameUrl,
    requestType,
    rule,
    timestamp
  }) => {
    if (!rule || !canAddEvent(tab.tabId)) {
      return;
    }

    const frameDomain = utils.url.getDomainName(frameUrl);
    const filteringEvent = {
      script: true,
      requestUrl: frameUrl,
      frameUrl,
      frameDomain,
      requestType,
      timestamp
    };
    addRuleToFilteringEvent(filteringEvent, rule);
    pushFilteringEvent(tab.tabId, filteringEvent);
  };
  /**
   * Adds remove query parameters event to log with the corresponding rule
   *
   * @param {Object} params - params object
   * @param {{tabId: Number}} params.tab - Tab object with one of properties tabId
   * @param {String} params.frameUrl - Frame url
   * @param {String} params.requestType - Request type
   * @param {Object} params.rule - removeparam rule
   * @param {number} params.timestamp - Request UTC timestamp
   */


  const addRemoveParamEvent = ({
    tab,
    frameUrl,
    requestType,
    rule,
    timestamp
  }) => {
    if (!rule || !canAddEvent(tab.tabId)) {
      return;
    }

    const frameDomain = utils.url.getDomainName(frameUrl);
    const filteringEvent = {
      removeParam: true,
      requestUrl: frameUrl,
      frameUrl,
      frameDomain,
      requestType,
      timestamp
    };
    addRuleToFilteringEvent(filteringEvent, rule);
    pushFilteringEvent(tab.tabId, filteringEvent);
  };
  /**
   * Adds removed header event
   *
   * @param tabId
   * @param frameUrl
   * @param headerName
   * @param rule
   */


  const addRemoveHeaderEvent = (tabId, frameUrl, headerName, rule) => {
    if (!rule || !canAddEvent(tabId)) {
      return;
    }

    const frameDomain = utils.url.getDomainName(frameUrl);
    const filteringEvent = {
      removeHeader: true,
      headerName,
      requestUrl: frameUrl,
      frameUrl,
      frameDomain,
      requestType: RequestTypes.DOCUMENT,
      timestamp: Date.now()
    };
    addRuleToFilteringEvent(filteringEvent, rule);
    pushFilteringEvent(tabId, filteringEvent);
  };
  /**
   * Writes to filtering event some useful properties from the replace rules
   * @param filteringEvent
   * @param replaceRules
   */


  const addReplaceRulesToFilteringEvent = (filteringEvent, replaceRules) => {
    // only replace rules can be applied together
    filteringEvent.requestRule = {};
    filteringEvent.requestRule.replaceRule = true;
    filteringEvent.replaceRules = [];
    replaceRules.forEach(replaceRule => {
      const ruleDTO = {};
      copyRuleProperties(ruleDTO, replaceRule);
      filteringEvent.replaceRules.push(ruleDTO);
    });
  };

  const isExistingCookieEvent = ({
    tabId,
    cookieName,
    cookieValue,
    cookieDomain
  }) => {
    const tabInfo = getFilteringInfoByTabId(tabId);
    const filteringEvents = tabInfo === null || tabInfo === void 0 ? void 0 : tabInfo.filteringEvents;

    if (!filteringEvents) {
      return false;
    }

    return filteringEvents.some(event => {
      return event.frameDomain === cookieDomain && event.cookieName === cookieName && event.cookieValue === cookieValue;
    });
  };
  /**
   * Adds cookie rule event
   *
   * @param {Object} params - params object
   * @param {Object} params.tabId
   * @param {string} params.cookieName
   * @param {string} params.cookieValue
   * @param {string} params.cookieDomain
   * @param {object} params.cookieRule
   * @param {boolean} params.isModifyingCookieRule
   * @param {boolean} params.thirdParty
   * @param {number} params.timestamp - Request UTC timestamp
   */


  const addCookieEvent = ({
    tabId,
    cookieName,
    cookieValue,
    cookieDomain,
    cookieRule,
    isModifyingCookieRule,
    thirdParty,
    timestamp
  }) => {
    if (!canAddEvent(tabId)) {
      return;
    }

    if (isExistingCookieEvent({
      tabId,
      cookieName,
      cookieValue,
      cookieDomain
    })) {
      return;
    }

    const filteringEvent = {
      frameDomain: cookieDomain,
      requestType: RequestTypes.COOKIE,
      requestThirdParty: thirdParty,
      cookieName,
      cookieValue,
      timestamp
    };

    if (cookieRule) {
      // Copy useful properties
      addRuleToFilteringEvent(filteringEvent, cookieRule);
      filteringEvent.requestRule.isModifyingCookieRule = isModifyingCookieRule;

      if (cookieRule.stealthActions) {
        filteringEvent.stealthActions = cookieRule.stealthActions;
      }
    }

    pushFilteringEvent(tabId, filteringEvent);
  };
  /**
   * Binds rule to HTTP request
   * @param tab Tab
   * @param requestRule Request rule
   * @param eventId Event identifier
   */


  const bindRuleToHttpRequestEvent = function (tab, requestRule, eventId) {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const tabInfo = getFilteringInfoByTabId(tab.tabId);
    const events = tabInfo.filteringEvents;

    if (events) {
      for (let i = events.length - 1; i >= 0; i -= 1) {
        const event = events[i];

        if (event.eventId === eventId) {
          addRuleToFilteringEvent(event, requestRule);
          break;
        }
      }
    }
  };
  /**
   * Replace rules are fired after the event was added
   * We should find event for this rule and update in log UI
   * @param tab
   * @param replaceRules
   * @param eventId
   */


  const bindReplaceRulesToHttpRequestEvent = function (tab, replaceRules, eventId) {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const tabInfo = getFilteringInfoByTabId(tab.tabId);
    const events = tabInfo.filteringEvents;

    if (events) {
      for (let i = events.length - 1; i >= 0; i -= 1) {
        const event = events[i];

        if (event.eventId === eventId) {
          addReplaceRulesToFilteringEvent(event, replaceRules);
          break;
        }
      }
    }
  };
  /**
   * Binds applied stealth actions to HTTP request
   *
   * @param {object} tab Request tab
   * @param {number} actions Applied actions
   * @param {number} eventId Event identifier
   */


  const bindStealthActionsToHttpRequestEvent = (tab, actions, eventId) => {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const tabInfo = getFilteringInfoByTabId(tab.tabId);
    const events = tabInfo.filteringEvents;

    if (events) {
      for (let i = events.length - 1; i >= 0; i -= 1) {
        const event = events[i];

        if (event.eventId === eventId) {
          event.stealthActions = actions;
          break;
        }
      }
    }
  };
  /**
   * Binds applied cspReportBlocked to HTTP request
   *
   * @param {object} tab Request tab
   * @param {boolean} cspReportBlocked is csp report blocked flag
   * @param {number} eventId Event identifier
   */


  const bindCspReportBlockedToHttpRequestEvent = (tab, cspReportBlocked, eventId) => {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const tabInfo = getFilteringInfoByTabId(tab.tabId);
    const events = tabInfo.filteringEvents;

    if (events) {
      for (let i = events.length - 1; i >= 0; i -= 1) {
        const event = events[i];

        if (event.eventId === eventId) {
          event.cspReportBlocked = cspReportBlocked;
          break;
        }
      }
    }
  };
  /**
   * Binds response status code to HTTP request
   *
   * @param {object} tab Request tab
   * @param {number} statusCode Response status code
   * @param {number} eventId Event identifier
   */


  const bindResponseDataToHttpRequestEvent = (tab, statusCode, eventId) => {
    if (!canAddEvent(tab.tabId)) {
      return;
    }

    const tabInfo = getFilteringInfoByTabId(tab.tabId);
    const events = tabInfo.filteringEvents;

    if (events) {
      for (let i = events.length - 1; i >= 0; i -= 1) {
        const event = events[i];

        if (event.eventId === eventId) {
          event.statusCode = statusCode;
          break;
        }
      }
    }
  };
  /**
   * Remove log requests for tab
   * @param {number} tabId
   * @param {boolean} [ignorePreserveLog]
   */


  const clearEventsByTabId = function (tabId, ignorePreserveLog) {
    const tabInfo = tabsInfoMap[tabId];
    const preserveLog = ignorePreserveLog ? false : preserveLogEnabled;

    if (tabInfo && !preserveLog) {
      delete tabInfo.filteringEvents;
      listeners.notifyListeners(listeners.TAB_RESET, tabInfo);
    }
  };
  /**
   * Synchronize currently opened tabs with out state
   */


  const synchronizeOpenTabs = async function () {
    const tabs = await tabsApi.getAll(); // As Object.keys() returns strings we convert them to integers,
    // because tabId is integer in extension API

    const tabIdsToRemove = Object.keys(tabsInfoMap).map(id => parseInt(id, 10));

    for (let i = 0; i < tabs.length; i += 1) {
      const openTab = tabs[i];
      const tabInfo = tabsInfoMap[openTab.tabId];

      if (!tabInfo) {
        // add tab
        addTab(openTab);
      } else {
        // update tab
        updateTab(openTab);
      }

      const index = tabIdsToRemove.indexOf(openTab.tabId);

      if (index >= 0) {
        tabIdsToRemove.splice(index, 1);
      }
    }

    for (let j = 0; j < tabIdsToRemove.length; j += 1) {
      removeTabById(tabIdsToRemove[j]);
    }

    const syncTabs = [];
    Object.keys(tabsInfoMap).forEach(tabId => {
      syncTabs.push(tabsInfoMap[tabId]);
    });
    return syncTabs;
  };
  /**
   * Returns info if preserve log is enabled
   * @return {boolean}
   */


  const isPreserveLogEnabled = () => {
    return preserveLogEnabled;
  };
  /**
   * Allows to toggle preserve log state
   * @param enabled
   */


  const setPreserveLogState = enabled => {
    preserveLogEnabled = enabled;
  };
  /**
   * We should synchronize open tabs and add listeners to the tabs after application
   * is initialized. Otherwise updating tabs can return wrong stats values and
   * overwrite them with wrong data
   */


  const init = () => {
    // Initialize filtering log
    synchronizeOpenTabs(); // Bind to tab events

    tabsApi.onCreated.addListener(addTab);
    tabsApi.onUpdated.addListener(updateTab);
    tabsApi.onRemoved.addListener(tab => {
      removeTabById(tab.tabId);
    });
  };

  return {
    synchronizeOpenTabs,
    init,
    getFilteringInfoByTabId,
    addHttpRequestEvent,
    bindRuleToHttpRequestEvent,
    bindReplaceRulesToHttpRequestEvent,
    addCosmeticEvent,
    addCookieEvent,
    addRemoveParamEvent,
    addRemoveHeaderEvent,
    addScriptInjectionEvent,
    bindStealthActionsToHttpRequestEvent,
    bindCspReportBlockedToHttpRequestEvent,
    bindResponseDataToHttpRequestEvent,
    clearEventsByTabId,
    isOpen,
    onOpenFilteringLogPage,
    onCloseFilteringLogPage,
    isPreserveLogEnabled,
    setPreserveLogState
  };
}();

/* harmony default export */ const filtering_log_browsers = (browsersFilteringLog);
;// CONCATENATED MODULE: ./Extension/src/background/filter/filtering-log/index.js
/**
 * !IMPORTANT!
 * './filtering-log.__ABSTRACT_BROWSERS__' is replaced during webpack compilation
 * with NormalModuleReplacementPlugin to proper browser implementation
 * './filtering-log.firefox' or './filtering-log.chrome'
 */


// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.add-all.js
var esnext_set_add_all = __webpack_require__(6063);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.delete-all.js
var esnext_set_delete_all = __webpack_require__(2336);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.difference.js
var esnext_set_difference = __webpack_require__(7226);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.every.js
var esnext_set_every = __webpack_require__(641);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.filter.js
var esnext_set_filter = __webpack_require__(5299);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.find.js
var esnext_set_find = __webpack_require__(2980);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.intersection.js
var esnext_set_intersection = __webpack_require__(2801);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.is-disjoint-from.js
var esnext_set_is_disjoint_from = __webpack_require__(7396);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.is-subset-of.js
var esnext_set_is_subset_of = __webpack_require__(6600);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.is-superset-of.js
var esnext_set_is_superset_of = __webpack_require__(9503);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.join.js
var esnext_set_join = __webpack_require__(6119);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.map.js
var esnext_set_map = __webpack_require__(608);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.reduce.js
var esnext_set_reduce = __webpack_require__(4061);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.some.js
var esnext_set_some = __webpack_require__(2229);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.symmetric-difference.js
var esnext_set_symmetric_difference = __webpack_require__(9055);
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.set.union.js
var esnext_set_union = __webpack_require__(3286);
;// CONCATENATED MODULE: ./Extension/src/background/filter/engine.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */





/**
 * TSUrlFilter Engine wrapper
 */

const engine = function () {
  const ASYNC_LOAD_CHUNK_SIZE = 5000;
  let engine;
  /**
   * Do not allow match requests until engine didn't load all rules
   * Otherwise engine can cache empty results for match requests
   * @return {*}
   */

  const isReady = () => {
    return Boolean(engine);
  };

  const startEngine = async lists => {
    log.info('Starting url filter engine'); // reset engine instance to avoid cached null values,
    // which may occur if try to get match result before all rules are loaded

    engine = null;
    const ruleStorage = new tsurlfilter_browser.RuleStorage(lists);
    const config = {
      engine: 'extension',
      version: backgroundPage.app && backgroundPage.app.getVersion(),
      verbose: true,
      compatibility: tsurlfilter_browser.CompatibilityTypes.extension
    };
    tsurlfilter_browser.setConfiguration(config);
    const engineInstance = new tsurlfilter_browser.Engine(ruleStorage, true);
    /*
     * UI thread becomes blocked on the options page while request filter is created
     * that's why we create filter rules using chunks of the specified length
     * Request filter creation is rather slow operation so we should
     * use setTimeout calls to give UI thread some time.
    */

    await engineInstance.loadRulesAsync(ASYNC_LOAD_CHUNK_SIZE);
    engine = engineInstance;
    log.info('Starting url filter engine..ok');
  };
  /**
   * @typedef {object} MatchQuery - Request Match Query
   *
   * @property {string} requestUrl    Request URL
   * @property {string} frameUrl      Document URL
   * @property {any} requestType      Request content type (one of UrlFilterRule.contentTypes)
   * @property {any} frameRule        Frame rule
  */

  /**
   * Gets matching result for request.
   *
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   * @returns matching result or null
   */


  const matchRequest = matchQuery => {
    const {
      requestUrl,
      frameUrl,
      requestType
    } = matchQuery;
    let {
      frameRule
    } = matchQuery;
    log.debug('Filtering http request for url: {0}, document: {1}, requestType: {2}', requestUrl, frameUrl, requestType);

    if (!isReady()) {
      log.warn('Filtering engine is not ready');
      return null;
    }

    if (!frameRule) {
      frameRule = null;
    }

    const request = new tsurlfilter_browser.Request(requestUrl, frameUrl, RequestTypes.transformRequestType(requestType));
    const result = engine.matchRequest(request, frameRule);
    log.debug('Result {0} found for url: {1}, document: {2}, requestType: {3}', result.getBasicResult(), requestUrl, frameUrl, requestType);
    return result;
  };
  /**
   * Matches current frame url and returns document-level rule if found.
   *
   * @param frameUrl    Frame URL
   * @returns matching result or null
   */


  const matchFrame = frameUrl => {
    if (!isReady()) {
      log.warn('Filtering engine is not ready');
      return null;
    }

    return engine.matchFrame(frameUrl);
  };
  /**
   * Gets cosmetic result for the specified hostname and cosmetic options
   *
   * @param url
   * @param option
   * @returns CosmeticResult result
   */


  const getCosmeticResult = (url, option) => {
    if (!isReady()) {
      return new tsurlfilter_browser.CosmeticResult();
    }

    const frameUrl = utils.url.getHost(url);
    const request = new tsurlfilter_browser.Request(url, frameUrl, tsurlfilter_browser.RequestType.Document);
    return engine.getCosmeticResult(request, option);
  };
  /**
   * @return Engine rules count
   */


  const getRulesCount = () => {
    return isReady() ? engine.getRulesCount() : 0;
  };

  return {
    startEngine,
    getRulesCount,
    isReady,
    matchRequest,
    matchFrame,
    getCosmeticResult
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/rules/local-script-rules/local-script-rules.chrome.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Empty module for chrome
 */
const localScriptRulesService = function () {
  const setLocalScriptRules = function () {// Do nothing
  };

  const isLocal = function () {
    // For chrome all rules are 'local'
    return true;
  };

  return {
    setLocalScriptRules,
    isLocal
  };
}();

/* harmony default export */ const local_script_rules_chrome = (localScriptRulesService);
;// CONCATENATED MODULE: ./Extension/src/background/filter/rules/local-script-rules/index.js
/**
 * !IMPORTANT!
 * './local-script-rules.__ABSTRACT_BROWSERS__' is replaced during webpack compilation
 * with NormalModuleReplacementPlugin to proper browser implementation
 * './local-script-rules.firefox' or './local-script-rules.chrome'
 */


;// CONCATENATED MODULE: ./Extension/src/background/filter/services/css-service.js
/**
 * Class to manage css
 */
const cssService = (() => {
  /**
   * Builds stylesheet from rules
   *
   * @param elemhideRules
   * @param injectRules
   * @param groupElemhideSelectors
   * @return {[]}
   */
  const buildStyleSheet = (elemhideRules, injectRules, groupElemhideSelectors) => {
    const CSS_SELECTORS_PER_LINE = 50;
    const ELEMHIDE_CSS_STYLE = ' { display: none!important; }\r\n';
    const elemhides = [];
    let selectorsCount = 0; // eslint-disable-next-line no-restricted-syntax

    for (const selector of elemhideRules) {
      selectorsCount += 1;
      elemhides.push(selector.getContent());

      if (selectorsCount % CSS_SELECTORS_PER_LINE === 0 || !groupElemhideSelectors) {
        elemhides.push(ELEMHIDE_CSS_STYLE);
      } else {
        elemhides.push(', ');
      }
    }

    if (elemhides.length > 0) {
      // Last element should always be a style (it will replace either a comma or the same style)
      elemhides[elemhides.length - 1] = ELEMHIDE_CSS_STYLE;
    }

    const elemHideStyle = elemhides.join('');
    const cssStyle = injectRules.map(x => x.getContent()).join('\r\n');
    const styles = [];

    if (elemHideStyle) {
      styles.push(elemHideStyle);
    }

    if (cssStyle) {
      styles.push(cssStyle);
    }

    return styles;
  };

  const ELEMHIDE_HIT_START = " { display: none!important; content: 'adguard";
  const INJECT_HIT_START = " content: 'adguard";
  const HIT_SEP = encodeURIComponent(';');
  const HIT_END = "' !important;}\r\n";
  /**
   * Urlencodes rule text.
   *
   * @param ruleText
   * @return {string}
   */

  const escapeRule = ruleText => encodeURIComponent(ruleText).replace(/['()]/g, match => ({
    "'": '%27',
    '(': '%28',
    ')': '%29'
  })[match]);
  /**
   * Patch rule selector adding adguard mark rule info in the content attribute
   * Example:
   * .selector -> .selector { content: 'adguard{filterId};{ruleText} !important;}
   * @param rule
   * @returns {String}
   */


  const addMarkerToElemhideRule = rule => {
    const result = [];
    result.push(rule.getContent());
    result.push(ELEMHIDE_HIT_START);
    result.push(rule.getFilterListId());
    result.push(HIT_SEP);
    result.push(escapeRule(rule.getText()));
    result.push(HIT_END);
    return result.join('');
  };
  /**
   * Patch rule selector adding adguard mark and rule info in the content attribute
   * Example:
   * .selector { color: red } -> .selector { color: red, content: 'adguard{filterId};{ruleText} !important;}
   * @param rule
   * @returns {String}
   */


  const addMarkerToInjectRule = rule => {
    const result = [];
    const ruleContent = rule.getContent(); // if rule text has content attribute we don't add rule marker

    const contentAttributeRegex = /[{;"(]\s*content\s*:/gi;

    if (contentAttributeRegex.test(ruleContent)) {
      return ruleContent;
    } // remove closing brace


    const ruleTextWithoutCloseBrace = ruleContent.slice(0, -1).trim(); // check semicolon

    const ruleTextWithSemicolon = ruleTextWithoutCloseBrace.endsWith(';') ? ruleTextWithoutCloseBrace : `${ruleTextWithoutCloseBrace};`;
    result.push(ruleTextWithSemicolon);
    result.push(INJECT_HIT_START);
    result.push(rule.getFilterListId());
    result.push(HIT_SEP);
    result.push(escapeRule(rule.getText()));
    result.push(HIT_END);
    return result.join('');
  };
  /**
   * Builds stylesheet with css-hits marker
   *
   * @param elemhideRules
   * @param injectRules
   * @return {*[]}
   */


  const buildStyleSheetHits = (elemhideRules, injectRules) => {
    const elemhideStyles = elemhideRules.map(x => addMarkerToElemhideRule(x));
    const injectStyles = injectRules.map(x => addMarkerToInjectRule(x));
    return [...elemhideStyles, ...injectStyles];
  };

  return {
    buildStyleSheet,
    buildStyleSheetHits
  };
})();
// EXTERNAL MODULE: ./node_modules/core-js/modules/esnext.string.replace-all.js
var esnext_string_replace_all = __webpack_require__(1625);
// EXTERNAL MODULE: ./node_modules/@adguard/filters-downloader/src/index.browser.js
var index_browser = __webpack_require__(9317);
var index_browser_default = /*#__PURE__*/__webpack_require__.n(index_browser);
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/service-client.js


/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







/**
 * Class for working with our backend server.
 * All requests sent by this class are covered in the privacy policy:
 * http://adguard.com/en/privacy.html#browsers
 */

const backend = function () {
  /**
   * Settings
   */
  const settings = {
    // Base url of our backend server
    get backendUrl() {
      return 'https://chrome.adtidy.org';
    },

    get apiKey() {
      return '4DDBE80A3DA94D819A00523252FB6380';
    },

    // Url for load filters metadata and rules
    get filtersUrl() {
      return lazyGet(this, 'filtersUrl', () => {
        if (browserUtils.isFirefoxBrowser()) {
          return 'https://filters.adtidy.org/extension/firefox';
        }

        if (browserUtils.isEdgeBrowser()) {
          return 'https://filters.adtidy.org/extension/edge';
        }

        if (browserUtils.isOperaBrowser()) {
          return 'https://filters.adtidy.org/extension/opera';
        }

        return 'https://filters.adtidy.org/extension/chromium';
      });
    },

    // URL for downloading AG filters
    get filterRulesUrl() {
      return `${this.filtersUrl}/filters/{filter_id}.txt`;
    },

    // URL for downloading optimized AG filters
    get optimizedFilterRulesUrl() {
      return `${this.filtersUrl}/filters/{filter_id}_optimized.txt`;
    },

    // URL for checking filter updates
    get filtersMetadataUrl() {
      const params = browserUtils.getExtensionParams();
      return `${this.filtersUrl}/filters.js?${params.join('&')}`;
    },

    // URL for downloading i18n localizations
    get filtersI18nMetadataUrl() {
      const params = browserUtils.getExtensionParams();
      return `${this.filtersUrl}/filters_i18n.json?${params.join('&')}`;
    },

    // URL for user complaints on missed ads or malware/phishing websites
    get reportUrl() {
      return `${this.backendUrl}/url-report.html`;
    },

    /**
     * URL for collecting filter rules statistics.
     * We do not collect it by default, unless user is willing to help.
     *
     * Filter rules stats are covered in our privacy policy and on also here:
     * http://adguard.com/en/filter-rules-statistics.html
     */
    get ruleStatsUrl() {
      return `${this.backendUrl}/rulestats.html`;
    },

    /**
     * Browsing Security lookups. In case of Firefox lookups are disabled for HTTPS urls.
     */
    get safebrowsingLookupUrl() {
      return 'https://sb.adtidy.org/safebrowsing-lookup-short-hash.html';
    },

    // Folder that contains filters metadata and files with rules. 'filters' by default
    get localFiltersFolder() {
      return 'filters';
    },

    // Path to the redirect sources
    get redirectSourcesFolder() {
      return 'assets/libs/scriptlets';
    },

    // Array of filter identifiers, that have local file with rules. Range from 1 to 14 by default
    get localFilterIds() {
      return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
    }

  };
  /**
   * FiltersDownloader constants
   */

  const FilterCompilerConditionsConstants = {
    adguard: true,
    adguard_ext_chromium: browserUtils.isChromium(),
    adguard_ext_firefox: browserUtils.isFirefoxBrowser(),
    adguard_ext_edge: browserUtils.isEdgeBrowser(),
    adguard_ext_safari: false,
    adguard_ext_opera: browserUtils.isOperaBrowser()
  };
  /**
   * Loading subscriptions map
   */

  const loadingSubscriptions = Object.create(null);
  /**
   * Executes async request
   * @param url Url
   * @param contentType Content type
   */

  function executeRequestAsync(url, contentType) {
    return new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();

      try {
        request.open('GET', url);
        request.setRequestHeader('Content-type', contentType);
        request.setRequestHeader('Pragma', 'no-cache');
        request.overrideMimeType(contentType);
        request.mozBackgroundRequest = true;

        request.onload = function () {
          resolve(request);
        };

        const errorCallbackWrapper = errorMessage => {
          return e => {
            let errorText = errorMessage;

            if (e !== null && e !== void 0 && e.message) {
              errorText = `${errorText}: ${e === null || e === void 0 ? void 0 : e.message}`;
            }

            const error = new Error(`Error: "${errorText}", statusText: ${request.statusText}`);
            reject(error);
          };
        };

        request.onerror = errorCallbackWrapper('An error occurred');
        request.onabort = errorCallbackWrapper('Request was aborted');
        request.ontimeout = errorCallbackWrapper('Request stopped by timeout');
        request.send(null);
      } catch (ex) {
        reject(ex);
      }
    });
  }
  /**
   * URL for downloading AG filter
   *
   * @param filterId Filter identifier
   * @param useOptimizedFilters
   * @private
   */


  function getUrlForDownloadFilterRules(filterId, useOptimizedFilters) {
    const url = useOptimizedFilters ? settings.optimizedFilterRulesUrl : settings.filterRulesUrl;
    return utils.strings.replaceAll(url, '{filter_id}', filterId);
  }
  /**
   * Appends request key to url
   */


  function addKeyParameter(url) {
    return `${url}&key=${settings.apiKey}`;
  }
  /**
   * Safe json parsing
   * @param text
   * @private
   */


  function parseJson(text) {
    try {
      return JSON.parse(text);
    } catch (ex) {
      log.error('Error parse json {0}', ex);
      return null;
    }
  }
  /**
   * Downloads metadata from backend
   * @return {Promise<void>}
   */


  const downloadMetadataFromBackend = async () => {
    const response = await executeRequestAsync(settings.filtersMetadataUrl, 'application/json');

    if (!(response !== null && response !== void 0 && response.responseText)) {
      throw new Error(`Empty response: ${response}`);
    }

    const metadata = parseJson(response.responseText);

    if (!metadata) {
      throw new Error(`Invalid response: ${response}`);
    }

    return metadata;
  };
  /**
   * Downloads i18n metadata from backend
   * @return {Promise<void>}
   */


  const downloadI18nMetadataFromBackend = async () => {
    const response = await executeRequestAsync(settings.filtersI18nMetadataUrl, 'application/json');

    if (!(response !== null && response !== void 0 && response.responseText)) {
      throw new Error(`Empty response: ${response}`);
    }

    const metadata = parseJson(response.responseText);

    if (!metadata) {
      throw new Error(`Invalid response: ${response}`);
    }

    return metadata;
  };
  /**
   * Downloads filter rules by filter ID
   *
   * @param filterId              Filter identifier
   * @param forceRemote           Force download filter rules from remote server
   * @param useOptimizedFilters   Download optimized filters flag
   * @returns {Promise<string>}   Downloaded rules
   */


  const downloadFilterRules = (filterId, forceRemote, useOptimizedFilters) => {
    let url;

    if (forceRemote || settings.localFilterIds.indexOf(filterId) < 0) {
      url = getUrlForDownloadFilterRules(filterId, useOptimizedFilters);
    } else {
      url = backgroundPage.getURL(`${settings.localFiltersFolder}/filter_${filterId}.txt`);

      if (useOptimizedFilters) {
        url = backgroundPage.getURL(`${settings.localFiltersFolder}/filter_mobile_${filterId}.txt`);
      }
    }

    return index_browser_default().download(url, FilterCompilerConditionsConstants);
  };
  /**
   * Downloads filter rules by url
   *
   * @param url - Subscription url
   */


  const downloadFilterRulesBySubscriptionUrl = async url => {
    if (url in loadingSubscriptions) {
      return;
    }

    loadingSubscriptions[url] = true;

    try {
      let lines = await index_browser_default().download(url, FilterCompilerConditionsConstants);
      lines = index_browser_default().resolveConditions(lines, FilterCompilerConditionsConstants);
      delete loadingSubscriptions[url];

      if (lines[0].indexOf('[') === 0) {
        // [Adblock Plus 2.0]
        lines.shift();
      }

      return lines;
    } catch (e) {
      delete loadingSubscriptions[url];
      const message = e instanceof Error ? e.message : e;
      throw new Error(message);
    }
  };

  const createError = (message, url, response) => {
    let errorMessage = `
            error:                    ${message}
            requested url:            ${url}`;

    if (response) {
      errorMessage = `
            error:                    ${message}
            requested url:            ${url}
            request status text:      ${response.statusText}`;
    }

    return new Error(errorMessage);
  };
  /**
   * Loads filter groups metadata
   */


  const getLocalFiltersMetadata = async () => {
    var _response;

    const url = backgroundPage.getURL(`${settings.localFiltersFolder}/filters.json`);
    let response;

    try {
      response = await executeRequestAsync(url, 'application/json');
    } catch (e) {
      const exMessage = (e === null || e === void 0 ? void 0 : e.message) || 'couldn\'t load local filters metadata';
      throw createError(exMessage, url);
    }

    if (!((_response = response) !== null && _response !== void 0 && _response.responseText)) {
      throw createError('empty response', url, response);
    }

    const metadata = parseJson(response.responseText);

    if (!metadata) {
      throw createError('invalid response', url, response);
    }

    return metadata;
  };
  /**
   * Loads filter groups metadata from local file
   * @returns {Promise}
   */


  const getLocalFiltersI18Metadata = async () => {
    var _response2;

    const url = backgroundPage.getURL(`${settings.localFiltersFolder}/filters_i18n.json`);
    let response;

    try {
      response = await executeRequestAsync(url, 'application/json');
    } catch (e) {
      const exMessage = (e === null || e === void 0 ? void 0 : e.message) || 'couldn\'t load local filters i18n metadata';
      throw createError(exMessage, url);
    }

    if (!((_response2 = response) !== null && _response2 !== void 0 && _response2.responseText)) {
      throw createError('empty response', url, response);
    }

    const metadata = parseJson(response.responseText);

    if (!metadata) {
      throw createError('invalid response', url, response);
    }

    return metadata;
  };
  /**
   * Loads script rules from local file
   * @returns {Promise}
   */


  const getLocalScriptRules = async () => {
    var _response3;

    const url = backgroundPage.getURL(`${settings.localFiltersFolder}/local_script_rules.json`);
    let response;

    try {
      response = await executeRequestAsync(url, 'application/json');
    } catch (e) {
      const exMessage = (e === null || e === void 0 ? void 0 : e.message) || 'couldn\'t load local script rules';
      throw createError(exMessage, url);
    }

    if (!((_response3 = response) !== null && _response3 !== void 0 && _response3.responseText)) {
      throw createError('empty response', url, response);
    }

    const metadata = parseJson(response.responseText);

    if (!metadata) {
      throw createError('invalid response', url, response);
    }

    return metadata;
  }; // TODO check necessity of this module,
  //  as we already have redirect sources in the webaccessible-resources folder

  /**
   * Loads redirect sources from local file
   * @returns {Promise}
   */


  const getRedirectSources = async () => {
    var _response4;

    const url = `${backgroundPage.getURL(settings.redirectSourcesFolder)}/redirects.yml`;
    let response;

    try {
      response = await executeRequestAsync(url, 'application/x-yaml');
    } catch (e) {
      const exMessage = (e === null || e === void 0 ? void 0 : e.message) || 'couldn\'t load redirect sources';
      throw createError(exMessage, url);
    }

    if (!((_response4 = response) !== null && _response4 !== void 0 && _response4.responseText)) {
      throw createError('empty response', url, response);
    }

    return response.responseText;
  };
  /**
   * Checks specified host hashes with our safebrowsing service
   *
   * @param hashes                Host hashes
   */


  const lookupSafebrowsing = async function (hashes) {
    const url = `${settings.safebrowsingLookupUrl}?prefixes=${encodeURIComponent(hashes.join('/'))}`;
    const response = await executeRequestAsync(url, 'application/json');
    return response;
  };
  /**
   * Sends feedback from the user to our server
   *
   * @param url           URL
   * @param messageType   Message type
   * @param comment       Message text
   */


  const sendUrlReport = function (url, messageType, comment) {
    let params = `url=${encodeURIComponent(url)}`;
    params += `&messageType=${encodeURIComponent(messageType)}`;

    if (comment) {
      params += `&comment=${encodeURIComponent(comment)}`;
    }

    params = addKeyParameter(params);
    const request = new XMLHttpRequest();
    request.open('POST', settings.reportUrl);
    request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    request.send(params);
  };
  /**
   * Sends filter hits stats to backend server.
   * This method is used if user has enabled "Send statistics for ad filters usage".
   * More information about ad filters usage stats:
   * http://adguard.com/en/filter-rules-statistics.html
   *
   * @param stats             Stats
   * @param enabledFilters    List of enabled filters
   */


  const sendHitStats = function (stats, enabledFilters) {
    let params = `stats=${encodeURIComponent(stats)}`;
    params += `&v=${encodeURIComponent(backgroundPage.app.getVersion())}`;
    params += `&b=${encodeURIComponent(prefs.browser)}`;

    if (enabledFilters) {
      for (let i = 0; i < enabledFilters.length; i += 1) {
        const filter = enabledFilters[i];
        params += `&f=${encodeURIComponent(`${filter.filterId},${filter.version}`)}`;
      }
    }

    params = addKeyParameter(params);
    const request = new XMLHttpRequest();
    request.open('POST', settings.ruleStatsUrl);
    request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    request.send(params);
  };
  /**
   * Configures backend's URLs
   * @param configuration Configuration object:
   * {
   *  filtersMetadataUrl: '...',
   *  filterRulesUrl: '...',
   *  localFiltersFolder: '...',
   *  localFilterIds: []
   * }
   */


  const configure = function (configuration) {
    const {
      filtersMetadataUrl
    } = configuration;

    if (filtersMetadataUrl) {
      Object.defineProperty(settings, 'filtersMetadataUrl', {
        get() {
          return filtersMetadataUrl;
        }

      });
    }

    const {
      filterRulesUrl
    } = configuration;

    if (filterRulesUrl) {
      Object.defineProperty(settings, 'filterRulesUrl', {
        get() {
          return filterRulesUrl;
        }

      });
    }

    const {
      localFiltersFolder
    } = configuration;

    if (localFiltersFolder) {
      Object.defineProperty(settings, 'localFiltersFolder', {
        get() {
          return localFiltersFolder;
        }

      });
    }

    const {
      redirectSourcesFolder
    } = configuration;

    if (redirectSourcesFolder) {
      Object.defineProperty(settings, 'redirectSourcesFolder', {
        get() {
          return redirectSourcesFolder;
        }

      });
    }

    const {
      localFilterIds
    } = configuration;

    if (localFilterIds) {
      Object.defineProperty(settings, 'localFilterIds', {
        get() {
          return localFilterIds;
        }

      });
    }
  };

  return {
    downloadFilterRules,
    downloadFilterRulesBySubscriptionUrl,
    getLocalFiltersMetadata,
    getLocalFiltersI18Metadata,
    getLocalScriptRules,
    getRedirectSources,
    downloadMetadataFromBackend,
    downloadI18nMetadataFromBackend,
    lookupSafebrowsing,
    sendUrlReport,
    sendHitStats,
    configure
  };
}();
// EXTERNAL MODULE: ./node_modules/@adguard/scriptlets/dist/umd/scriptlets.umd.js
var scriptlets_umd = __webpack_require__(8782);
// EXTERNAL MODULE: ./node_modules/lru_map/dist/lru.js
var lru = __webpack_require__(7553);
;// CONCATENATED MODULE: ./Extension/src/background/utils/redirects-cache.js

/**
 * Used for new type of redirects, i.e. click2load.html
 */

const redirectsCache = function () {
  const cache = new lru.LRUMap(100);

  const add = url => cache.set(url, true);

  const hasUrl = url => cache.has(url);

  return {
    add,
    hasUrl
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/redirects-tokens-cache.js


/**
 * Used for new type of redirects, i.e. click2load.html
 */

const redirectsTokensCache = function () {
  const cache = new lru.LRUMap(1000);
  /**
   * Generates random unblock token for url and saves it to cache.
   * Used while redirect creating in createRedirectFileUrl()
   * @returns {string} token
   */

  const generateToken = () => {
    const token = nanoid();
    cache.set(token, true);
    return token;
  };
  /**
   * Checks whether token exist in cache.
   * Used while redirect checking in getBlockedResponseByRule()
   * @param {string} token
   * @returns {boolean}
   */


  const hasToken = token => cache.has(token);

  return {
    generateToken,
    hasToken
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/resources.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */




/**
 * Web accessible resources helper
 */

const resources = function () {
  /**
   * Resources directory
   *
   * @type {string}
   */
  const WEB_ACCESSIBLE_RESOURCES = 'web-accessible-resources';
  /**
   * Foil ability of web pages to identify extension through its web accessible resources.
   *
   * Inspired by:
   * https://github.com/gorhill/uBlock/blob/7f999b7/platform/chromium/vapi-background.js
   */

  const warSecret = (() => {
    const root = browser_polyfill_default().runtime.getURL('/');
    const secrets = [];
    let lastSecretTime = 0; // eslint-disable-next-line consistent-return

    const guard = function (details) {
      const {
        url
      } = details;
      const pos = secrets.findIndex(secret => url.lastIndexOf(`?secret=${secret}`) !== -1);

      if (pos === -1) {
        return {
          redirectUrl: root
        };
      }

      secrets.splice(pos, 1);
    };

    browser_polyfill_default().webRequest.onBeforeRequest.addListener(guard, {
      urls: [`${root}${WEB_ACCESSIBLE_RESOURCES}/*`]
    }, ['blocking']);
    return () => {
      if (secrets.length !== 0) {
        if (Date.now() - lastSecretTime > 5000) {
          secrets.splice(0);
        } else if (secrets.length > 256) {
          secrets.splice(0, secrets.length - 192);
        }
      }

      lastSecretTime = Date.now();
      const secret = nanoid();
      secrets.push(secret);
      return `?secret=${secret}`;
    };
  })();
  /**
   * Load resources by path
   *
   * @param path
   * @return {Promise<string>}
   */


  const loadResource = async path => {
    const url = browser_polyfill_default().runtime.getURL(`/${WEB_ACCESSIBLE_RESOURCES}/${path}${warSecret()}`);
    const response = await fetch(url);
    return response.text();
  };
  /**
   * Create url for redirect file
   *
   * @param {string} redirectFile
   * @param {string} requestUrl
   * @return {*}
   */


  const createRedirectFileUrl = (redirectFile, requestUrl) => {
    const params = new URLSearchParams(warSecret());

    if (redirectService.getBlockingRedirects().includes(redirectFile)) {
      const unblockToken = redirectsTokensCache.generateToken();
      params.set('__unblock', unblockToken);
      params.set('__origin', requestUrl);
    }

    return browser_polyfill_default().runtime.getURL(`${WEB_ACCESSIBLE_RESOURCES}/redirects/${redirectFile}?${params.toString()}`);
  }; // EXPOSE


  return {
    loadResource,
    createRedirectFileUrl
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/redirect-service.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */





const {
  Redirects
} = scriptlets_umd.redirects;
/**
 * Redirects service class
 */

const redirectService = function () {
  let redirects = null; // list of blocking type redirects, i.e. for click2load.html

  let blockingRedirects = [];
  /**
   * Initialize service
   */

  const init = rawYaml => {
    redirects = new Redirects(rawYaml);
    const redirectsData = redirects.redirects;
    blockingRedirects = Object.keys(redirectsData).filter(r => redirectsData[r].isBlocking);
  };
  /**
   * Returns blocking redirects titles array
   * @returns {string[]}
   */


  const getBlockingRedirects = () => blockingRedirects;
  /**
   * Check whether redirect creating is needed
   * i.e. for click2load.html it's not needed after button click
   * @param {string} redirectTitle
   * @param {string} requestUrl
   * @returns {boolean}
   */


  const shouldCreateRedirectUrl = (redirectTitle, requestUrl) => {
    if (!blockingRedirects.includes(redirectTitle)) {
      // no further checking is needed for most of redirects
      // except blocking redirects, i.e. click2load.html
      return true;
    } // unblock token passed to redirect by createRedirectFileUrl and returned back.
    // it should be last parameter in url


    const UNBLOCK_TOKEN_PARAM = '__unblock';
    let cleanRequestUrl = requestUrl;
    const url = new URL(requestUrl);
    const params = new URLSearchParams(url.search);
    const unblockToken = params.get(UNBLOCK_TOKEN_PARAM);

    if (unblockToken) {
      // if redirect has returned unblock token back,
      // add url to cache for no further redirecting on button click;
      // save cleaned origin url so unblock token parameter should be cut off
      params.delete(UNBLOCK_TOKEN_PARAM);
      cleanRequestUrl = `${url.origin}${url.pathname}?${params.toString}`;
      redirectsCache.add(cleanRequestUrl);
    }

    return !redirectsCache.hasUrl(cleanRequestUrl) || !redirectsTokensCache.hasToken(unblockToken);
  };
  /**
   * Creates url
   *
   * @param title
   * @param requestUrl
   * @return string|null
   */


  const createRedirectUrl = (title, requestUrl) => {
    if (!title) {
      return null;
    }

    const shouldRedirect = shouldCreateRedirectUrl(title, requestUrl);

    if (!shouldRedirect) {
      return null;
    }

    const redirectSource = redirects.getRedirect(title);

    if (!redirectSource) {
      log.debug(`There is no redirect source with title: "${title}"`);
      return null;
    }

    return resources.createRedirectFileUrl(redirectSource.file, requestUrl);
  };

  const hasRedirect = title => {
    return !!redirects.getRedirect(title);
  };

  return {
    init,
    hasRedirect,
    createRedirectUrl,
    getBlockingRedirects
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/filters-state.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */



/**
 * Helper class for working with filters metadata storage (local storage)
 */

const filtersState = function () {
  const FILTERS_STATE_PROP = 'filters-state';
  const FILTERS_VERSION_PROP = 'filters-version';
  const GROUPS_STATE_PROP = 'groups-state';
  /**
   * Gets filter version from the local storage
   * @returns {*}
   */

  const getFiltersVersion = function () {
    let filters = Object.create(null);

    try {
      const json = storage_localStorage.getItem(FILTERS_VERSION_PROP);

      if (json) {
        filters = JSON.parse(json);
      }
    } catch (ex) {
      log.error('Error retrieve filters version info, cause {0}', ex);
    }

    return filters;
  };
  /**
   * Gets filters state from the local storage
   * @returns {*}
   */


  const getFiltersState = function () {
    let filters = Object.create(null);

    try {
      const json = storage_localStorage.getItem(FILTERS_STATE_PROP);

      if (json) {
        filters = JSON.parse(json);
      }
    } catch (ex) {
      log.error('Error retrieve filters state info, cause {0}', ex);
    }

    return filters;
  };
  /**
   * Gets groups state from the local storage
   * @returns {any}
   */


  const getGroupsState = function () {
    let groups = Object.create(null);

    try {
      const json = storage_localStorage.getItem(GROUPS_STATE_PROP);

      if (json) {
        groups = JSON.parse(json);
      }
    } catch (e) {
      log.error('Error retrieve groups state info, cause {0}', e);
    }

    return groups;
  };
  /**
   * Updates filter version in the local storage
   *
   * @param filter Filter version metadata
   */


  const updateFilterVersion = function (filter) {
    const filters = getFiltersVersion();
    filters[filter.filterId] = {
      version: filter.version,
      lastCheckTime: filter.lastCheckTime,
      lastUpdateTime: filter.lastUpdateTime,
      expires: filter.expires
    };
    storage_localStorage.setItem(FILTERS_VERSION_PROP, JSON.stringify(filters));
  };
  /**
   * Updates filter state in the local storage
   *
   * @param filter Filter state object
   */


  const updateFilterState = function (filter) {
    const filters = getFiltersState();
    filters[filter.filterId] = {
      loaded: filter.loaded,
      enabled: filter.enabled,
      installed: filter.installed
    };
    storage_localStorage.setItem(FILTERS_STATE_PROP, JSON.stringify(filters));
  };

  const removeFilter = filterId => {
    const filters = getFiltersState();
    delete filters[filterId];
    storage_localStorage.setItem(FILTERS_STATE_PROP, JSON.stringify(filters));
  };
  /**
   * Updates group enable state in the local storage
   *
   * @param group - SubscriptionGroup object
   */


  const updateGroupState = function (group) {
    const groups = getGroupsState();

    if (typeof group.enabled === 'undefined') {
      delete groups[group.groupId].enabled;
    } else {
      groups[group.groupId] = {
        enabled: group.enabled
      };
    }

    storage_localStorage.setItem(GROUPS_STATE_PROP, JSON.stringify(groups));
  }; // Add event listener to persist filter metadata to local storage


  listeners.addListener((event, payload) => {
    switch (event) {
      case listeners.SUCCESS_DOWNLOAD_FILTER:
        updateFilterState(payload);
        updateFilterVersion(payload);
        break;

      case listeners.FILTER_ADD_REMOVE:
      case listeners.FILTER_ENABLE_DISABLE:
        updateFilterState(payload);
        break;

      case listeners.FILTER_GROUP_ENABLE_DISABLE:
        updateGroupState(payload);
        break;

      default:
        break;
    }
  });
  return {
    getFiltersVersion,
    getFiltersState,
    getGroupsState,
    // These methods are used only for migrate from old versions
    updateFilterVersion,
    updateFilterState,
    removeFilter
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/metadata.js
/* eslint-disable max-classes-per-file */

/**
 * Filter metadata
 */
class SubscriptionFilter {
  constructor({
    filterId,
    groupId,
    name,
    description,
    homepage,
    version,
    timeUpdated,
    displayNumber = 0,
    languages = [],
    expires,
    subscriptionUrl,
    tags,
    customUrl,
    trusted,
    checksum
  }) {
    this.filterId = filterId;
    this.groupId = groupId;
    this.name = name;
    this.description = description;
    this.homepage = homepage;
    this.version = version;
    this.timeUpdated = timeUpdated;
    this.displayNumber = displayNumber;
    this.languages = languages;
    this.expires = expires;
    this.subscriptionUrl = subscriptionUrl;
    this.tags = tags; // Custom filters data

    if (typeof customUrl !== 'undefined') {
      this.customUrl = customUrl;
    }

    if (typeof trusted !== 'undefined') {
      this.trusted = trusted;
    }

    if (typeof checksum !== 'undefined') {
      this.checksum = checksum;
    }
  }

}
/**
 * Group metadata
 */

class SubscriptionGroup {
  constructor(groupId, groupName, displayNumber) {
    this.groupId = groupId;
    this.groupName = groupName;
    this.displayNumber = displayNumber;
  }

}
/**
 * Tag metadata
 */

class FilterTag {
  constructor(tagId, keyword) {
    this.tagId = tagId;
    this.keyword = keyword;
  }

}
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/metadata-factory.js

/**
 * Metadata factory
 */

const metadataFactory = (() => {
  /**
   * Parses string to date
   *
   * @param timeUpdatedString String in format 'yyyy-MM-dd'T'HH:mm:ssZ'
   * @returns number from date string
   */
  const parseTimeUpdated = timeUpdatedString => {
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1272
    if (Number.isInteger(timeUpdatedString)) {
      return new Date(timeUpdatedString).getTime();
    } // https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Date/parse


    let timeUpdated = Date.parse(timeUpdatedString);

    if (Number.isNaN(timeUpdated)) {
      // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/478
      timeUpdated = Date.parse(timeUpdatedString.replace(/\+(\d{2})(\d{2})$/, '+$1:$2'));
    }

    if (Number.isNaN(timeUpdated)) {
      timeUpdated = new Date().getTime();
    }

    return timeUpdated;
  };
  /**
   * Create tag from object
   *
   * @param tag Object
   * @returns {FilterTag}
   */


  const createFilterTagFromJSON = tag => {
    const tagId = Number.parseInt(tag.tagId, 10);
    const {
      keyword
    } = tag;
    return new FilterTag(tagId, keyword);
  };
  /**
   * Create group from object
   *
   * @param group Object
   * @returns {SubscriptionGroup}
   */


  const createSubscriptionGroupFromJSON = group => {
    const groupId = Number.parseInt(group.groupId, 10);
    const defaultGroupName = group.groupName;
    const displayNumber = Number.parseInt(group.displayNumber, 10);
    return new SubscriptionGroup(groupId, defaultGroupName, displayNumber);
  };
  /**
   * Create filter from object
   *
   * @param filter Object
   */


  const createSubscriptionFilterFromJSON = filter => {
    const filterId = Number.parseInt(filter.filterId, 10);
    const groupId = Number.parseInt(filter.groupId, 10);
    const timeUpdated = parseTimeUpdated(filter.timeUpdated);
    const expires = Number.parseInt(filter.expires, 10);
    const displayNumber = Number.parseInt(filter.displayNumber, 10);
    const {
      name,
      description,
      homepage,
      version,
      subscriptionUrl,
      languages,
      tags,
      customUrl,
      trusted,
      checksum
    } = filter;

    if (tags.length === 0) {
      tags.push(0);
    }

    return new SubscriptionFilter({
      filterId,
      groupId,
      name,
      description,
      homepage,
      version,
      timeUpdated,
      displayNumber,
      languages,
      expires,
      subscriptionUrl,
      tags,
      customUrl,
      trusted,
      checksum
    });
  };

  return {
    createFilterTagFromJSON,
    createSubscriptionGroupFromJSON,
    createSubscriptionFilterFromJSON
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/metadata-cache.js
/**
 * Cache data for filters, groups and tags
 */
const metadataCache = (() => {
  let tags = [];
  let groups = [];
  let groupsMap = {};
  let filters = [];
  let filtersMap = {};
  /**
   * Returns cache data
   */

  const getData = () => ({
    tags,
    groups,
    groupsMap,
    filters,
    filtersMap
  });
  /**
   * Updates cache data
   */


  const setData = data => {
    tags = data.tags || tags;
    groups = data.groups || groups;
    groupsMap = data.groupsMap || groupsMap;
    filters = data.filters || filters;
    filtersMap = data.filtersMap || filtersMap;
  };
  /**
   * Gets filter metadata by filter identifier
   */


  const getFilter = filterId => filtersMap[filterId];
  /**
   * @returns Array of Filters metadata
   */


  const getFilters = () => filters;
  /**
   * Removes filter metadata by id
   * @param filterId
   */


  const removeFilter = filterId => {
    filters = filters.filter(f => f.filterId !== filterId);
    delete filtersMap[filterId];
  };
  /**
   * Updates filter metadata
   * @param filter
   */


  const updateFilters = filter => {
    removeFilter(filter.filterId);
    filters.push(filter);
    filtersMap[filter.filterId] = filter;
  };
  /**
   * @returns Group metadata
   */


  const getGroup = groupId => groupsMap[groupId];
  /**
   * @returns Array of Groups metadata
   */


  const getGroups = () => groups;
  /**
   * @returns Array of Groups metadata
   */


  const getGroupsMap = () => groupsMap;
  /**
   * @returns Array of Tags metadata
   */


  const getTags = () => tags;

  return {
    getData,
    setData,
    getFilter,
    getFilters,
    removeFilter,
    updateFilters,
    getGroup,
    getGroups,
    getGroupsMap,
    getTags
  };
})();
// EXTERNAL MODULE: ./node_modules/crypto-js/md5.js
var md5 = __webpack_require__(6172);
var md5_default = /*#__PURE__*/__webpack_require__.n(md5);
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/custom-filters.js









/**
 * Custom filters module
 */

const customFilters = (() => {
  /**
   * Amount of lines to parse metadata from filter's header
   * @type {number}
   */
  const AMOUNT_OF_LINES_TO_PARSE = 50;
  /**
   * Storage key for custom filter's data
   * @type {string}
   */

  const CUSTOM_FILTERS_STORAGE_KEY = 'custom_filters';
  /**
   * Parses expires string in meta
   *
   * @param str
   * @return {number}
   */

  const parseExpiresStr = str => {
    const regexp = /(\d+)\s+(day|hour)/;
    const parseRes = str.match(regexp);

    if (!parseRes) {
      const parsed = Number.parseInt(str, 10);
      return Number.isNaN(parsed) ? 0 : parsed;
    }

    const [, num, period] = parseRes;
    let multiplier = 1;

    switch (period) {
      case 'day':
        {
          multiplier = 24 * 60 * 60;
          break;
        }

      case 'hour':
        {
          multiplier = 60 * 60;
          break;
        }

      default:
        {
          break;
        }
    }

    return num * multiplier;
  };
  /**
   * Parses filter metadata from rules header
   *
   * @param rules
   * @returns object
   */


  const parseFilterDataFromHeader = rules => {
    const parseTag = tagName => {
      let result = ''; // Look up no more than 50 first lines

      const maxLines = Math.min(AMOUNT_OF_LINES_TO_PARSE, rules.length);

      for (let i = 0; i < maxLines; i += 1) {
        const rule = rules[i];
        const search = `! ${tagName}: `;
        const indexOfSearch = rule.indexOf(search);

        if (indexOfSearch >= 0) {
          result = rule.substring(indexOfSearch + search.length);
        }
      }

      if (tagName === 'Expires') {
        result = parseExpiresStr(result);
      }

      return result;
    };

    return {
      name: parseTag('Title'),
      description: parseTag('Description'),
      homepage: parseTag('Homepage'),
      version: parseTag('Version'),
      expires: parseTag('Expires'),
      timeUpdated: parseTag('TimeUpdated')
    };
  };
  /**
   * Gets new filter id for custom filter
   * @return {number}
   */


  const addCustomFilterId = () => {
    let max = 0;
    const filters = metadataCache.getFilters();
    filters.forEach(f => {
      if (f.filterId > max) {
        max = f.filterId;
      }
    });
    return max >= CUSTOM_FILTERS_START_ID ? max + 1 : CUSTOM_FILTERS_START_ID;
  };
  /**
   * Loads custom filters from storage
   *
   * @returns {Array}
   */


  const loadCustomFilters = () => {
    const customFilters = storage_localStorage.getItem(CUSTOM_FILTERS_STORAGE_KEY);
    return customFilters ? JSON.parse(customFilters) : [];
  };
  /**
   * Saves custom filter to storage or updates it if filter with same id was found
   *
   * @param filter
   */


  const saveCustomFilterInStorage = filter => {
    const customFilters = loadCustomFilters();
    const updatedCustomFilters = customFilters.filter(f => f.filterId !== filter.filterId);
    updatedCustomFilters.push(filter);
    storage_localStorage.setItem(CUSTOM_FILTERS_STORAGE_KEY, JSON.stringify(updatedCustomFilters));
  };
  /**
   * Remove custom filter data from storage
   *
   * @param filter
   */


  const removeCustomFilterFromStorage = filter => {
    const customFilters = loadCustomFilters();
    const updatedCustomFilters = customFilters.filter(f => {
      if (f.filterId === filter.filterId) {
        return filter.installed;
      }

      return true;
    });
    storage_localStorage.setItem(CUSTOM_FILTERS_STORAGE_KEY, JSON.stringify(updatedCustomFilters));
  };
  /**
   * Compares filter version or filter checksum
   * @param newVersion
   * @param newChecksum
   * @param oldFilter
   * @returns Boolean
   */


  const isFilterUpdated = (newVersion, newChecksum, oldFilter) => {
    if (browserUtils.isSemver(oldFilter.version) && browserUtils.isSemver(newVersion)) {
      return !browserUtils.isGreaterOrEqualsVersion(oldFilter.version, newVersion);
    }

    if (!oldFilter.checksum) {
      return true;
    }

    return newChecksum !== oldFilter.checksum;
  };
  /**
   * Count md5 checksum for the filter content
   * @param {Array<String>} rules
   * @returns {String} checksum string
   */


  const getChecksum = rules => {
    const rulesText = rules.join('\n');
    return md5_default()(rulesText).toString();
  };
  /**
   * Updates filter checksum and version in the storage and internal structures
   * @param filter
   * @param {object} info
   */


  const updateCustomFilterInfo = (filter, info) => {
    const {
      checksum,
      version,
      timeUpdated,
      lastCheckTime,
      expires
    } = info;
    filter.checksum = checksum || filter.checksum;
    filter.version = version || filter.version;
    filter.timeUpdated = timeUpdated || filter.timeUpdated;
    filter.lastCheckTime = lastCheckTime || filter.lastCheckTime;
    filter.expires = expires || filter.expires;

    if ('enabled' in info) {
      filter.enabled = info.enabled;
    }

    metadataCache.updateFilters(filter);
    saveCustomFilterInStorage(filter);
  };
  /**
   * Safe download rules from subscription url
   *
   * @param url
   * @return {Promise<null|*>}
   */


  const downloadRules = async url => {
    let rules;

    try {
      rules = await backend.downloadFilterRulesBySubscriptionUrl(url);
      return rules;
    } catch (e) {
      log.error(`Error download filter by url ${url}, cause: ${e || ''}`);
      return null;
    }
  };
  /**
   * Limits filter download with timeout
   * @param url
   */


  const downloadRulesWithTimeout = async url => {
    const DOWNLOAD_LIMIT_MS = 3 * 1000;
    return Promise.race([downloadRules(url), new Promise((_, reject) => {
      setTimeout(() => reject(new Error('Fetch timeout is over')), DOWNLOAD_LIMIT_MS);
    })]);
  };
  /**
   * Adds or updates custom filter
   *
   * @param url subscriptionUrl
   * @param options
   */


  const updateCustomFilter = async (url, options) => {
    const {
      title,
      trusted,
      enabled
    } = options;
    const rules = await downloadRulesWithTimeout(url);

    if (!rules) {
      return null;
    }

    const parsedData = parseFilterDataFromHeader(rules);
    const {
      description,
      homepage,
      version,
      expires,
      timeUpdated = new Date().toISOString()
    } = parsedData;
    const checksum = !version || !browserUtils.isSemver(version) ? getChecksum(rules) : null; // Check if filter from this url was added before

    let filter = metadataCache.getFilters().find(f => f.customUrl === url);

    if (filter) {
      if (!isFilterUpdated(version, checksum, filter)) {
        updateCustomFilterInfo(filter, {
          lastCheckTime: Date.now()
        });
        return null;
      }

      updateCustomFilterInfo(filter, {
        version,
        checksum,
        timeUpdated,
        expires,
        lastCheckTime: Date.now()
      });
    } else {
      filter = new SubscriptionFilter({
        filterId: addCustomFilterId(),
        groupId: ANTIBANNER_GROUPS_ID.CUSTOM_FILTERS_GROUP_ID,
        name: title,
        description,
        homepage,
        version,
        timeUpdated,
        expires,
        subscriptionUrl: url,
        tags: [0],
        customUrl: url,
        checksum,
        trusted
      });
      filter.lastCheckTime = Date.now();
      filter.loaded = true;
      filter.enabled = enabled === true;
      metadataCache.updateFilters(filter);
      saveCustomFilterInStorage(filter);
    }

    listeners.notifyListeners(listeners.SUCCESS_DOWNLOAD_FILTER, filter);
    listeners.notifyListeners(listeners.UPDATE_FILTER_RULES, filter, rules);
    return filter.filterId;
  };
  /**
   * Retrieves custom filter information
   * @param url
   * @param options
   * @returns {Promise<{filter: SubscriptionFilter}|{}|{error: *}>}
   */


  const getCustomFilterInfo = async (url, options) => {
    // Check if filter from this url was added before
    if (metadataCache.getFilters().find(f => f.customUrl === url)) {
      return {
        errorAlreadyExists: true
      };
    }

    const rules = await downloadRules(url);

    if (!rules) {
      return {};
    }

    const parsedData = parseFilterDataFromHeader(rules);
    const {
      name = options.title,
      description,
      homepage,
      version,
      expires,
      timeUpdated = new Date().toISOString()
    } = parsedData;
    const filter = new SubscriptionFilter({
      groupId: ANTIBANNER_GROUPS_ID.CUSTOM_FILTERS_GROUP_ID,
      name,
      description,
      homepage,
      version,
      timeUpdated,
      expires,
      subscriptionUrl: url,
      tags: [0],
      customUrl: url
    });
    filter.loaded = true;
    filter.rulesCount = rules.filter(rule => rule.trim().indexOf('!') !== 0).length;
    return {
      filter
    };
  };
  /**
   * Removes filter
   *
   * @param filter
   */


  const removeCustomFilter = filter => {
    if (filter && filter.filterId) {
      metadataCache.removeFilter(filter.filterId);
    }
  };
  /**
   * Returns custom filters
   *
   * @returns Array
   */


  const getCustomFilters = function () {
    return metadataCache.getFilters().filter(f => f.customUrl);
  }; // Add event listener to persist filter metadata to local storage


  listeners.addListener((event, payload) => {
    if (event === listeners.FILTER_ADD_REMOVE) {
      if (payload && payload.removed) {
        removeCustomFilter(payload);
        removeCustomFilterFromStorage(payload);
      }
    }
  });
  return {
    getCustomFilters,
    loadCustomFilters,
    updateCustomFilter,
    getCustomFilterInfo,
    CUSTOM_FILTERS_START_ID: CUSTOM_FILTERS_START_ID,
    CUSTOM_FILTERS_GROUP_DISPLAY_NUMBER: CUSTOM_FILTERS_GROUP_DISPLAY_NUMBER
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/subscription.js

















/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */















/**
 * Service that loads and parses filters metadata from backend server.
 * For now we just store filters metadata in an XML file within the extension.
 * In future we'll add an opportunity to update metadata along with filter rules update.
 */

const subscriptions = (() => {
  /**
   * Storage keys for metadata objects
   * @type {string}
   */
  const METADATA_STORAGE_KEY = 'filters-metadata';
  const I18N_METADATA_STORAGE_KEY = 'filters-i18n-metadata';
  /**
   * Updates filters version and state info.
   * Loads this data from the storage and then updates adguard.subscription.filters property
   *
   * @private
   */

  const loadFiltersVersionAndStateInfo = () => {
    // Load filters metadata from the storage
    const filtersVersionInfo = filtersState.getFiltersVersion(); // Load filters state from the storage

    const filtersStateInfo = filtersState.getFiltersState();
    const filters = metadataCache.getFilters();

    for (let i = 0; i < filters.length; i += 1) {
      const filter = filters[i];
      const {
        filterId
      } = filter;
      const versionInfo = filtersVersionInfo[filterId];
      const stateInfo = filtersStateInfo[filterId];

      if (versionInfo) {
        filter.version = versionInfo.version;
        filter.lastCheckTime = versionInfo.lastCheckTime;
        filter.lastUpdateTime = versionInfo.lastUpdateTime;

        if (versionInfo.expires) {
          filter.expires = versionInfo.expires;
        }
      }

      if (stateInfo) {
        filter.enabled = stateInfo.enabled;
        filter.installed = stateInfo.installed;
        filter.loaded = stateInfo.loaded;
      }

      metadataCache.updateFilters(filter);
    }
  };
  /**
   * Updates groups state info
   * Loads state info from the storage and then updates adguard.subscription.groups properly
   * @private
   */


  const loadGroupsStateInfo = () => {
    // Load filters state from the storage
    const groupsStateInfo = filtersState.getGroupsState();
    const groups = metadataCache.getGroups();

    for (let i = 0; i < groups.length; i += 1) {
      const group = groups[i];
      const {
        groupId
      } = group;
      const stateInfo = groupsStateInfo[groupId];

      if (stateInfo) {
        group.enabled = stateInfo.enabled;
        metadataCache.getGroup(group);
      }
    }
  };
  /**
   * Refreshes subscription's objects with metadata
   * @param metadata
   */


  const saveMetadata = metadata => {
    const tags = [];
    const groups = [];
    const groupsMap = {};
    const filters = [];
    const filtersMap = {};

    for (let i = 0; i < metadata.tags.length; i += 1) {
      tags.push(metadataFactory.createFilterTagFromJSON(metadata.tags[i]));
    }

    for (let j = 0; j < metadata.filters.length; j += 1) {
      const filter = metadataFactory.createSubscriptionFilterFromJSON(metadata.filters[j]);
      filters.push(filter);
      filtersMap[filter.filterId] = filter;
    }

    for (let k = 0; k < metadata.groups.length; k += 1) {
      const group = metadataFactory.createSubscriptionGroupFromJSON(metadata.groups[k]);
      groups.push(group);
      groupsMap[group.groupId] = group;
    }

    const customFiltersGroup = new SubscriptionGroup(ANTIBANNER_GROUPS_ID.CUSTOM_FILTERS_GROUP_ID, translator.getMessage('options_antibanner_custom_group'), customFilters.CUSTOM_FILTERS_GROUP_DISPLAY_NUMBER);
    groups.push(customFiltersGroup);
    groupsMap[customFiltersGroup.groupId] = customFiltersGroup; // Load custom filters

    const customFiltersList = customFilters.loadCustomFilters();
    customFiltersList.forEach(f => {
      const customFilter = metadataFactory.createSubscriptionFilterFromJSON(f);
      filters.push(customFilter);
      filtersMap[customFilter.filterId] = customFilter;
    });
    filters.sort((f1, f2) => f1.displayNumber - f2.displayNumber);
    groups.sort((f1, f2) => f1.displayNumber - f2.displayNumber);
    metadataCache.setData({
      tags,
      groups,
      groupsMap,
      filters,
      filtersMap
    });
  };
  /**
   * Load groups and filters metadata
   * @returns {Promise} returns promise
   */


  const loadMetadata = async () => {
    let metadata; // Load from storage first

    const data = storage_localStorage.getItem(METADATA_STORAGE_KEY);

    if (data) {
      metadata = JSON.parse(data);
    } else {
      metadata = await backend.getLocalFiltersMetadata();
    }

    saveMetadata(metadata);
    log.info('Filters metadata loaded');
  };
  /**
   * Reloads groups and filters metadata from backend
   * @returns {Promise} returns promise
   */


  const reloadMetadataFromBackend = async () => {
    const metadata = await backend.downloadMetadataFromBackend();
    storage_localStorage.setItem(METADATA_STORAGE_KEY, JSON.stringify(metadata));
    saveMetadata(metadata);
    loadFiltersVersionAndStateInfo();
    loadGroupsStateInfo();
    log.info('Filters metadata reloaded from backend');
  };
  /**
   * Load metadata of the specified filters
   *
   * @param filterIds         Filters identifiers
   */


  const getFiltersMetadata = async filterIds => {
    if (!filterIds || filterIds.length === 0) {
      return [];
    }

    const metadata = await backend.downloadMetadataFromBackend();
    const filterMetadataList = [];

    for (let i = 0; i < filterIds.length; i += 1) {
      const filter = utils.collections.find(metadata.filters, 'filterId', filterIds[i]);

      if (filter) {
        filterMetadataList.push(metadataFactory.createSubscriptionFilterFromJSON(filter));
      }
    }

    return filterMetadataList;
  };
  /**
   * Localize tag
   * @param tag
   * @param i18nMetadata
   * @private
   */


  const applyFilterTagLocalization = (tag, i18nMetadata) => {
    const {
      tagId
    } = tag;
    const localizations = i18nMetadata[tagId];

    if (localizations) {
      const locale = utils.i18n.normalize(localizations, backgroundPage.app.getLocale());
      const localization = localizations[locale];

      if (localization) {
        tag.name = localization.name;
        tag.description = localization.description;
      }
    }
  };
  /**
   * Localize filter
   * @param filter
   * @param i18nMetadata
   * @private
   */


  const applyFilterLocalization = (filter, i18nMetadata) => {
    const {
      filterId
    } = filter;
    const localizations = i18nMetadata[filterId];

    if (localizations) {
      const locale = utils.i18n.normalize(localizations, backgroundPage.app.getLocale());
      const localization = localizations[locale];

      if (localization) {
        filter.name = localization.name;
        filter.description = localization.description;
      }
    }
  };
  /**
   * Localize group
   * @param group
   * @param i18nMetadata
   * @private
   */


  const applyGroupLocalization = (group, i18nMetadata) => {
    const {
      groupId
    } = group;
    const localizations = i18nMetadata[groupId];

    if (localizations) {
      const locale = utils.i18n.normalize(localizations, backgroundPage.app.getLocale());
      const localization = localizations[locale];

      if (localization) {
        group.groupName = localization.name;
      }
    }
  };
  /**
   * Refreshes subscription's objects with i18n metadata
   * @param i18nMetadata
   */


  const saveI18nMetadata = i18nMetadata => {
    const tagsI18n = i18nMetadata.tags;
    const filtersI18n = i18nMetadata.filters;
    const groupsI18n = i18nMetadata.groups;
    const {
      tags,
      groups,
      filters
    } = metadataCache.getData();

    for (let i = 0; i < tags.length; i += 1) {
      applyFilterTagLocalization(tags[i], tagsI18n);
    }

    for (let j = 0; j < filters.length; j += 1) {
      applyFilterLocalization(filters[j], filtersI18n);
    }

    for (let k = 0; k < groups.length; k += 1) {
      applyGroupLocalization(groups[k], groupsI18n);
    }

    metadataCache.setData({
      tags,
      groups,
      filters
    });
  };
  /**
   * Loads groups and filters localizations
   * @return {Promise} returns promise
   */


  const loadMetadataI18n = async () => {
    log.info('Loading filters i18n metadata..');
    let metadata; // Load from storage first

    const data = storage_localStorage.getItem(I18N_METADATA_STORAGE_KEY);

    if (data) {
      metadata = JSON.parse(data);
    } else {
      metadata = await backend.getLocalFiltersI18Metadata();
    }

    saveI18nMetadata(metadata);
    log.info('Filters i18n metadata loaded');
  };
  /**
   * Reloads i18n metadata localizations from backend
   * @returns {Promise} returns promise
   */


  const reloadI18nMetadataFromBackend = async () => {
    const metadata = await backend.downloadI18nMetadataFromBackend();
    storage_localStorage.setItem(I18N_METADATA_STORAGE_KEY, JSON.stringify(metadata));
    saveI18nMetadata(metadata);
    log.info('Filters i18n metadata reloaded from backend');
  };
  /**
   * Loads script rules from local file
   * @returns {Promise}
   * @private
   */


  const loadLocalScriptRules = async () => {
    if (browserUtils.isFirefoxBrowser()) {
      const json = await backend.getLocalScriptRules();
      local_script_rules_chrome.setLocalScriptRules(json);
      log.info('Filters local script rules loaded');
    }
  };
  /**
   * Loads redirect sources from local file
   * @returns {Promise}
   * @private
   */


  const loadRedirectSources = async () => {
    const txt = await backend.getRedirectSources();
    redirectService.init(txt);
    log.info('Filters redirect sources loaded');
  };
  /**
   * Initialize subscription service, loading local filters metadata
   * @return {Promise}
   */


  const init = async function () {
    try {
      await loadMetadata();
      await loadMetadataI18n();
      await loadLocalScriptRules();
      await loadRedirectSources();
    } catch (e) {
      log.error(`Error loading metadata, cause: ${e.message}`);
    }
  };
  /**
   * @returns Array of Filters metadata
   */


  const getFilters = function () {
    return metadataCache.getFilters();
  };
  /**
   * Gets filter metadata by filter identifier
   */


  const getFilter = function (filterId) {
    return metadataCache.getFilter(filterId);
  };

  const isTrustedFilter = filterId => {
    if (filterId < customFilters.CUSTOM_FILTERS_START_ID) {
      return true;
    }

    const filter = metadataCache.getFilter(filterId);
    return !!(filter && filter.trusted && filter.trusted === true);
  };
  /**
   * @returns Array of Tags metadata
   */


  const getTags = function () {
    return metadataCache.getTags();
  };
  /**
   * @returns Array of Groups metadata
   */


  const getGroups = () => metadataCache.getGroups();
  /**
   * @returns Group metadata
   */


  const getGroup = groupId => metadataCache.getGroup(groupId);
  /**
   * Checks if group has enabled status true or false
   * @param groupId
   * @returns {boolean}
   */


  const groupHasEnabledStatus = groupId => {
    const group = metadataCache.getGroup(groupId);
    return typeof group.enabled !== 'undefined';
  };
  /**
   * Gets list of filters for the specified languages
   *
   * @param locale Locale to check
   * @returns {Array} List of filters identifiers
   */


  const getFilterIdsForLanguage = function (locale) {
    if (!locale) {
      return [];
    }

    const filters = metadataCache.getFilters();
    const filterIds = [];

    for (let i = 0; i < filters.length; i += 1) {
      const filter = filters[i];
      const {
        languages
      } = filter;

      if (languages && languages.length > 0) {
        const language = utils.i18n.normalize(languages, locale);

        if (language) {
          filterIds.push(filter.filterId);
        }
      }
    }

    return filterIds;
  };
  /**
   * @return list of filters
   */


  const getLangSuitableFilters = () => {
    // Get language-specific filters by user locale
    let filterIds = [];
    let localeFilterIds = getFilterIdsForLanguage(backgroundPage.app.getLocale());
    filterIds = filterIds.concat(localeFilterIds); // Get language-specific filters by navigator languages
    // Get all used languages

    const languages = browserUtils.getNavigatorLanguages();

    for (let i = 0; i < languages.length; i += 1) {
      localeFilterIds = getFilterIdsForLanguage(languages[i]);
      filterIds = filterIds.concat(localeFilterIds);
    }

    return [...new Set(filterIds)];
  };

  return {
    init,
    reloadMetadataFromBackend,
    reloadI18nMetadataFromBackend,
    loadFiltersVersionAndStateInfo,
    loadGroupsStateInfo,
    getFiltersMetadata,
    getFilterIdsForLanguage,
    getLangSuitableFilters,
    getTags,
    getGroups,
    getGroup,
    getFilters,
    getFilter,
    isTrustedFilter,
    groupHasEnabledStatus
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/page-stats.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







/**
 * Global stats
 */

const pageStats = function () {
  const MAX_HOURS_HISTORY = 24;
  const MAX_DAYS_HISTORY = 30;
  const MAX_MONTHS_HISTORY = 3;
  const TOTAL_GROUP = {
    groupId: 'total',
    groupName: translator.getMessage('popup_statistics_total')
  };
  const pageStatisticProperty = 'page-statistic';
  const pageStatsHolder = {
    /**
     * Getter for total page stats (gets it from local storage)
     *
     * @returns {*}
     * @private
     */
    get stats() {
      return lazyGet(pageStatsHolder, 'stats', () => {
        let stats;

        try {
          const json = storage_localStorage.getItem(pageStatisticProperty);

          if (json) {
            stats = JSON.parse(json);
          }
        } catch (ex) {
          log.error('Error retrieve page statistic from storage, cause {0}', ex);
        }

        return stats || Object.create(null);
      });
    },

    save: utils.concurrent.throttle(function () {
      storage_localStorage.setItem(pageStatisticProperty, JSON.stringify(this.stats));
    }, prefs.statsSaveInterval),

    clear() {
      storage_localStorage.removeItem(pageStatisticProperty);
      lazyGetClear(pageStatsHolder, 'stats');
    }

  };
  /**
   * Total count of blocked requests
   *
   * @returns {Number} Count of blocked requests
   */

  const getTotalBlocked = function () {
    const {
      stats
    } = pageStatsHolder;

    if (!stats) {
      return 0;
    }

    return stats.totalBlocked || 0;
  };
  /**
   * Updates total count of blocked requests
   *
   * @param blocked Count of blocked requests
   */


  const updateTotalBlocked = function (blocked) {
    const {
      stats
    } = pageStatsHolder;
    stats.totalBlocked = (stats.totalBlocked || 0) + blocked;
    pageStatsHolder.save();
  };
  /**
   * Resets tab stats
   */


  const resetStats = function () {
    pageStatsHolder.clear();
  };
  /**
   * Object used to cache bindings between filters and groups
   * @type {{filterId: {groupId: Number, groupName: String, displayNumber: Number}}}
   */


  const blockedGroupsFilters = {}; // TODO check why not all filter stats appear here, for example cosmetic filters

  /**
   * Returns blocked group by filter id
   *
   * @param {number} filterId
   * @returns
   */

  const getBlockedGroupByFilterId = function (filterId) {
    let blockedGroup = blockedGroupsFilters[filterId];

    if (blockedGroup !== undefined) {
      return blockedGroup;
    }

    const filter = subscriptions.getFilter(filterId);

    if (!filter) {
      return undefined;
    }

    const group = subscriptions.getGroup(filter.groupId);

    if (!group) {
      return undefined;
    }

    const {
      groupId,
      groupName,
      displayNumber
    } = group;
    blockedGroup = {
      groupId,
      groupName,
      displayNumber
    };
    blockedGroupsFilters[filter.filterId] = blockedGroup;
    return blockedGroup;
  };

  const createStatsDataItem = function (type, blocked) {
    const result = {};

    if (type) {
      result[type] = blocked;
    }

    result[TOTAL_GROUP.groupId] = blocked;
    return result;
  };
  /**
   * Blocked types to filters relation dictionary
   */


  const createStatsData = function (now, type, blocked) {
    const result = Object.create(null);
    result.hours = [];
    result.days = [];
    result.months = [];

    for (let i = 1; i < MAX_HOURS_HISTORY; i += 1) {
      result.hours.push(createStatsDataItem(null, 0));
    }

    result.hours.push(createStatsDataItem(type, blocked));

    for (let j = 1; j < MAX_DAYS_HISTORY; j += 1) {
      result.days.push(createStatsDataItem(null, 0));
    }

    result.days.push(createStatsDataItem(type, blocked));

    for (let k = 1; k < MAX_MONTHS_HISTORY; k += 1) {
      result.months.push(createStatsDataItem(null, 0));
    }

    result.months.push(createStatsDataItem(type, blocked));
    result.updated = now.getTime();
    return result;
  };

  const updateStatsDataItem = function (type, blocked, current) {
    current[type] = (current[type] || 0) + blocked;
    current[TOTAL_GROUP.groupId] = (current[TOTAL_GROUP.groupId] || 0) + blocked;
    return current;
  };

  const updateStatsData = function (now, type, blocked, current) {
    const currentDate = new Date(current.updated);
    const result = current;

    if (utils.dates.isSameHour(now, currentDate) && result.hours.length > 0) {
      result.hours[result.hours.length - 1] = updateStatsDataItem(type, blocked, result.hours[result.hours.length - 1]);
    } else {
      let diffHours = utils.dates.getDifferenceInHours(now, currentDate);

      while (diffHours >= 2) {
        result.hours.push(createStatsDataItem(null, 0));
        diffHours -= 1;
      }

      result.hours.push(createStatsDataItem(type, blocked));

      if (result.hours.length > MAX_HOURS_HISTORY) {
        result.hours = result.hours.slice(-MAX_HOURS_HISTORY);
      }
    }

    if (utils.dates.isSameDay(now, currentDate) && result.days.length > 0) {
      result.days[result.days.length - 1] = updateStatsDataItem(type, blocked, result.days[result.days.length - 1]);
    } else {
      let diffDays = utils.dates.getDifferenceInDays(now, currentDate);

      while (diffDays >= 2) {
        result.days.push(createStatsDataItem(null, 0));
        diffDays -= 1;
      }

      result.days.push(createStatsDataItem(type, blocked));

      if (result.days.length > MAX_DAYS_HISTORY) {
        result.days = result.days.slice(-MAX_DAYS_HISTORY);
      }
    }

    if (utils.dates.isSameMonth(now, currentDate) && result.months.length > 0) {
      result.months[result.months.length - 1] = updateStatsDataItem(type, blocked, result.months[result.months.length - 1]);
    } else {
      let diffMonths = utils.dates.getDifferenceInMonths(now, currentDate);

      while (diffMonths >= 2) {
        result.months.push(createStatsDataItem(null, 0));
        diffMonths -= 1;
      }

      result.months.push(createStatsDataItem(type, blocked));
    }

    result.updated = now.getTime();
    return result;
  };
  /**
   * Updates stats data
   *
   * For every hour/day/month we have an object:
   * {
   *      blockedType: count,
   *      ..,
   *
   *      total: count
   * }
   *
   * We store last 24 hours, 30 days and all past months stats
   *
   * var data = {
   *              hours: [],
   *              days: [],
   *              months: [],
   *              updated: Date };
   *
   * @param filterId
   * @param blocked count
   * @param now date
   */


  const updateStats = function (filterId, blocked, now) {
    const blockedGroup = getBlockedGroupByFilterId(filterId);

    if (blockedGroup === undefined) {
      return;
    }

    const {
      groupId
    } = blockedGroup;
    const {
      stats
    } = pageStatsHolder;
    let updated;

    if (!stats.data) {
      updated = createStatsData(now, groupId, blocked);
    } else {
      updated = updateStatsData(now, groupId, blocked, stats.data);
    }

    pageStatsHolder.stats.data = updated;
    pageStatsHolder.save();
  };

  const getBlockedGroups = () => {
    const groups = subscriptions.getGroups().map(group => {
      return {
        groupId: group.groupId,
        groupName: group.groupName,
        displayNumber: group.displayNumber
      };
    });
    return [TOTAL_GROUP, ...groups.sort((prevGroup, nextGroup) => {
      return prevGroup.displayNumber - nextGroup.displayNumber;
    })];
  };
  /**
   * Returns statistics data object
   * @param {Date} [date] - used in the tests to provide time of stats object creation
   */


  const getStatisticsData = (date = new Date()) => {
    let {
      stats
    } = pageStatsHolder;

    if (!stats) {
      stats = {};
    }

    if (!stats.data) {
      stats.data = createStatsData(date, null, 0);
      pageStatsHolder.stats.data = stats.data;
      pageStatsHolder.save();
    }

    return {
      today: stats.data.hours,
      lastWeek: stats.data.days.slice(-7),
      lastMonth: stats.data.days,
      lastYear: stats.data.months.slice(-12),
      overall: stats.data.months,
      blockedGroups: getBlockedGroups()
    };
  };

  return {
    resetStats,
    updateTotalBlocked,
    updateStats,
    getTotalBlocked,
    getStatisticsData
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filtering-api.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 * Api for filtering and elements hiding.
 *
 * TODO: Delete this service
 */

const filteringApi = function () {
  function getRequestFilter() {
    return antiBannerService.getRequestFilter();
  }
  /**
   * @returns boolean true when request filter was initialized first time
   */


  const isReady = function () {
    return engine.isReady();
  };
  /**
   * When browser just started we need some time on request filter initialization.
   * This could be a problem in case when browser has a homepage and it is just started.
   * In this case request filter is not yet initalized so we don't block requests and inject css.
   * To fix this, content script will repeat requests for selectors until request filter is ready
   * and it will also collapse all elements which should have been blocked.
   *
   * @returns boolean true if we should collapse elements with content script
   */


  const shouldCollapseAllElements = function () {
    // We assume that if content script is requesting CSS in first 5 seconds after request filter init,
    // then it is possible, that we've missed some elements and now we should collapse these elements
    const requestFilterInitTime = antiBannerService.getRequestFilterInitTime();
    return requestFilterInitTime > 0 && requestFilterInitTime + 5000 > new Date().getTime();
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const findRuleForRequest = function (matchQuery) {
    return getRequestFilter().findRuleForRequest(matchQuery);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const findAllowlistRule = function (matchQuery) {
    return getRequestFilter().findAllowlistRule(matchQuery);
  };

  const findDocumentRule = function (documentUrl) {
    return getRequestFilter().findDocumentRule(documentUrl);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const findStealthAllowlistRule = function (matchQuery) {
    return getRequestFilter().findStealthAllowlistRule(matchQuery);
  };

  const getSelectorsForUrl = function (documentUrl, cosmeticOptions, traditionalCss, extCss) {
    return getRequestFilter().getSelectorsForUrl(documentUrl, cosmeticOptions, !traditionalCss, !extCss);
  };

  const getScriptsStringForUrl = function (documentUrl, tab, cosmeticOptions) {
    return getRequestFilter().getScriptsStringForUrl(documentUrl, tab, cosmeticOptions);
  };

  const getContentRulesForUrl = function (documentUrl) {
    return getRequestFilter().getContentRulesForUrl(documentUrl);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getCspRules = function (matchQuery) {
    return getRequestFilter().findCspRules(matchQuery);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getCookieRules = function (matchQuery) {
    return getRequestFilter().findCookieRules(matchQuery);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getReplaceRules = function (matchQuery) {
    return getRequestFilter().findReplaceRules(matchQuery);
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getCosmeticOption = function (matchQuery) {
    return getRequestFilter().getMatchingResult(matchQuery).getCosmeticOption();
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getRemoveParamRules = function (matchQuery) {
    return getRequestFilter().getMatchingResult(matchQuery).getRemoveParamRules();
  };
  /**
   * @param {MatchQuery} matchQuery - {@link MatchQuery}
   */


  const getRemoveHeaderRules = function (matchQuery) {
    return getRequestFilter().getMatchingResult(matchQuery).getRemoveHeaderRules();
  };

  const getRequestFilterInfo = function () {
    return antiBannerService.getRequestFilterInfo();
  };

  return {
    isReady,
    shouldCollapseAllElements,
    findRuleForRequest,
    findAllowlistRule,
    findDocumentRule,
    getSelectorsForUrl,
    getScriptsStringForUrl,
    getContentRulesForUrl,
    getCspRules,
    getCookieRules,
    getReplaceRules,
    getRemoveParamRules,
    getRemoveHeaderRules,
    findStealthAllowlistRule,
    getCosmeticOption,
    getRequestFilterInfo
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/tabs/frames.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */









/**
 * Object that contains info about every browser tab.
 */

const frames_frames = function () {
  /**
   * Adds frame to map. This method is called on first document request.
   * If this is a main frame - saves this info in frame data.
   *
   * @param tab       Tab object
   * @param frameId   Frame ID
   * @param url       Page URL
   * @param type      Request content type (UrlFilterRule.contentTypes)
   * @returns Frame data
   */
  const recordFrame = function (tab, frameId, url, type) {
    const frame = tabsApi.getTabFrame(tab.tabId, frameId);
    let previousUrl = '';

    if (type === RequestTypes.DOCUMENT) {
      tabsApi.clearTabFrames(tab.tabId);
      tabsApi.clearTabMetadata(tab.tabId);

      if (frame) {
        previousUrl = frame.url;
      }
    }

    tabsApi.recordTabFrame(tab.tabId, frameId, url, utils.url.getDomainName(url));

    if (type === RequestTypes.DOCUMENT) {
      tabsApi.updateTabMetadata(tab.tabId, {
        previousUrl
      });
      reloadFrameData(tab);
    }
  };
  /**
   * This method reloads frame data and updates previous url if necessary
   * We use it in the webRequest.onCommit event because when website uses service worker
   * main_frame request can not fire in the webRequest events
   * @param tab
   * @param frameId
   * @param url
   * @param type
   */


  const checkAndRecordMainFrame = (tab, frameId, url, type) => {
    if (type !== RequestTypes.DOCUMENT) {
      return;
    }

    const {
      tabId
    } = tab;
    const frame = tabsApi.getTabFrame(tabId, frameId); // If no main_frame in tab, than we consider this as a new page load

    if (!frame) {
      tabsApi.recordTabFrame(tabId, frameId, url, utils.url.getDomainName(url));
      reloadFrameData(tab);
      return;
    } // if frame has different rule, then we consider this as a new page load


    let previousUrl = '';

    if (frame && frame.url !== url) {
      previousUrl = frame.url;
      tabsApi.clearTabFrames(tabId);
      tabsApi.clearTabMetadata(tabId);
      tabsApi.recordTabFrame(tabId, frameId, url, utils.url.getDomainName(url));
      tabsApi.updateTabMetadata(tabId, {
        previousUrl
      });
      reloadFrameData(tab);
    }
  };
  /**
   * Gets frame URL
   *
   * @param tab       Tab
   * @param frameId   Frame ID
   * @returns Frame URL
   */


  const getFrameUrl = function (tab, frameId) {
    const frame = tabsApi.getTabFrame(tab.tabId, frameId);
    return frame ? frame.url : null;
  };
  /**
   * Gets main frame URL
   *
   * @param tab    Tab
   * @returns Frame URL
   */


  const getMainFrameUrl = function (tab) {
    return getFrameUrl(tab, MAIN_FRAME_ID);
  };
  /**
   * Gets frame Domain
   *
   * @param tab       Tab
   * @returns Frame Domain
   */


  const getFrameDomain = function (tab) {
    const frame = tabsApi.getTabFrame(tab.tabId, 0);
    return frame ? frame.domainName : null;
  };
  /**
   * @param tab Tab
   * @returns true if Tab have allowlist rule
   */


  const isTabAllowlisted = function (tab) {
    const frameRule = tabsApi.getTabMetadata(tab.tabId, 'frameRule');
    return frameRule && frameRule.isDocumentAllowlistRule();
  };
  /**
   * @param tab Tab
   * @returns true if Tab have allowlist rule and allowlist isn't invert
   */


  const isTabAllowlistedForSafebrowsing = function (tab) {
    return isTabAllowlisted(tab) && allowlist.isDefaultMode();
  };
  /**
   * @param tab Tab
   * @returns true if protection is paused
   */


  const isTabProtectionDisabled = function (tab) {
    return tabsApi.getTabMetadata(tab.tabId, 'applicationFilteringDisabled');
  };
  /**
   * Returns true if tab is in allowlist
   *
   * @param tab Tab
   * @returns true if Adguard for Windows/Android/Mac is detected and tab in allowlist
   */


  const isTabAdguardAllowlisted = function (tab) {
    return tabsApi.getTabMetadata(tab.tabId, 'adguardDocumentAllowlisted');
  };
  /**
   * @param tab   Tab
   * @returns Adguard allowlist rule in user filter associated with this tab
   */


  const getTabAdguardUserAllowlistRule = function (tab) {
    const adguardUserAllowlisted = tabsApi.getTabMetadata(tab.tabId, 'adguardUserAllowlisted');

    if (adguardUserAllowlisted) {
      return tabsApi.getTabMetadata(tab.tabId, 'adguardAllowlistRule');
    }

    return null;
  };
  /**
   * Gets allowlist rule for the specified tab
   * @param tab Tab to check
   * @returns allowlist rule applied to that tab (if any)
   */


  const getFrameRule = function (tab) {
    return tabsApi.getTabMetadata(tab.tabId, 'frameRule');
  };
  /**
   * Reloads tab data (checks allowlist and filtering status)
   *
   * @param tab Tab to reload
   */


  const reloadFrameData = function (tab) {
    const frame = tabsApi.getTabFrame(tab.tabId, 0);

    if (frame) {
      const applicationFilteringDisabled = settings.isFilteringDisabled();
      let frameRule = null;

      if (!applicationFilteringDisabled) {
        const {
          url
        } = frame;
        frameRule = allowlist.findAllowlistRule(url);

        if (!frameRule) {
          frameRule = filteringApi.findDocumentRule(url);
        }
      }

      tabsApi.updateTabMetadata(tab.tabId, {
        frameRule,
        applicationFilteringDisabled
      });
    }
  };
  /**
   * Attach referrer url to the tab's main frame object.
   * This referrer is then used on safebrowsing "Access Denied" for proper "Go Back" behavior.
   *
   * @param tab Tab
   * @param referrerUrl Referrer to record
   */


  const recordFrameReferrerHeader = function (tab, referrerUrl) {
    tabsApi.updateTabMetadata(tab.tabId, {
      referrerUrl
    });
  };
  /**
   * Gets main frame data
   *
   * @param tab Tab
   * @returns {*} frame data
   */


  const getFrameInfo = function (tab) {
    const {
      tabId
    } = tab;
    const frame = tabsApi.getTabFrame(tabId);
    let {
      url
    } = tab;

    if (!url && frame) {
      url = frame.url;
    }

    const localStorageInitialized = storage_localStorage.isInitialized();
    const urlFilteringDisabled = !utils.url.isHttpRequest(url); // application is available for tabs where url is with http schema
    // and when localstorage is initialized

    const applicationAvailable = localStorageInitialized && !urlFilteringDisabled;
    let documentAllowlisted = false;
    let userAllowlisted = false;
    let canAddRemoveRule = false;
    let frameRule;
    const adguardProductName = '';
    const totalBlocked = pageStats.getTotalBlocked() || 0;
    const totalBlockedTab = tabsApi.getTabMetadata(tabId, 'blocked') || 0;
    const applicationFilteringDisabled = settings.isFilteringDisabled();

    if (applicationAvailable) {
      documentAllowlisted = isTabAllowlisted(tab);

      if (documentAllowlisted) {
        const rule = getFrameRule(tab);
        userAllowlisted = utils.filters.isAllowlistFilterRule(rule) || utils.filters.isUserFilterRule(rule);
        frameRule = {
          filterId: rule.getFilterListId(),
          ruleText: rule.getText()
        };
      } // It means site in exception


      canAddRemoveRule = !(documentAllowlisted && !userAllowlisted);
    }

    const domainName = getFrameDomain(tab);
    return {
      url,
      applicationAvailable,
      domainName,
      applicationFilteringDisabled,
      urlFilteringDisabled,
      documentAllowlisted,
      userAllowlisted,
      canAddRemoveRule,
      frameRule,
      adguardProductName,
      totalBlockedTab,
      totalBlocked
    };
  };
  /**
   * Update count of blocked requests
   *
   * @param tab - Tab
   * @param blocked - count of blocked requests
   * @returns  updated count of blocked requests
   */


  const updateBlockedAdsCount = function (tab, blocked) {
    pageStats.updateTotalBlocked(blocked);
    blocked = (tabsApi.getTabMetadata(tab.tabId, 'blocked') || 0) + blocked;
    tabsApi.updateTabMetadata(tab.tabId, {
      blocked
    });
    return blocked;
  };
  /**
   * Reset count of blocked requests for tab or overall stats
   * @param tab - Tab (optional)
   */


  const resetBlockedAdsCount = function (tab) {
    if (tab) {
      tabsApi.updateTabMetadata(tab.tabId, {
        blocked: 0
      });
    } else {
      pageStats.resetStats();
    }
  };
  /**
   * Is tab in incognito mode?
   * @param tab Tab
   */


  const isIncognitoTab = function (tab) {
    return tabsApi.isIncognito(tab.tabId);
  };
  /**
   * Checks if we should process request further
   * @param {object} tab
   * @returns {boolean}
   */


  const shouldStopRequestProcess = tab => isTabProtectionDisabled(tab) || isTabAllowlisted(tab); // Records frames on application initialization


  listeners.addListener(event => {
    if (event === listeners.APPLICATION_INITIALIZED) {
      tabsApi.forEach(tab => {
        recordFrame(tab, 0, tab.url, RequestTypes.DOCUMENT);
      });
    }
  });
  return {
    recordFrame,
    getFrameUrl,
    getMainFrameUrl,
    getFrameDomain,
    isTabAllowlisted,
    isTabAllowlistedForSafebrowsing,
    isTabProtectionDisabled,
    isTabAdguardAllowlisted,
    getTabAdguardUserAllowlistRule,
    getFrameRule,
    reloadFrameData,
    recordFrameReferrerHeader,
    getFrameInfo,
    updateBlockedAdsCount,
    resetBlockedAdsCount,
    isIncognitoTab,
    shouldStopRequestProcess,
    checkAndRecordMainFrame
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/rules/hit-stats/hit-stats.browsers.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







/**
 * This module is used to store and track ad filters usage stats.
 * It is used if user has enabled "Send statistics for ad filters usage" option.
 * More info about ad filters stats: http://adguard.com/en/filter-rules-statistics.html
 */

const browsersHitStats = function () {
  const MAX_PAGE_VIEWS_COUNT = 20;
  const HITS_COUNT_PROP = 'filters-hit-count';
  const HITS_PROP = 'h';
  let throttleTimeoutId;
  /**
   * Reads hit stats from local storage
   * @returns {null}
   */

  function getHitCountStats() {
    const json = storage_localStorage.getItem(HITS_COUNT_PROP);
    let stats = Object.create(null);

    try {
      if (json) {
        stats = JSON.parse(json);
      }
    } catch (ex) {
      log.error('Error retrieve hit count statistic, cause {0}', ex);
    }

    return stats;
  }
  /**
   * Object for aggregation hit stats (Lazy initialized)
   */


  const hitStatsHolder = {
    get hitStats() {
      return lazyGet(hitStatsHolder, 'hitStats', getHitCountStats);
    }

  };
  /**
   * Cleanup stats
   */

  function cleanup() {
    storage_localStorage.removeItem(HITS_COUNT_PROP);
    lazyGetClear(hitStatsHolder, 'hitStats');
  }
  /**
   * Sends hit stats to backend server
   */


  function sendStats() {
    const overallViews = hitStatsHolder.hitStats.views || 0;

    if (overallViews < MAX_PAGE_VIEWS_COUNT) {
      return;
    }

    const enabledFilters = application.getEnabledFilters();
    backend.sendHitStats(JSON.stringify(hitStatsHolder.hitStats), enabledFilters);
    cleanup();
  }
  /**
   * Save hit stats to local storage and invoke sendStats
   * Throttled with 2 seconds delay
   * @param stats
   */


  function saveHitsCountStats(stats) {
    if (throttleTimeoutId) {
      clearTimeout(throttleTimeoutId);
    }

    throttleTimeoutId = setTimeout(() => {
      try {
        storage_localStorage.setItem(HITS_COUNT_PROP, JSON.stringify(stats));
      } catch (ex) {
        log.error('Error save hit count statistic to storage, cause {0}', ex);
      }

      sendStats();
    }, 2000);
  }
  /**
   * Add 1 domain view to stats
   * @param domain
   */


  const addDomainView = function (domain) {
    if (!domain) {
      return;
    }

    let {
      domains
    } = hitStatsHolder.hitStats;

    if (!domains) {
      domains = Object.create(null);
      hitStatsHolder.hitStats.domains = domains;
    }

    let domainInfo = domains[domain];

    if (!domainInfo) {
      domainInfo = Object.create(null);
      domains[domain] = domainInfo;
      domainInfo.views = 0;
    }

    domainInfo.views += 1;
    hitStatsHolder.hitStats.views = (hitStatsHolder.hitStats.views || 0) + 1;
    saveHitsCountStats(hitStatsHolder.hitStats);
  };
  /**
   * Add 1 rule hit to stats
   * @param domain Domain of site where rule was applied
   * @param ruleText
   * @param filterId
   * @param requestUrl Url to which rule was applied
   */


  const addRuleHit = function (domain, ruleText, filterId, requestUrl) {
    if (!domain || !ruleText || !filterId) {
      return;
    }

    const domainInfo = hitStatsHolder.hitStats.domains ? hitStatsHolder.hitStats.domains[domain] : null;

    if (!domainInfo) {
      return;
    }

    let {
      rules
    } = domainInfo;

    if (!rules) {
      rules = Object.create(null);
      domainInfo.rules = rules;
    }

    let filterRules = rules[filterId];

    if (!filterRules) {
      filterRules = Object.create(null);
      rules[filterId] = filterRules;
    }

    if (!(ruleText in filterRules)) {
      filterRules[ruleText] = null;
    }

    let ruleInfo = filterRules[ruleText];

    if (!ruleInfo) {
      ruleInfo = Object.create(null);
      filterRules[ruleText] = ruleInfo;
    }

    if (requestUrl) {
      const requestDomain = utils.url.getDomainName(requestUrl); // Domain hits

      const domainHits = ruleInfo[requestDomain] || 0;
      ruleInfo[requestDomain] = domainHits + 1;
    } else {
      // Css hits
      const hits = ruleInfo[HITS_PROP] || 0;
      ruleInfo[HITS_PROP] = hits + 1;
    }

    saveHitsCountStats(hitStatsHolder.hitStats);
  };
  /**
   * Hit stats getter
   */


  const getStats = function () {
    return hitStatsHolder.hitStats;
  };
  /**
   * Cleanup stats on property disabled
   */


  settings.onUpdated.addListener(setting => {
    if (setting === settings.DISABLE_COLLECT_HITS && !settings.collectHitsCount()) {
      cleanup();
    }
  });
  return {
    addRuleHit,
    addDomainView,
    cleanup,
    getStats
  };
}();

/* harmony default export */ const hit_stats_browsers = (browsersHitStats);
;// CONCATENATED MODULE: ./Extension/src/background/filter/rules/hit-stats/index.js
/**
 * !IMPORTANT!
 * './hit-stats.__ABSTRACT_API__.js' is replaced during webpack compilation
 * with NormalModuleReplacementPlugin to proper browser implementation
 * './hit-stats.adguard-api.js' or './hit-stats.browsers.js'
 */


;// CONCATENATED MODULE: ./Extension/src/background/filter/request-context-storage.js














/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */



/**
 * Module for managing requests context.
 *
 * Each request has a context with unique key: requestId
 * Context contains information about this request: id, url, referrer, type, applied rules, original and modified headers
 *
 * This API is exposed via requestContextStorage:
 *
 * - get - Get context by key
 * - record - Initialize context for request (uses in onBeforeRequest)
 * - update - Updates context properties (rules)
 * - bindContentRule - Binds content rule and removed element to the context
 * - onContentModificationStarted - Must be called to point that content modification is started
 *   Following 2 methods have same logic (push rules to log, record rule hits and perform cleanup), but called in different cases:
 * - onRequestCompleted - Finishes request processing on request complete/error event.
 * - onContentModificationFinished - After content modification and applying all rules (replace and content)
 */

const requestContextStorage = function () {
  /**
   * @typedef {object} RequestContext
   * @property {string} requestId - Request identifier
   * @property {string} requestUrl - Request url
   * @property {string} referrerUrl - Request referrer url
   * @property {string} requestType - Request type
   * @property {number} engineRequestType - TsUrlFilter Request type
   * @property {{tabId: Number}} tab - Request tab
   * @property {Array} requestHeaders - Original request headers
   * @property {Array} modifiedRequestHeaders - Modified request headers
   * @property {Array} responseHeaders - Original response headers
   * @property {Array} modifiedResponseHeaders - Modified response headers
   * @property {object} requestRule - Request rule
   * @property {Array} replaceRules - Applied replace rules
   * @property {Array} contentRules - Content rules
   * @property {Array} cspRules CSP - rules
   * @property {number} eventId - Internal counter for log events
   * @property {number} requestState - Is request between onBeforeRequest and onCompleted/onErrorOccurred events
   * @property {number} contentModifyingState - Is content modification started
   * @property {Map<object, string[]>} elements - Content rules attached elements
   * @property {number} stealthActions - Applied stealth actions
   * @property {boolean} cspReportBlocked - Blocked because is csp report request
   * @property {number} statusCode Response status code
   * @property {number} timestamp Request UTC timestamp
   */

  /**
   * @typedef {object} States
   * @property {number} NONE - Ready for cleanup (not started or already finished and processed)
   * @property {number} PROCESSING - In progress
   * @property {number} DONE - Finished, ready for processing. Next transition to NONE and cleanup
   */
  const States = {
    NONE: 1,
    PROCESSING: 2,
    DONE: 3
  };
  /**
   * Collects context
   * @type {Map<string, RequestContext>}
   */

  const contexts = new Map();
  /**
   * Event counter for pushing rules to the filtering log on request complete/error
   * Don't use requestId, because redirected requests have the same request identifier
   * @type {number}
   */

  let nextEventId = 0;
  /**
   * Append rules to the current rules
   * @param {Array} original - Original value
   * @param {Array} toAppend - Value to append
   * @returns {Array} concatenated value
   */

  const appendRules = (original, toAppend) => {
    if (toAppend) {
      original = (original || []).concat(toAppend);
    }

    return original;
  };
  /**
   * Creates copy of headers array
   * @param headers Headers to copy
   * @return {{name: *, value: *}[]}
   */


  const copyHeaders = headers => (headers || []).map(h => ({
    name: h.name,
    value: h.value
  }));
  /**
   * Generates next event identifier
   * @returns {number}
   */


  const getNextEventId = () => {
    nextEventId += 1;
    return nextEventId;
  };
  /**
   * Gets request context
   * @param {string} requestId Request identifier
   */


  const get = requestId => {
    return contexts.get(String(requestId));
  };
  /**
   * Records request context
   * @param {Object} params params object
   * @param {string} params.requestId Request identifier
   * @param {string} params.requestUrl Request url
   * @param {string} params.referrerUrl Request referrer url
   * @param {string} params.originUrl Request origin url (initiator)
   * @param {string} params.requestType Request type
   * @param {string} params.engineRequestType TsUrlFilter Request type
   * @param {Object} params.tab Request tab
   * @param {string} params.method Request HTTP method
   */


  const record = ({
    requestId,
    requestUrl,
    referrerUrl,
    originUrl,
    requestType,
    engineRequestType,
    tab,
    method
  }) => {
    const eventId = getNextEventId(); // Clears filtering log. If contexts map already contains this requests that means that we caught redirect

    if (requestType === RequestTypes.DOCUMENT && !contexts.has(String(requestId))) {
      filtering_log_browsers.clearEventsByTabId(tab.tabId);
    }

    const timestamp = Date.now();
    const context = {
      requestId,
      requestUrl,
      referrerUrl,
      originUrl,
      requestType,
      engineRequestType,
      tab,
      eventId,
      requestState: States.PROCESSING,
      contentModifyingState: States.NONE,
      timestamp,
      method
    };
    contexts.set(String(requestId), context);
    filtering_log_browsers.addHttpRequestEvent({
      tab,
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      timestamp,
      eventId,
      method
    });
    return context;
  };
  /**
   * Some "requests" can't be intercepted by webRequest API: WS and WebRTC, popups.
   * So them don't have usual request identifier and must be processing in the other way.
   * @param {Object} params params object
   * @param {string} params.requestUrl  Request URL
   * @param {string} params.referrerUrl  Referrer
   * @param {string} params.requestType  Request type
   * @param {Object} params.tab  Tab
   * @param {Object} params.requestRule  Request rule
   */


  const recordEmulated = ({
    requestUrl,
    referrerUrl,
    requestType,
    tab,
    requestRule
  }) => {
    filtering_log_browsers.addHttpRequestEvent({
      tab,
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      requestRule,
      timestamp: Date.now()
    });
    webRequestService.recordRuleHit(tab, requestRule, requestUrl);
  };
  /**
   * Updates request context
   * @param {string} requestId Request identifier
   * @param {RequestContext} update
   */


  const update = (requestId, update) => {
    const context = contexts.get(String(requestId));

    if (!context) {
      return;
    } // Updates request lifecycle


    if ('requestState' in update) {
      context.requestState = update.requestState;
    }

    if ('contentModifyingState' in update) {
      context.contentModifyingState = update.contentModifyingState;
    } // Updates rules for request


    if ('requestRule' in update) {
      context.requestRule = update.requestRule; // Some requests may execute for a long time, that's why we update filtering log when
      // we get a request rule

      filtering_log_browsers.bindRuleToHttpRequestEvent(context.tab, context.requestRule, context.eventId);
    }

    if ('replaceRules' in update) {
      context.replaceRules = update.replaceRules;
    }

    if ('cspRules' in update) {
      context.cspRules = appendRules(context.cspRules, update.cspRules);
    }

    if ('stealthActions' in update) {
      context.stealthActions = update.stealthActions;
    }

    if ('requestHeaders' in update) {
      context.requestHeaders = copyHeaders(update.requestHeaders);
    }

    if ('responseHeaders' in update) {
      context.responseHeaders = copyHeaders(update.responseHeaders);
    }

    if ('modifiedRequestHeaders' in update) {
      context.modifiedRequestHeaders = copyHeaders(update.modifiedRequestHeaders);
    }

    if ('modifiedResponseHeaders' in update) {
      context.modifiedResponseHeaders = copyHeaders(update.modifiedResponseHeaders);
    }

    if ('cspReportBlocked' in update) {
      context.cspReportBlocked = update.cspReportBlocked;
    }

    if ('statusCode' in update) {
      context.statusCode = update.statusCode;
      filtering_log_browsers.bindResponseDataToHttpRequestEvent(context.tab, context.statusCode, context.eventId);
    }

    if ('contentType' in update) {
      context.contentType = update.contentType;
    }
  };
  /**
   * Binds content rule with serialized element to the request
   *
   * @param {string} requestId Request identifier
   * @param {object} rule Content rule
   * @param {object} elementHtml Serialized HTML element
   */


  const bindContentRule = (requestId, rule, elementHtml) => {
    const context = contexts.get(String(requestId));

    if (!context) {
      return;
    }

    context.contentRules = appendRules(context.contentRules, [rule]);

    if (!context.elements) {
      context.elements = new Map();
    }

    let ruleElements = context.elements.get(rule);

    if (!ruleElements) {
      ruleElements = [];
      context.elements.set(rule, ruleElements);
    }

    ruleElements.push(elementHtml);
  };
  /**
   * Finishes request processing
   *
   * Invoked in the following cases:
   * 1) on complete/error event for request
   * 2) on content modification finished
   *
   * In case of content modification don't forget to call onContentModificationStarted method
   * to prevent removing context for complete/error event for request
   *
   * @param {string} requestId Request identifier
   */


  const remove = requestId => {
    const context = contexts.get(String(requestId));

    if (!context) {
      return;
    }

    const {
      tab,
      requestUrl,
      referrerUrl
    } = context;
    let ruleHitsRecords = [];

    if (context.requestState === States.DONE) {
      context.requestState = States.NONE;
      const {
        requestRule,
        cspRules,
        stealthActions,
        cspReportBlocked
      } = context;

      if (requestRule) {
        filtering_log_browsers.bindRuleToHttpRequestEvent(tab, requestRule, context.eventId);
        ruleHitsRecords.push(requestRule);
      }

      if (cspRules) {
        cspRules.forEach(cspRule => {
          filtering_log_browsers.addHttpRequestEvent({
            tab,
            requestUrl,
            frameUrl: referrerUrl,
            requestType: RequestTypes.CSP,
            requestRule: cspRule,
            timestamp: Date.now()
          });
        });
        ruleHitsRecords = ruleHitsRecords.concat(cspRules);
      }

      if (stealthActions) {
        filtering_log_browsers.bindStealthActionsToHttpRequestEvent(tab, stealthActions, context.eventId);
      }

      if (cspReportBlocked) {
        filtering_log_browsers.bindCspReportBlockedToHttpRequestEvent(tab, cspReportBlocked, context.eventId);
      }
    }

    if (context.contentModifyingState === States.DONE) {
      context.contentModifyingState = States.NONE;
      const {
        replaceRules
      } = context;
      const {
        contentRules
      } = context;

      if (replaceRules) {
        filtering_log_browsers.bindReplaceRulesToHttpRequestEvent(tab, replaceRules, context.eventId);
        ruleHitsRecords = ruleHitsRecords.concat(replaceRules);
      }

      if (contentRules) {
        contentRules.forEach(contentRule => {
          const elements = context.elements.get(contentRule) || [];
          elements.forEach(element => {
            filtering_log_browsers.addCosmeticEvent({
              tab,
              element,
              frameUrl: requestUrl,
              requestType: context.requestType,
              requestRule: contentRule,
              timestamp: Date.now()
            });
          });
          context.elements.delete(contentRule);
        });
        ruleHitsRecords = ruleHitsRecords.concat(contentRules);
      }
    }

    for (let i = 0; i < ruleHitsRecords.length; i += 1) {
      webRequestService.recordRuleHit(tab, ruleHitsRecords[i], requestUrl);
    } // All processes finished


    if (context.requestState === States.NONE && context.contentModifyingState === States.NONE) {
      contexts.delete(String(requestId));
    }
  };
  /**
   * Called on request complete/error event
   *
   * @param {string} requestId Request identifier
   * @param {number} statusCode Response status code
   */


  const onRequestCompleted = (requestId, statusCode) => {
    update(requestId, {
      requestState: States.DONE,
      statusCode
    });
    remove(requestId);
  };
  /**
   * Indicates that content modification in progress
   *
   * @param {string} requestId Request identifier
   */


  const onContentModificationStarted = requestId => {
    update(requestId, {
      contentModifyingState: States.PROCESSING
    });
  };
  /**
   * Indicates that content modification finished
   *
   * @param {string} requestId Request identifier
   */


  const onContentModificationFinished = requestId => {
    update(requestId, {
      contentModifyingState: States.DONE
    });
    remove(requestId);
  }; // Expose


  return {
    get,
    record,
    recordEmulated,
    update,
    bindContentRule,
    onRequestCompleted,
    onContentModificationStarted,
    onContentModificationFinished
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/expiring-cache.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


const ExpiringCache = (() => {
  /**
   * Cache with maxCacheSize stored in local storage, which automatically clears expired values
   *
   * @param {string} storagePropertyName      Name of the local storage property.
   * @param {number} size                     Max cache size
   */
  function ExpiringCache(storagePropertyName, size) {
    const CACHE_SIZE = 1000;
    const maxCacheSize = size || CACHE_SIZE;
    let cache;
    let cacheSize;

    function getCacheFromLocalStorage() {
      let data = Object.create(null);

      try {
        const json = storage_localStorage.getItem(storagePropertyName);

        if (json) {
          data = JSON.parse(json);
        }
      } catch (ex) {
        // ignore
        log.error('Error read from {0} cache, cause: {1}', storagePropertyName, ex);
        storage_localStorage.removeItem(storagePropertyName);
      }

      return data;
    }

    function saveCacheToLocalStorage() {
      try {
        storage_localStorage.setItem(storagePropertyName, JSON.stringify(cache));
      } catch (ex) {
        log.error('Error save to {0} cache, cause: {1}', storagePropertyName, ex);
      }
    }
    /**
     * Retrieves value from cache and checks if saved data is not expired yet.
     * @param {string} key
     * @returns {null|object} saved data
     */


    function getValue(key) {
      const value = cache[key];

      if (value !== undefined) {
        const expires = value.expires - 0;

        if (Date.now() >= expires) {
          return null;
        }

        return value.data;
      }

      return null;
    }

    function cleanup() {
      const keys = Object.keys(cache);

      for (let i = 0; i < keys.length; i += 1) {
        const key = keys[i];
        const foundItem = getValue(key);

        if (!foundItem) {
          delete cache[key];
          cacheSize -= 1;
        }
      }

      if (cacheSize > maxCacheSize / 2) {
        const keys = Object.keys(cache);

        for (let i = 0; i < keys.length; i += 1) {
          const key = keys[i];
          delete cache[key];
          cacheSize -= 1;

          if (cacheSize <= maxCacheSize / 2) {
            break;
          }
        }
      }

      saveCacheToLocalStorage();
    }

    const saveValue = function (key, data, expires) {
      if (!key) {
        return;
      }

      if (cacheSize > maxCacheSize) {
        cleanup();
      }

      cache[key] = {
        data,
        expires
      };
      cacheSize += 1;

      if (cacheSize % 20 === 0) {
        saveCacheToLocalStorage();
      }
    }; // Load cache


    cache = getCacheFromLocalStorage();
    cacheSize = Object.keys(cache).length;
    cleanup();
    return {
      getValue,
      saveValue
    };
  }
  /**
   * Expose
   */


  return ExpiringCache;
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/document-filter.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */








const documentFilterService = function () {
  const trustedCache = {
    get cache() {
      return lazyGet(trustedCache, 'cache', () => new ExpiringCache('document-block-cache'));
    }

  };

  function documentFilterService() {
    const TRUSTED_TTL_MS = 1000 * 60 * 40; // 40 minutes

    const DOCUMENT_BLOCKED_URL = 'pages/ad-blocked.html';
    /**
     * Checks if url is trusted
     * @param url
     * @returns {boolean}
     */

    const isTrusted = url => {
      const host = utils.url.getHost(url);

      if (!host) {
        return false;
      }

      const value = trustedCache.cache.getValue(host);
      return !!value;
    };
    /**
     * Return url of the document block page and ads there parameters with rule and url
     * @param url
     * @param ruleText
     * @returns {null|string}
     */


    const getDocumentBlockPageUrl = (url, ruleText) => {
      if (isTrusted(url)) {
        return null;
      }

      let blockingUrl = backgroundPage.getURL(DOCUMENT_BLOCKED_URL);
      blockingUrl += `?url=${encodeURIComponent(url)}`;
      blockingUrl += `&rule=${encodeURIComponent(ruleText)}`;
      return blockingUrl;
    };
    /**
     * Gets url host and adds it to the cache of trusted domains
     * @param url
     */


    const addToTrusted = async url => {
      const host = utils.url.getHost(url);

      if (!host) {
        return;
      }

      trustedCache.cache.saveValue(host, {
        host
      }, Date.now() + TRUSTED_TTL_MS); // Reloads ad-blocked page with trusted url

      const tab = await tabsApi.getActive();

      if (tab) {
        tabsApi.reload(tab.tabId, url);
      }
    };
    /**
     * Shows document block page
     * @param tabId
     * @param url
     */


    const showDocumentBlockPage = (tabId, url) => {
      const incognitoTab = frames_frames.isIncognitoTab({
        tabId
      }); // Chrome doesn't allow to show extension pages in incognito mode

      if (incognitoTab && browserUtils.isChromium()) {
        // Closing tab before opening a new one may lead to browser crash (Chromium)
        uiService.openTab(url).then(() => {
          tabsApi.remove(tabId);
        });
      } else {
        tabsApi.updateUrl(tabId, url);
      }
    };

    return {
      getDocumentBlockPageUrl,
      addToTrusted,
      showDocumentBlockPage
    };
  }

  return documentFilterService();
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/stealth-service.js
/* eslint-disable no-use-before-define */

/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */












/**
 * Class to apply stealth settings
 * - Cookie
 * - Headers
 * - WebRTC
 */

const stealthService = (() => {
  /**
   * Privacy permission for block webrtc stealth setting
   */
  const PRIVACY_PERMISSIONS = {
    permissions: ['privacy']
  };
  /**
   * Processes request headers
   *
   * @param {string} requestId Request identifier
   * @param {Array} requestHeaders Request headers
   * @return {boolean} True if headers were modified
   */

  const processRequestHeaders = function (requestId, requestHeaders) {
    const context = requestContextStorage.get(requestId);

    if (!context) {
      return false;
    }

    const {
      requestUrl,
      requestType
    } = context;
    log.debug('Stealth service processing request headers for {0}', requestUrl);

    if (!canApplyStealthActionsToContext(context)) {
      return false;
    }

    const stealthActions = engine.processRequestHeaders(requestUrl, RequestTypes.transformRequestType(requestType), requestHeaders);

    if (stealthActions > 0) {
      requestContextStorage.update(requestId, {
        stealthActions
      });
    }

    log.debug('Stealth service processed request headers for {0}', requestUrl);
    return stealthActions > 0;
  };
  /**
   * Returns rule list with stealth mode rules
   * @return {StringRuleList}
   */


  const getStealthModeRuleList = () => {
    const rulesTexts = engine.getCookieRulesTexts().join('\n');
    return new tsurlfilter_browser.StringRuleList(utils.filters.STEALTH_MODE_FILTER_ID, rulesTexts, false, false);
  };
  /**
   * Checks is engine has stealth mode rules
   * @return {boolean}
   */


  const hasFilterRules = () => {
    return engine.getCookieRulesTexts().length > 0;
  };
  /**
   * Checks if stealth actions are available for provided request context
   *
   * @param context
   * @return {boolean}
   */


  const canApplyStealthActionsToContext = context => {
    const {
      requestUrl,
      requestType,
      tab
    } = context;

    if (frames_frames.shouldStopRequestProcess(tab)) {
      log.debug('Tab allowlisted or protection disabled');
      return false;
    }

    const mainFrameUrl = frames_frames.getMainFrameUrl(tab);

    if (!mainFrameUrl) {
      // frame wasn't recorded in onBeforeRequest event
      log.debug('Frame was not recorded in onBeforeRequest event');
      return false;
    }

    return canApplyStealthActions(tab, requestUrl, mainFrameUrl, requestType);
  };
  /**
   * Checks if stealth actions are available for provided request with parameters
   *
   * @param tab
   * @param requestUrl
   * @param referrerUrl
   * @param requestType
   * @return {boolean}
   */


  const canApplyStealthActions = (tab, requestUrl, referrerUrl, requestType) => {
    // if stealth mode is disabled
    if (isStealthModeDisabled()) {
      return false;
    }

    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule: frames_frames.getFrameRule(tab)
    });

    if (allowlistRule && allowlistRule.isDocumentAllowlistRule()) {
      log.debug(`Allowlist rule found: ${allowlistRule.getText()}`);
      return false;
    } // If stealth is allowlisted


    const stealthAllowlistRule = findStealthAllowlistRule(requestUrl, referrerUrl, requestType);

    if (stealthAllowlistRule) {
      log.debug(`Allowlist stealth rule found: ${stealthAllowlistRule.getText()}`);
      return false;
    }

    return true;
  };
  /**
   * Checks if tab is allowlisted for stealth
   *
   * @param requestUrl
   * @param referrerUrl
   * @param requestType
   * @returns allowlist rule if found
   */


  const findStealthAllowlistRule = function (requestUrl, referrerUrl, requestType) {
    if (referrerUrl) {
      const stealthDocumentAllowlistRule = filteringApi.findStealthAllowlistRule({
        requestUrl: referrerUrl,
        frameUrl: referrerUrl,
        requestType
      });

      if (stealthDocumentAllowlistRule && stealthDocumentAllowlistRule.isDocumentAllowlistRule()) {
        log.debug('Stealth document allowlist rule found.');
        return stealthDocumentAllowlistRule;
      }
    }

    const stealthAllowlistRule = filteringApi.findStealthAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType
    });

    if (stealthAllowlistRule) {
      log.debug('Stealth allowlist rule found.');
      return stealthAllowlistRule;
    }

    return null;
  };
  /**
   * Checks if stealth mode is disabled
   * @returns {boolean}
   */


  const isStealthModeDisabled = () => {
    return settings.getProperty(settings.DISABLE_STEALTH_MODE) || settings.isFilteringDisabled();
  };
  /**
   * Returns stealth setting current value, considering if global stealth setting is enabled
   * @param stealthSettingName
   * @returns {boolean}
   */


  const getStealthSettingValue = stealthSettingName => {
    if (isStealthModeDisabled()) {
      return false;
    }

    return settings.getProperty(stealthSettingName);
  };
  /**
   * Updates browser privacy.network settings depending on blocking WebRTC or not
   *
   * @param blockWebRTC
   */


  const setBlockWebRTC = async blockWebRTC => {
    // Edge doesn't support privacy api
    // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy
    if (!(browser_polyfill_default()).privacy) {
      return;
    }

    const logError = e => {
      log.error('Error updating privacy.network settings: {0}', e);
    }; // Deprecated since Chrome 48


    if (typeof (browser_polyfill_default()).privacy.network.webRTCMultipleRoutesEnabled === 'object') {
      try {
        if (blockWebRTC) {
          await browser_polyfill_default().privacy.network.webRTCMultipleRoutesEnabled.set({
            value: false,
            scope: 'regular'
          });
        } else {
          await browser_polyfill_default().privacy.network.webRTCMultipleRoutesEnabled.clear({
            scope: 'regular'
          });
        }
      } catch (e) {
        logError(e);
      }
    } // Since chromium 48


    if (typeof (browser_polyfill_default()).privacy.network.webRTCIPHandlingPolicy === 'object') {
      try {
        if (blockWebRTC) {
          await browser_polyfill_default().privacy.network.webRTCIPHandlingPolicy.set({
            value: 'disable_non_proxied_udp',
            scope: 'regular'
          });
        } else {
          await browser_polyfill_default().privacy.network.webRTCIPHandlingPolicy.clear({
            scope: 'regular'
          });
        }
      } catch (e) {
        logError(e);
      }
    }

    if (typeof (browser_polyfill_default()).privacy.network.peerConnectionEnabled === 'object') {
      try {
        if (blockWebRTC) {
          browser_polyfill_default().privacy.network.peerConnectionEnabled.set({
            value: false,
            scope: 'regular'
          });
        } else {
          browser_polyfill_default().privacy.network.peerConnectionEnabled.clear({
            scope: 'regular'
          });
        }
      } catch (e) {
        logError(e);
      }
    }
  };

  const handleWebRTCEnabling = async () => {
    try {
      let isPermissionsGranted = await browserUtils.containsPermissions(PRIVACY_PERMISSIONS);

      if (!isPermissionsGranted) {
        isPermissionsGranted = await browserUtils.requestPermissions(PRIVACY_PERMISSIONS);
      }

      if (isPermissionsGranted) {
        await setBlockWebRTC(false);
      } else {
        // If privacy permission is not granted set block webrtc value to false
        settings.setProperty(settings.BLOCK_WEBRTC, false);
      }
    } catch (e) {
      log.error(e);
    }
  };

  const handleWebRTCDisabling = async () => {
    try {
      let isPermissionsGranted = await browserUtils.containsPermissions(PRIVACY_PERMISSIONS);

      if (!isPermissionsGranted) {
        isPermissionsGranted = await browserUtils.requestPermissions(PRIVACY_PERMISSIONS);
      }

      if (isPermissionsGranted) {
        await setBlockWebRTC(true);
        await browserUtils.removePermission(PRIVACY_PERMISSIONS);
      }
    } catch (e) {
      log.error(e);
    }
  };

  const handlePrivacyPermissions = async shouldBlock => {
    if (shouldBlock) {
      await handleWebRTCDisabling();
    } else {
      await handleWebRTCEnabling();
    }
  };
  /**
   * Browsers api doesn't allow to get optional permissions
   * via chrome.permissions.getAll and we can't check privacy
   * availability via `browser.privacy !== undefined` till permission
   * isn't enabled by the user
   *
   * That's why use edge browser detection
   * Privacy methods are not working at all in the Edge
   * @returns {boolean}
   */


  const canBlockWebRTC = () => {
    return !browserUtils.isEdgeBrowser();
  };
  /**
   * Initializes service
   */


  const init = () => {
    engine = new tsurlfilter_browser.StealthService(getConfig());
  };
  /**
   * We handle privacy permission only for chromium browsers
   * In the Firefox privacy permission is available by default
   * because they can't be optional there
   * @returns {boolean}
   */


  const shouldHandlePrivacyPermission = () => {
    return browserUtils.isChromium();
  };
  /**
   * Returns stealth service configuration object
   */


  const getConfig = () => {
    return {
      blockChromeClientData: getStealthSettingValue(settings.BLOCK_CHROME_CLIENT_DATA),
      hideReferrer: getStealthSettingValue(settings.HIDE_REFERRER),
      hideSearchQueries: getStealthSettingValue(settings.HIDE_SEARCH_QUERIES),
      sendDoNotTrack: getStealthSettingValue(settings.SEND_DO_NOT_TRACK),
      selfDestructThirdPartyCookies: getStealthSettingValue(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES),
      selfDestructThirdPartyCookiesTime: settings.getProperty(settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME),
      selfDestructFirstPartyCookies: getStealthSettingValue(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES),
      selfDestructFirstPartyCookiesTime: settings.getProperty(settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME)
    };
  };

  const STEALTH_SETTINGS = [settings.DISABLE_STEALTH_MODE, settings.BLOCK_CHROME_CLIENT_DATA, settings.HIDE_REFERRER, settings.HIDE_SEARCH_QUERIES, settings.SEND_DO_NOT_TRACK, settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES, settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME, settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES, settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME, settings.BLOCK_WEBRTC];
  let engine = new tsurlfilter_browser.StealthService(getConfig());
  settings.onUpdated.addListener(setting => {
    if (STEALTH_SETTINGS.includes(setting)) {
      // Rebuild engine on settings update
      engine = new tsurlfilter_browser.StealthService(getConfig());
      listeners.notifyListeners(listeners.UPDATE_FILTER_RULES);
    }
  });

  if (canBlockWebRTC()) {
    settings.onUpdated.addListener(async (settingName, settingValue) => {
      if (settingName === settings.BLOCK_WEBRTC || settingName === settings.DISABLE_STEALTH_MODE) {
        let shouldBlock;

        if (settingName === settings.BLOCK_WEBRTC) {
          if (!isStealthModeDisabled()) {
            shouldBlock = settingValue;
          }
        } else if (settingName === settings.DISABLE_STEALTH_MODE) {
          if (settings.getProperty(settings.BLOCK_WEBRTC)) {
            // Enable webRTC if stealth mode is disabled
            shouldBlock = !settingValue;
          }
        }

        if (typeof shouldBlock === 'undefined') {
          // Nothing to change indeed
          return;
        }

        if (shouldHandlePrivacyPermission()) {
          await handlePrivacyPermissions(shouldBlock);
        } else {
          await setBlockWebRTC(shouldBlock);
        }
      }
    });
    listeners.addListener(async event => {
      let isPermissionsGranted;

      switch (event) {
        case listeners.APPLICATION_INITIALIZED:
          try {
            isPermissionsGranted = await browserUtils.containsPermissions(PRIVACY_PERMISSIONS);
          } catch (e) {
            log.error(e);
          }

          if (isPermissionsGranted) {
            await setBlockWebRTC(getStealthSettingValue(settings.BLOCK_WEBRTC));
          }

          break;

        default:
          break;
      }
    });
  }
  /**
   * Returns either script which will send dom signal, or empty string
   * @returns {*}
   */


  const getSetDomSignalScript = () => {
    return engine.getSetDomSignalScript();
  };

  return {
    init,
    processRequestHeaders,
    getStealthModeRuleList,
    hasFilterRules,
    canBlockWebRTC,
    getSetDomSignalScript,
    STEALTH_ACTIONS: STEALTH_ACTIONS
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/request-blocking.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */
















const webRequestService = function () {
  const onRequestBlockedChannel = utils.channels.newChannel();
  /**
   * Checks if we can collect hit stats for this tab:
   * Option "Send ad filters usage" is enabled and tab isn't incognito
   * @param {object} tab
   * @returns {boolean}
   */

  const canCollectHitStatsForTab = function (tab) {
    if (!tab) {
      return settings.collectHitsCount();
    }

    return tab && settings.collectHitsCount() && !frames_frames.isIncognitoTab(tab);
  };
  /**
   * Records filtering rule hit
   *
   * @param tab            Tab object
   * @param requestRule    Rule to record
   * @param requestUrl     Request URL
   */


  const recordRuleHit = function (tab, requestRule, requestUrl) {
    if (requestRule && !utils.filters.isUserFilterRule(requestRule) && !utils.filters.isAllowlistFilterRule(requestRule) && canCollectHitStatsForTab(tab)) {
      const domain = frames_frames.getFrameDomain(tab);
      hit_stats_browsers.addRuleHit(domain, requestRule.getText(), requestRule.getFilterListId(), requestUrl);
    }
  };
  /**
   * An object with the selectors and scripts to be injected into the page
   * @typedef {Object} SelectorsAndScripts
   * @property {SelectorsData} selectors An object with the CSS styles that needs to be applied
   * @property {string} scripts Javascript to be injected into the page
   * @property {boolean} collapseAllElements If true, content script must force
   * the collapse check of the page elements
   */

  /**
   * Prepares CSS and JS which should be injected to the page.
   *
   * @param tab                       Tab data
   * @param documentUrl               Document URL
   * @param {boolean} force           Indicates whether to retrieve JS and Css selectors, used in 'webrequest' call
   *
   * When cssFilterOptions and force are undefined, we handle it in a special way
   * that depends on whether the browser supports inserting CSS and scripts from the background page
   *
   * @returns {SelectorsAndScripts} an object with the selectors and scripts to be injected into the page
   */


  const processGetSelectorsAndScripts = function (tab, documentUrl, force) {
    const result = Object.create(null);

    if (!tab) {
      return result;
    }

    if (!filteringApi.isReady()) {
      result.requestFilterReady = false;
      return result;
    }

    if (frames_frames.isTabProtectionDisabled(tab)) {
      return result;
    }

    if (frames_frames.isTabAllowlisted(tab)) {
      return result;
    }

    const cosmeticOptions = filteringApi.getCosmeticOption({
      requestUrl: documentUrl,
      frameUrl: documentUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule: frames_frames.getFrameRule(tab)
    });

    if (force || !prefs.features.canUseInsertCSSAndExecuteScript) {
      // Retrieve ExtendedCss selectors only if canUseInsertCSSAndExecuteScript is unavailable
      result.selectors = filteringApi.getSelectorsForUrl(documentUrl, cosmeticOptions, true, !prefs.features.canUseInsertCSSAndExecuteScript); // grep "localScriptRulesService" for details about script source

      result.scripts = filteringApi.getScriptsStringForUrl(documentUrl, tab, cosmeticOptions); // add stealth dom signal script

      result.scripts += stealthService.getSetDomSignalScript();
    } else {
      // In preload content script only ExtendedCss selectors are necessary.
      // Traditional css selectors would be injected via tabs.injectCss.
      // Except when browser starts with open tabs
      result.selectors = filteringApi.getSelectorsForUrl(documentUrl, cosmeticOptions, false, true);
    } // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1337


    result.collectRulesHits = isCollectingCosmeticRulesHits(tab);
    result.collapseAllElements = filteringApi.shouldCollapseAllElements();
    return result;
  };
  /**
   * Checks if request that is wrapped in page script should be blocked.
   * We do this because browser API doesn't have full support for intercepting all requests, e.g. WebSocket or WebRTC.
   *
   * @param tab           Tab
   * @param requestUrl    request url
   * @param referrerUrl   referrer url
   * @param requestType   Request type (WEBSOCKET or WEBRTC)
   * @returns {boolean}   true if request is blocked
   */


  const checkPageScriptWrapperRequest = function (tab, requestUrl, referrerUrl, requestType) {
    if (!tab) {
      return false;
    }

    let requestRule = getRuleForRequest(tab, requestUrl, referrerUrl, requestType);
    requestRule = postProcessRequest(tab, requestUrl, referrerUrl, requestType, requestRule);
    requestContextStorage.recordEmulated({
      requestUrl,
      referrerUrl,
      requestType,
      tab,
      requestRule
    });
    return isRequestBlockedByRule(requestRule);
  };
  /**
   * Checks if request is blocked
   *
   * @param tab           Tab
   * @param requestUrl    request url
   * @param referrerUrl   referrer url
   * @param requestType   one of RequestType
   * @returns {boolean}   true if request is blocked
   */


  const processShouldCollapse = function (tab, requestUrl, referrerUrl, requestType) {
    if (!tab) {
      return false;
    }

    const requestRule = getRuleForRequest(tab, requestUrl, referrerUrl, requestType);
    return isRequestBlockedByRule(requestRule);
  };
  /**
   * Checks if requests are blocked
   *
   * @param tab               Tab
   * @param referrerUrl       referrer url
   * @param collapseRequests  requests array
   * @returns {*}             requests array
   */


  const processShouldCollapseMany = function (tab, referrerUrl, collapseRequests) {
    if (!tab) {
      return collapseRequests;
    }

    for (let i = 0; i < collapseRequests.length; i += 1) {
      const request = collapseRequests[i];
      const requestRule = getRuleForRequest(tab, request.elementUrl, referrerUrl, request.requestType);
      request.collapse = isRequestBlockedByRule(requestRule);
    }

    return collapseRequests;
  };
  /**
   * Checks if request is blocked by rule
   * Do not allow redirect rules because they can't be used in collapse check functions
   *
   * @param requestRule
   * @returns {*|boolean}
   */


  const isRequestBlockedByRule = requestRule => {
    return requestRule && !requestRule.isAllowlist() && !requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Replace) && !requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Redirect);
  };
  /**
   * Checks if popup is blocked by rule
   * @param requestRule
   * @returns {boolean}
   */


  const isPopupBlockedByRule = requestRule => {
    return requestRule && !requestRule.isAllowlist() && requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Popup);
  };
  /**
   * Check if document is blocked by rule
   * @param requestRule
   * @return {boolean}
   */


  const isDocumentBlockingRule = requestRule => {
    return requestRule && !requestRule.isAllowlist() && requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Document);
  };
  /**
   * Gets blocked response by rule
   * For details see https://developer.chrome.com/extensions/webRequest#type-BlockingResponse
   * or https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/BlockingResponse
   * @param requestRule   Request rule or null
   * @param requestType   Request type
   * @param requestUrl    Request url
   * @returns {*} Blocked response or null
   */


  const getBlockedResponseByRule = function (requestRule, requestType, requestUrl) {
    if (isRequestBlockedByRule(requestRule)) {
      const isDocumentLevel = requestType === RequestTypes.DOCUMENT || requestType === RequestTypes.SUBDOCUMENT;

      if (isDocumentLevel && isDocumentBlockingRule(requestRule)) {
        const documentBlockedPage = documentFilterService.getDocumentBlockPageUrl(requestUrl, requestRule.getText());

        if (documentBlockedPage) {
          return {
            documentBlockedPage
          };
        }

        return null;
      } // Don't block main_frame request


      if (requestType !== RequestTypes.DOCUMENT) {
        return {
          cancel: true
        };
      } // check if request rule is blocked by rule and is redirect rule

    } else if (requestRule && !requestRule.isAllowlist()) {
      if (requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Redirect)) {
        const redirectUrl = redirectService.createRedirectUrl(requestRule.getAdvancedModifierValue(), requestUrl);

        if (redirectUrl) {
          return {
            redirectUrl
          };
        }
      }
    }

    return null;
  };
  /**
   * Finds rule for request
   *
   * @param tab           Tab
   * @param requestUrl    request url
   * @param referrerUrl   referrer url
   * @param requestType   one of RequestType
   * @returns {*}         rule or null
   */


  const getRuleForRequest = function (tab, requestUrl, referrerUrl, requestType) {
    if (frames_frames.isTabProtectionDisabled(tab)) {
      // don't process request
      return null;
    }

    let allowlistRule;
    /**
     * Background requests will be allowlisted if their referrer
     * url will match with user allowlist rule
     * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1032
     */

    if (tab.tabId === BACKGROUND_TAB_ID) {
      allowlistRule = allowlist.findAllowlistRule(referrerUrl);
    } else {
      allowlistRule = frames_frames.getFrameRule(tab);
    }

    if (allowlistRule && allowlistRule.isDocumentAllowlistRule()) {
      // Frame is allowlisted by the main frame's $document rule
      // We do nothing more in this case - return the rule.
      return allowlistRule;
    }

    if (!allowlistRule) {
      // If allowlist rule is not found for the main frame, we check it for referrer
      allowlistRule = filteringApi.findAllowlistRule({
        requestUrl,
        frameUrl: referrerUrl,
        requestType: RequestTypes.DOCUMENT
      });
    }

    return filteringApi.findRuleForRequest({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule: allowlistRule
    });
  };
  /**
   * Finds all content rules for the url
   * @param tab Tab
   * @param documentUrl Document URL
   * @returns collection of content rules or null
   */


  const getContentRules = function (tab, documentUrl) {
    if (frames_frames.shouldStopRequestProcess(tab)) {
      // don't process request
      return null;
    }

    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl: documentUrl,
      frameUrl: documentUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule: frames_frames.getFrameRule(tab)
    });

    if (allowlistRule && allowlistRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Content)) {
      return null;
    }

    return filteringApi.getContentRulesForUrl(documentUrl);
  };
  /**
   * Find CSP rules for request
   * @param tab           Tab
   * @param requestUrl    Request URL
   * @param referrerUrl   Referrer URL
   * @param requestType   Request type (DOCUMENT or SUBDOCUMENT)
   * @returns {Array}     Collection of rules or null
   */


  const getCspRules = function (tab, requestUrl, referrerUrl, requestType) {
    if (frames_frames.shouldStopRequestProcess(tab)) {
      // don't process request
      return null;
    }

    const frameRule = frames_frames.getFrameRule(tab); // @@||example.org^$document or @@||example.org^$urlblock —
    // disables all the $csp rules on all the pages matching the rule pattern.
    // eslint-disable-next-line max-len

    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule
    });

    if (allowlistRule && allowlistRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Urlblock)) {
      return null;
    }

    return filteringApi.getCspRules({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule
    });
  };
  /**
   * Find cookie rules for request
   * @param tab           Tab
   * @param requestUrl    Request URL
   * @param referrerUrl   Referrer URL
   * @param requestType   Request type
   * @returns {Array}     Collection of rules or null
   */


  const getCookieRules = (tab, requestUrl, referrerUrl, requestType) => {
    if (frames_frames.shouldStopRequestProcess(tab)) {
      // Don't process request
      return null;
    }

    const frameRule = frames_frames.getFrameRule(tab);
    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule
    });

    if (allowlistRule && allowlistRule.isDocumentAllowlistRule()) {
      // $cookie rules are not affected by regular exception rules (@@) unless it's a $document exception.
      return null;
    } // Get all $cookie rules matching the specified request


    return filteringApi.getCookieRules({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule
    });
  };
  /**
   * Find replace rules for request
   * @param tab
   * @param requestUrl
   * @param referrerUrl
   * @param requestType
   * @returns {*} Collection of rules or null
   */


  const getReplaceRules = (tab, requestUrl, referrerUrl, requestType) => {
    if (frames_frames.shouldStopRequestProcess(tab)) {
      // don't process request
      return null;
    }

    const frameRule = frames_frames.getFrameRule(tab);
    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule
    });

    if (allowlistRule && allowlistRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Content)) {
      return null;
    }

    return filteringApi.getReplaceRules({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule
    });
  };
  /**
   * Remove query parameters by rules for request
   * @param tab
   * @param requestUrl
   * @param referrerUrl
   * @param requestType
   * @param method
   * @returns {*} Collection of rules or null
   */


  const removeParamFromUrl = (tab, requestUrl, referrerUrl, requestType, method) => {
    if (frames_frames.shouldStopRequestProcess(tab)) {
      // don't process request
      return null;
    } // https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#removeparam-modifier


    const canByAppliedToMethod = method && ['GET', 'OPTIONS', 'HEAD'].includes(method.toUpperCase());

    if (!canByAppliedToMethod) {
      return null;
    }

    const frameRule = frames_frames.getFrameRule(tab);
    const allowlistRule = filteringApi.findAllowlistRule({
      requestUrl,
      frameUrl: referrerUrl,
      requestType: RequestTypes.DOCUMENT,
      frameRule
    });

    if (allowlistRule && allowlistRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.RemoveParam)) {
      return null;
    }

    const rules = filteringApi.getRemoveParamRules({
      requestUrl,
      frameUrl: referrerUrl,
      requestType,
      frameRule
    });
    let result = requestUrl;
    rules.forEach(r => {
      if (!r.isAllowlist()) {
        const ruleResult = r.getAdvancedModifier().removeParameters(result);

        if (ruleResult !== result) {
          filtering_log_browsers.addRemoveParamEvent({
            tab,
            frameUrl: requestUrl,
            requestType,
            rule: r,
            timestamp: Date.now()
          });
        }

        result = ruleResult;
      }
    });

    if (result !== requestUrl) {
      return result;
    }

    return null;
  };
  /**
   * Processes HTTP response.
   * It could do the following:
   * 1. Add event to the filtering log (for DOCUMENT requests)
   * 2. Record page stats (if it's enabled)
   *
   * @param tab Tab object
   * @param requestUrl Request URL
   * @param referrerUrl Referrer URL
   * @param requestType Request type
   * @return {void}
   */


  const processRequestResponse = function (tab, requestUrl, referrerUrl, requestType) {
    // add page view to stats
    if (requestType === RequestTypes.DOCUMENT) {
      const domain = frames_frames.getFrameDomain(tab);

      if (canCollectHitStatsForTab(tab)) {
        hit_stats_browsers.addDomainView(domain);
      }
    }
  };
  /**
   * Request post processing, firing events, add log records etc.
   *
   * @param tab           Tab
   * @param requestUrl    request url
   * @param referrerUrl   referrer url
   * @param requestType   one of RequestType
   * @param requestRule   rule
   * @return {object} Request rule if suitable by its own type and request type or null
   */


  const postProcessRequest = function (tab, requestUrl, referrerUrl, requestType, requestRule) {
    if (requestRule && !requestRule.isAllowlist()) {
      const isRequestBlockingRule = isRequestBlockedByRule(requestRule);
      const isReplaceRule = requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Replace); // Url blocking rules are not applicable to the main_frame

      if (isRequestBlockingRule && requestType === RequestTypes.DOCUMENT) {
        // except rules with $document and $popup modifiers
        const isDocumentRule = requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Document);
        const isPopupBlockingRule = isPopupBlockedByRule(requestRule);

        if (!isDocumentRule && !isPopupBlockingRule) {
          requestRule = null;
        }
      } // Replace rules are processed in content-filtering


      if (isReplaceRule) {
        requestRule = null;
      }

      if (requestRule) {
        listeners.notifyListenersAsync(listeners.ADS_BLOCKED, requestRule, tab, 1);
        const details = {
          tabId: tab.tabId,
          requestUrl,
          referrerUrl,
          requestType
        };
        details.rule = requestRule.getText();
        details.filterId = requestRule.getFilterListId();
        onRequestBlockedChannel.notify(details);
      }
    }

    return requestRule;
  };

  const isCollectingCosmeticRulesHits = tab => {
    /**
     * Edge Legacy browser doesn't support css content attribute for node elements except
     * :before and :after
     * Due to this we can't use cssHitsCounter for edge browser
     */
    if (browserUtils.isEdgeBrowser()) {
      return false;
    }

    return canCollectHitStatsForTab(tab) || filtering_log_browsers.isOpen();
  }; // EXPOSE


  return {
    processGetSelectorsAndScripts,
    checkPageScriptWrapperRequest,
    processShouldCollapse,
    processShouldCollapseMany,
    isRequestBlockedByRule,
    isPopupBlockedByRule,
    getBlockedResponseByRule,
    getRuleForRequest,
    getCspRules,
    getCookieRules,
    getContentRules,
    getReplaceRules,
    removeParamFromUrl,
    processRequestResponse,
    postProcessRequest,
    recordRuleHit,
    onRequestBlocked: onRequestBlockedChannel,
    isCollectingCosmeticRulesHits
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/request-filter.js

















/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */









const RequestFilter = (() => {
  /**
   * Request filter is main class which applies filter rules.
   *
   * @type {Function}
   */
  const RequestFilter = function () {};

  RequestFilter.prototype = {
    getRulesCount() {
      return engine.getRulesCount();
    },

    /**
     * An object with the information on the CSS and ExtendedCss stylesheets which
     * need to be injected into a web page.
     *
     * @typedef {Object} SelectorsData
     * @property {Array.<string>} css Regular CSS stylesheets
     * @property {Array.<string>} extendedCss ExtendedCSS stylesheets
     * @property {boolean} cssHitsCounterEnabled If true - collecting CSS rules hits stats
     * is enabled
     */

    /**
     * Builds CSS for the specified web page.
     * http://adguard.com/en/filterrules.html#hideRules
     *
     * @param {string} url Page URL
     * @param {number} options bitmask
     * @param {boolean} ignoreTraditionalCss flag
     * @param {boolean} ignoreExtCss flag
     * @returns {*} CSS and ExtCss data for the webpage
     */
    getSelectorsForUrl(url, options, ignoreTraditionalCss, ignoreExtCss) {
      const cosmeticResult = engine.getCosmeticResult(url, options);
      const elemhideCss = [...cosmeticResult.elementHiding.generic, ...cosmeticResult.elementHiding.specific];
      const injectCss = [...cosmeticResult.CSS.generic, ...cosmeticResult.CSS.specific];
      const elemhideExtCss = [...cosmeticResult.elementHiding.genericExtCss, ...cosmeticResult.elementHiding.specificExtCss];
      const injectExtCss = [...cosmeticResult.CSS.genericExtCss, ...cosmeticResult.CSS.specificExtCss];
      const collectingCosmeticRulesHits = webRequestService.isCollectingCosmeticRulesHits();

      if (collectingCosmeticRulesHits) {
        const styles = !ignoreTraditionalCss ? cssService.buildStyleSheetHits(elemhideCss, injectCss) : [];
        const extStyles = !ignoreExtCss ? cssService.buildStyleSheetHits(elemhideExtCss, injectExtCss) : [];
        return {
          css: styles,
          extendedCss: extStyles
        };
      }

      const styles = !ignoreTraditionalCss ? cssService.buildStyleSheet(elemhideCss, injectCss, true) : [];
      const extStyles = !ignoreExtCss ? cssService.buildStyleSheet(elemhideExtCss, injectExtCss, false) : [];
      return {
        css: styles,
        extendedCss: extStyles
      };
    },

    /**
     * Builds domain-specific JS injection for the specified page.
     * http://adguard.com/en/filterrules.html#javascriptInjection
     *
     * @param url Page URL
     * @param cosmeticOptions bitmask
     * @returns {CosmeticRule[]} Javascript for the specified URL
     */
    getScriptsForUrl(url, cosmeticOptions) {
      const cosmeticResult = engine.getCosmeticResult(url, cosmeticOptions);
      return cosmeticResult.getScriptRules();
    },

    /**
     * Builds the final output string for the specified page.
     * Depending on the browser we either allow or forbid the new remote rules
     * grep "localScriptRulesService" for details about script source
     *
     * @param {string} url Page URL
     * @param {Object} tab tab
     * @param cosmeticOptions bitmask
     * @returns {string} Script to be applied
     */
    getScriptsStringForUrl(url, tab, cosmeticOptions) {
      const debug = filtering_log_browsers && filtering_log_browsers.isOpen();
      const scriptRules = this.getScriptsForUrl(url, cosmeticOptions);
      const isFirefox = browserUtils.isFirefoxBrowser();
      const selectedScriptRules = scriptRules.filter(scriptRule => {
        // Scriptlets should not be excluded for remote filters
        if (scriptRule.isScriptlet) {
          return true;
        } // User rules should not be excluded from remote filters


        if (scriptRule.filterListId === utils.filters.USER_FILTER_ID) {
          return true;
        }

        const isLocal = local_script_rules_chrome.isLocal(scriptRule.getText());

        if (isLocal) {
          return true;
        }


        return true;
      });

      if (debug) {
        selectedScriptRules.forEach(scriptRule => {
          if (!scriptRule.isGeneric()) {
            filtering_log_browsers.addScriptInjectionEvent({
              tab,
              frameUrl: url,
              requestType: RequestTypes.DOCUMENT,
              rule: scriptRule,
              timestamp: Date.now()
            });
          }
        });
      }

      const scripts = selectedScriptRules.map(scriptRule => scriptRule.getScript({
        debug,
        request: {
          domain: url
        }
      })); // remove repeating scripts

      const scriptsCode = [...new Set(scripts)].join('\r\n');
      return `
            (function () {
                try {
                    ${scriptsCode}
                } catch (ex) {
                    console.error('Error executing AG js: ' + ex);
                }
            })();
            `;
    },

    /**
     * Gets or creates matching result
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     */
    getMatchingResult(matchQuery) {
      const result = engine.matchRequest(matchQuery);

      if (!result) {
        return new tsurlfilter_browser.MatchingResult([], null);
      }

      return result;
    },

    /**
     * Searches for the allowlist rule for the specified pair (url/referrer)
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     *
     * @returns NetworkRule found or null
     */
    findAllowlistRule(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      const basicResult = result.getBasicResult();

      if (basicResult && basicResult.isAllowlist()) {
        return basicResult;
      }

      return null;
    },

    findDocumentRule(documentUrl) {
      return engine.matchFrame(documentUrl);
    },

    /**
     * Searches for stealth allowlist rule for the specified pair (url/referrer)
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     *
     * @returns NetworkRule found or null
     */
    findStealthAllowlistRule(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      return result.stealthRule;
    },

    /**
     * Searches for the filter rule for the specified request.
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     * @returns NetworkRule found or null
     */
    findRuleForRequest(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      return result.getBasicResult();
    },

    /**
     * Searches for content rules for the specified domain
     *
     * @param documentUrl Document URL
     * @returns CosmeticRule[] of content rules
     */
    getContentRulesForUrl(documentUrl) {
      // eslint-disable-next-line max-len
      const cosmeticResult = engine.getCosmeticResult(documentUrl, tsurlfilter_browser.CosmeticOption.CosmeticOptionHtml);
      return cosmeticResult.Html.getRules();
    },

    /**
     * Searches for CSP rules for the specified request
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     * @returns NetworkRule[] of CSP rules for applying to the request or null
     */
    findCspRules(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      return result.getCspRules();
    },

    /**
     * Searches for replace modifier rules
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     * @returns NetworkRule[] matching
     */
    findReplaceRules(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      return result.getReplaceRules();
    },

    /**
     * Searches for cookie rules matching specified request.
     *
     * @param {MatchQuery} matchQuery - {@link MatchQuery}
     * @returns NetworkRule[] matching
     */
    findCookieRules(matchQuery) {
      const result = this.getMatchingResult(matchQuery);
      return result.getCookieRules();
    }

  };
  return RequestFilter;
})();
// EXTERNAL MODULE: ./node_modules/crypto-js/sha256.js
var sha256 = __webpack_require__(8975);
var sha256_default = /*#__PURE__*/__webpack_require__.n(sha256);
;// CONCATENATED MODULE: ./Extension/src/background/utils/lru-cache.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */



/**
 * Cache with maxCacheSize stored in local storage, which automatically clears less recently used entries
 *
 * @param {string} storagePropertyName      Name of the local storage property.
 * @param {number} size                     Max cache size
 */

function LruCache(storagePropertyName, size) {
  const CACHE_SIZE = 1000;
  const maxCacheSize = size || CACHE_SIZE;
  let cache;
  let cacheSize;

  function getCacheFromLocalStorage() {
    let entries = null;

    try {
      const json = storage_localStorage.getItem(storagePropertyName);

      if (json) {
        const data = JSON.parse(json);
        entries = data.map(x => [x.key, x.value]);
      }
    } catch (ex) {
      // ignore
      log.error('Error read from {0} cache, cause: {1}', storagePropertyName, ex);
      storage_localStorage.removeItem(storagePropertyName);
    }

    return new lru.LRUMap(maxCacheSize, entries);
  }

  function saveCacheToLocalStorage() {
    try {
      storage_localStorage.setItem(storagePropertyName, JSON.stringify(cache.toJSON()));
    } catch (ex) {
      log.error('Error save to {0} cache, cause: {1}', storagePropertyName, ex);
    }
  }
  /**
   * Retrieves value from cache and checks if saved data is not expired yet.
   * @param {string} key
   * @returns {null|object} saved data
   */


  function getValue(key) {
    return cache.get(key);
  }

  const saveValue = function (key, data) {
    if (!key) {
      return;
    }

    cache.set(key, data);
    cacheSize += 1;

    if (cacheSize % 20 === 0) {
      saveCacheToLocalStorage();
    }
  };
  /**
   * Clears cache
   */


  const clear = () => {
    cache = new lru.LRUMap(maxCacheSize, null);
    cacheSize = cache.size;
    saveCacheToLocalStorage();
  }; // Load cache


  cache = getCacheFromLocalStorage();
  cacheSize = cache.size;
  return {
    getValue,
    saveValue,
    clear
  };
}
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/safebrowsing/safebrowsing.browsers.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */











/**
 * Initializing SafebrowsingFilter.
 *
 * http://adguard.com/en/how-malware-blocked.html#extension
 */

const safebrowsing = function () {
  // Lazy initialized safebrowsing cache
  const safebrowsingCache = {
    get cache() {
      return lazyGet(safebrowsingCache, 'cache', () => new LruCache('sb-lru-cache'));
    }

  };
  /**
   * Backend requests cache
   */

  const safebrowsingRequestsCache = new lru.LRUMap(1000);
  const suspendedFromProperty = 'safebrowsing-suspended-from';
  /**
   * If we've got an error response from the backend, suspend requests for
   * this time: 40 minutes
   */

  const SUSPEND_TTL = 40 * 60 * 1000;
  const SB_ALLOW_LIST = 'allowlist';
  /**
   * Domain hash length
   */

  const DOMAIN_HASH_LENGTH = 4;

  function isMalwareList(listName) {
    return utils.strings.contains(listName, 'malware');
  }

  function isPhishingList(listName) {
    return utils.strings.contains(listName, 'phishing');
  }
  /**
   * Parses safebrowsing service response
   *
   * @param responseText  Response text
   * @param hashesMap  Hashes hosts map
   * @returns Safebrowsing list or null
   * @private
   */


  function processSbResponse(responseText, hashesMap) {
    if (!responseText || responseText.length > 10 * 1024) {
      return null;
    }

    try {
      let result;
      const lines = responseText.split('\n');

      for (let i = 0; i < lines.length; i += 1) {
        const r = lines[i].split(':');
        const hash = r[2];
        const list = r[0];
        safebrowsingCache.cache.saveValue(hash, list);

        if (!result) {
          const host = hashesMap[hash];

          if (host) {
            result = list;
          }
        }
      }

      return result;
    } catch (ex) {
      log.error('Error parse safebrowsing response, cause {0}', ex);
    }

    return null;
  }
  /**
   * Creates lookup callback parameter
   * @param sbList    Safebrowsing list we've detected or null
   * @returns Safebrowsing list or null if this list is SB_ALLOW_LIST (means that site was allowlisted).
   * @private
   */


  function createResponse(sbList) {
    if (isMalwareList(sbList) || isPhishingList(sbList)) {
      return sbList;
    }

    return null;
  }
  /**
   * Resumes previously suspended work of SafebrowsingFilter
   * @private
   */


  function resumeSafebrowsing() {
    storage_localStorage.removeItem(suspendedFromProperty);
  }
  /**
   * Suspend work of SafebrowsingFilter (in case of backend error)
   * @private
   */


  function suspendSafebrowsing() {
    storage_localStorage.setItem(suspendedFromProperty, Date.now());
  }
  /**
   * Calculates hash for host string
   *
   * @param host
   * @return {string}
   */


  function createHash(host) {
    return sha256_default()(`${host}/`).toString().toUpperCase();
  }
  /**
   * Calculates SHA256 hashes for strings in hosts and then
   * gets prefixes for calculated hashes
   *
   * @param hosts
   * @returns Map object of prefixes
   * @private
   */


  function createHashesMap(hosts) {
    const result = Object.create(null);

    for (let i = 0; i < hosts.length; i += 1) {
      const host = hosts[i];
      const hash = createHash(host);
      result[hash] = host;
    }

    return result;
  }
  /**
   * Checks safebrowsing cache
   *
   * @param hosts List of hosts
   * @returns Safebrowsing list (for blacklisted request) or null
   * @private
   */


  function checkHostsInSbCache(hosts) {
    for (let i = 0; i < hosts.length; i += 1) {
      const sbList = safebrowsingCache.cache.getValue(createHash(hosts[i]));

      if (sbList) {
        return sbList;
      }
    }

    return null;
  }
  /**
   * Extracts hosts from one host.
   * This method returns all sub-domains and IP address of the specified host.
   *
   * @param host Host
   * @returns Array of extracted host names
   * @private
   */


  function extractHosts(host) {
    const hosts = [];

    if (utils.url.isIpv4(host) || utils.url.isIpv6(host)) {
      hosts.push(host);
      return hosts;
    }

    const parts = host.split('.');

    if (parts.length <= 2) {
      hosts.push(host);
    } else {
      for (let i = 0; i <= parts.length - 2; i += 1) {
        hosts.push(utils.strings.join(parts, '.', i, parts.length));
      }
    }

    return hosts;
  }
  /**
   * Access Denied page URL
   *
   * @param requestUrl    Request URL
   * @param referrerUrl   Referrer URL
   * @param sbList        Safebrowsing list
   * @returns page URL
   */


  const getErrorPageURL = function (requestUrl, referrerUrl, sbList) {
    const listName = sbList || 'malware';
    let url = 'pages/safebrowsing.html';
    url += `?malware=${isMalwareList(listName)}`;
    url += `&host=${encodeURIComponent(utils.url.getHost(requestUrl))}`;
    url += `&url=${encodeURIComponent(requestUrl)}`;
    url += `&ref=${encodeURIComponent(referrerUrl)}`;
    return backgroundPage.getURL(url);
  };
  /**
   * Performs lookup to safebrowsing service
   *
   * @param requestUrl        Request URL
   */


  const lookupUrl = async function (requestUrl) {
    const host = utils.url.getHost(requestUrl);

    if (!host) {
      return;
    }

    const hosts = extractHosts(host);

    if (!hosts || hosts.length === 0) {
      return;
    } // try find request url in cache


    let sbList = checkHostsInSbCache(hosts);

    if (sbList) {
      return createResponse(sbList);
    } // check safebrowsing is active


    const now = Date.now();
    const suspendedFrom = storage_localStorage.getItem(suspendedFromProperty) - 0;

    if (suspendedFrom && now - suspendedFrom < SUSPEND_TTL) {
      return;
    }

    const hashesMap = createHashesMap(hosts);
    const hashes = Object.keys(hashesMap);
    let shortHashes = [];

    for (let i = 0; i < hashes.length; i += 1) {
      shortHashes.push(hashes[i].substring(0, DOMAIN_HASH_LENGTH));
    } // Filter already checked hashes


    shortHashes = shortHashes.filter(x => !safebrowsingRequestsCache.get(x));

    if (shortHashes.length === 0) {
      // In case we have not found anything in safebrowsingCache and all short hashes have been checked in
      // safebrowsingRequestsCache - means that there is no need to request backend again
      safebrowsingCache.cache.saveValue(createHash(host), SB_ALLOW_LIST);
      return createResponse(SB_ALLOW_LIST);
    }

    let response;

    try {
      response = await backend.lookupSafebrowsing(shortHashes);
    } catch (e) {
      log.error('Error response from safebrowsing lookup server for {0}', host);
      suspendSafebrowsing();
      return;
    }

    if (response && response.status >= 500) {
      // Error on server side, suspend request
      // eslint-disable-next-line max-len
      log.error('Error response status {0} received from safebrowsing lookup server.', response.status);
      suspendSafebrowsing();
      return;
    }

    if (!response) {
      log.error('Can`t read response from the server');
      return;
    }

    resumeSafebrowsing();
    shortHashes.forEach(x => {
      safebrowsingRequestsCache.set(x, true);
    });
    sbList = SB_ALLOW_LIST;

    if (response.status !== 204) {
      sbList = processSbResponse(response.responseText, hashesMap) || SB_ALLOW_LIST;
    }

    safebrowsingCache.cache.saveValue(createHash(host), sbList);
    return createResponse(sbList);
  };
  /**
   * Checks URL with safebrowsing filter.
   * http://adguard.com/en/how-malware-blocked.html#extension
   *
   * @param requestUrl Request URL
   * @param referrerUrl Referrer URL
   */


  const checkSafebrowsingFilter = async function (requestUrl, referrerUrl) {
    if (!settings.safebrowsingInfoEnabled()) {
      return;
    }

    log.debug('Checking safebrowsing filter for {0}', requestUrl);
    const sbList = await lookupUrl(requestUrl);

    if (!sbList) {
      log.debug('No safebrowsing rule found');
      return;
    }

    log.debug('Following safebrowsing filter has been fired: {0}', sbList);
    return getErrorPageURL(requestUrl, referrerUrl, sbList);
  };
  /**
   * Temporarily allowlist URL
   * Adds URL to trusted sites (this URL will be ignored by safebrowsing filter)
   *
   * @param url URL
   */


  const addToSafebrowsingTrusted = function (url) {
    const host = utils.url.getHost(url);

    if (!host) {
      return;
    }

    safebrowsingCache.cache.saveValue(createHash(host), SB_ALLOW_LIST);
  };
  /**
   * Clears safebrowsing cache
   */


  const clearCache = () => {
    safebrowsingCache.cache.clear();
  };
  /**
   * Subscribes to safebrowsing setting change and clears cache when setting changes
   */


  const init = () => {
    listeners.addSpecifiedListener(listeners.SETTING_UPDATED, (_, {
      propertyName
    }) => {
      if (propertyName === settings.DISABLE_SAFEBROWSING) {
        clearCache();
      }
    });
  }; // Init


  init();
  return {
    checkSafebrowsingFilter,
    lookupUrl,
    addToSafebrowsingTrusted,
    getErrorPageURL,
    extractHosts,
    createHashesMap,
    processSbResponse,
    clearCache
  };
}();

/* harmony default export */ const safebrowsing_browsers = (safebrowsing);
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/safebrowsing/index.js
/**
 * !IMPORTANT!
 * `./safebrowsing.__ABSTRACT_API__` should be replaced during bundling with webpack with proper module
 *  - safebrowsing.adguard-api.js - for adguard-api
 *  - safebrowsing.browsers.js - for other browsers
 */


;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/filters-tags.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 * Filter tags service
 */

const tags = (() => {
  const RECOMMENDED_TAG_ID = 10;
  const PURPOSE_ADS_TAG_ID = 1;
  const PURPOSE_PRIVACY_TAG_ID = 2;
  const PURPOSE_SOCIAL_TAG_ID = 3;
  const PURPOSE_SECURITY_TAG_ID = 4;
  const PURPOSE_ANNOYANCES_TAG_ID = 5;
  const PURPOSE_COOKIES_TAG_ID = 6;
  const PURPOSE_MOBILE_TAG_ID = 19;

  const getTags = function () {
    return subscriptions.getTags();
  };

  const getFilters = function () {
    return subscriptions.getFilters().filter(f => f.filterId !== utils.filters.SEARCH_AND_SELF_PROMO_FILTER_ID);
  };

  const getFiltersByTagId = function (tagId, filters) {
    return filters.filter(f => f.tags.indexOf(tagId) >= 0);
  };

  const getRecommendedFilters = function (filters) {
    return getFiltersByTagId(RECOMMENDED_TAG_ID, filters);
  };

  const isRecommendedFilter = filter => filter.tags.includes(RECOMMENDED_TAG_ID);

  const isMobileFilter = filter => filter.tags.includes(PURPOSE_MOBILE_TAG_ID);

  const getPurposeGroupedFilters = function () {
    const filters = getFilters();
    const adsFilters = getFiltersByTagId(PURPOSE_ADS_TAG_ID, filters);
    const socialFilters = getFiltersByTagId(PURPOSE_SOCIAL_TAG_ID, filters);
    const privacyFilters = getFiltersByTagId(PURPOSE_PRIVACY_TAG_ID, filters);
    const annoyancesFilters = getFiltersByTagId(PURPOSE_ANNOYANCES_TAG_ID, filters);
    const cookiesFilters = getFiltersByTagId(PURPOSE_COOKIES_TAG_ID, filters);
    const securityFilters = getFiltersByTagId(PURPOSE_SECURITY_TAG_ID, filters);
    return {
      ads: adsFilters,
      social: socialFilters,
      privacy: privacyFilters,
      security: securityFilters,
      annoyances: annoyancesFilters,
      cookies: cookiesFilters
    };
  };

  return {
    getTags,
    getPurposeGroupedFilters,
    isRecommendedFilter,
    isMobileFilter,
    getFiltersByTagId,
    getRecommendedFilters
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/filters-categories.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */




/**
 * Filter categories service
 */

const categories = (() => {
  /**
   * @returns {Array.<*>} filters
   */
  const getFilters = function () {
    const result = subscriptions.getFilters().filter(f => {
      return !f.removed;
    });
    const filterTags = tags.getTags();
    result.forEach(f => {
      f.tagsDetails = [];
      f.tags.forEach(tagId => {
        const tagDetails = filterTags.find(tag => {
          return tag.tagId === tagId;
        });

        if (tagDetails) {
          if (tagDetails.keyword.startsWith('reference:')) {
            // Hide 'reference:' tags
            return;
          }

          if (!tagDetails.keyword.startsWith('lang:')) {
            // Hide prefixes except of 'lang:'
            tagDetails.keyword = tagDetails.keyword.substring(tagDetails.keyword.indexOf(':') + 1);
          }

          f.tagsDetails.push(tagDetails);
        }
      });
    });
    return result;
  };
  /**
   * Selects filters by groupId
   *
   * @param groupId
   * @param filters
   * @returns {Array.<SubscriptionFilter>}
   */


  const selectFiltersByGroupId = function (groupId, filters) {
    return filters.filter(filter => filter.groupId === groupId);
  };
  /**
   * Constructs filters metadata for options.html page
   */


  const getFiltersMetadata = function () {
    const groupsMeta = subscriptions.getGroups();
    const filters = getFilters();
    const categories = [];

    for (let i = 0; i < groupsMeta.length; i += 1) {
      const category = groupsMeta[i];
      category.filters = selectFiltersByGroupId(category.groupId, filters);
      categories.push(category);
    }

    return {
      filters,
      categories
    };
  };
  /**
   * If filter has mobile tag we check if platform is mobile, in other cases we do not check
   * @param filter
   * @returns {boolean}
   */


  const doesFilterMatchPlatform = filter => {
    if (tags.isMobileFilter(filter)) {
      return !!prefs.mobile;
    }

    return true;
  };
  /**
   * Returns recommended filters, which meet next requirements
   * 1. filter has recommended tag
   * 2. if filter has language tag, tag should match with user locale
   * 3. filter should correspond to platform mobile or desktop
   * @param groupId
   * @returns {Array} recommended filters by groupId
   */


  const getRecommendedFilterIdsByGroupId = function (groupId) {
    const metadata = getFiltersMetadata();
    const result = [];
    const langSuitableFilters = subscriptions.getLangSuitableFilters();

    for (let i = 0; i < metadata.categories.length; i += 1) {
      const category = metadata.categories[i];

      if (category.groupId === groupId) {
        category.filters.forEach(filter => {
          if (tags.isRecommendedFilter(filter) && doesFilterMatchPlatform(filter)) {
            // get ids intersection to enable recommended filters matching the lang tag
            // only if filter has language
            if (filter.languages && filter.languages.length > 0) {
              if (langSuitableFilters.includes(filter.filterId)) {
                result.push(filter.filterId);
              }
            } else {
              result.push(filter.filterId);
            }
          }
        });
        return result;
      }
    }

    return result;
  };
  /**
   * If group doesn't have enabled property we consider that group is enabled for the first time
   * On first group enable we add and enable recommended filters by groupId
   * On the next calls we just enable group
   * @param {number} groupId
   */


  const enableFiltersGroup = async function (groupId) {
    const group = subscriptions.getGroup(groupId);

    if (group && typeof group.enabled === 'undefined') {
      const recommendedFiltersIds = getRecommendedFilterIdsByGroupId(groupId);
      await application.addAndEnableFilters(recommendedFiltersIds);
    }

    application.enableGroup(groupId);
  };
  /**
   * Disables group
   * @param {number} groupId
   * @param {boolean} drop
   */


  const disableFiltersGroup = function (groupId, drop) {
    application.disableGroup(groupId, drop);
  };

  return {
    getFiltersMetadata,
    enableFiltersGroup,
    disableFiltersGroup
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/settings/default-settings.js

/**
 * Default settings set
 */

const defaultSettings = {
  'general-settings': {
    'allow-acceptable-ads': true,
    'show-blocked-ads-count': !settings.defaultProperties[settings.DISABLE_SHOW_PAGE_STATS],
    'autodetect-filters': !settings.defaultProperties[settings.DISABLE_DETECT_FILTERS],
    'safebrowsing-enabled': !settings.defaultProperties[settings.DISABLE_SAFEBROWSING],
    'filters-update-period': settings.DEFAULT_FILTERS_UPDATE_PERIOD,
    'appearance-theme': settings.defaultProperties[settings.APPEARANCE_THEME]
  },
  'extension-specific-settings': {
    'use-optimized-filters': settings.defaultProperties[settings.USE_OPTIMIZED_FILTERS],
    'collect-hits-count': !settings.defaultProperties[settings.DISABLE_COLLECT_HITS],
    'show-context-menu': !settings.defaultProperties[settings.DISABLE_SHOW_CONTEXT_MENU],
    'show-info-about-adguard': !settings.defaultProperties[settings.DISABLE_SHOW_ADGUARD_PROMO_INFO],
    'show-app-updated-info': !settings.defaultProperties[settings.DISABLE_SHOW_APP_UPDATED_NOTIFICATION],
    'hide-rate-adguard': settings.defaultProperties[settings.HIDE_RATE_BLOCK],
    'user-rules-editor-wrap': settings.defaultProperties[settings.USER_RULES_EDITOR_WRAP]
  },
  'filters': {
    'enabled-groups': [1, 6, 7],
    'enabled-filters': [2, 10],
    'custom-filters': [],
    'user-filter': {
      'rules': '',
      'disabled-rules': '',
      'enabled': true
    },
    'whitelist': {
      'inverted': false,
      'domains': [],
      'inverted-domains': [],
      'enabled': true
    }
  },
  'stealth': {
    'stealth_disable_stealth_mode': settings.defaultProperties[settings.DISABLE_STEALTH_MODE],
    'stealth-hide-referrer': settings.defaultProperties[settings.HIDE_REFERRER],
    'stealth-hide-search-queries': settings.defaultProperties[settings.HIDE_SEARCH_QUERIES],
    'stealth-send-do-not-track': settings.defaultProperties[settings.SEND_DO_NOT_TRACK],
    'stealth-block-webrtc': settings.defaultProperties[settings.BLOCK_WEBRTC],
    'stealth-remove-x-client': settings.defaultProperties[settings.BLOCK_CHROME_CLIENT_DATA],
    'stealth-block-third-party-cookies': settings.defaultProperties[settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES],
    'stealth-block-third-party-cookies-time': settings.defaultProperties[settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME],
    'stealth-block-first-party-cookies': settings.defaultProperties[settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES],
    'stealth-block-first-party-cookies-time': settings.defaultProperties[settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME],
    'block-known-trackers': false,
    'strip-tracking-parameters': false
  }
};
// EXTERNAL MODULE: ./Extension/src/background/settings/validator.js
var settings_validator = __webpack_require__(352);
var validator_default = /*#__PURE__*/__webpack_require__.n(settings_validator);
;// CONCATENATED MODULE: ./Extension/src/background/settings/settings-provider.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */












/**
 * This is standalone validator module precompiled by ajv
 * We use this module for prevent ajv run cached validator function code from string
 */


/**
 * Application settings provider.
 */

const settingsProvider = function () {
  const BACKUP_PROTOCOL_VERSION = '1.0';
  /**
   * Collect enabled filters ids without custom filters
   * @returns {Array}
   */

  const collectEnabledFilterIds = () => {
    const enabledFilters = application.getEnabledFilters();
    return enabledFilters.filter(filter => !filter.customUrl).map(filter => filter.filterId);
  };
  /**
   * Collects data about added custom filters to the extension
   * @returns {CustomFilterInitial} - returns data enough to import custom filter
   */


  const collectCustomFiltersData = () => {
    const customFiltersList = customFilters.getCustomFilters();
    return customFiltersList.map(filter => ({
      customUrl: filter.customUrl,
      enabled: filter.enabled,
      title: filter.name || '',
      trusted: filter.trusted
    }));
  };

  const collectEnabledGroupIds = () => {
    const groups = subscriptions.getGroups();
    return groups.filter(group => group.enabled).map(group => group.groupId);
  };
  /**
   * Loads filters settings section
   */


  const loadFiltersSection = async () => {
    const enabledFilterIds = collectEnabledFilterIds();
    const enabledGroupIds = collectEnabledGroupIds();
    const customFiltersData = collectCustomFiltersData(); // Collect allowlist/blacklist domains, allowlist inverted mode and allowlist enabled state

    const allowlistDomains = allowlist.getAllowlistedDomains() || [];
    const blockListDomains = allowlist.getBlocklistedDomains() || [];
    const defaultAllowlistMode = !!allowlist.isDefaultMode();
    const allowlistEnabled = settings.getAllowlistEnabledState(); // Collect user rules

    const content = await userrules.getUserRulesText();
    const userFilterEnabled = settings.getUserFilterEnabled();
    const section = {
      'filters': {
        'enabled-groups': enabledGroupIds,
        'enabled-filters': enabledFilterIds,
        'custom-filters': customFiltersData,
        'user-filter': {
          'rules': content,
          'disabled-rules': '',
          enabled: userFilterEnabled
        },
        'whitelist': {
          'inverted': !defaultAllowlistMode,
          'domains': allowlistDomains,
          'inverted-domains': blockListDomains,
          'enabled': allowlistEnabled
        }
      }
    };
    return section;
  };
  /**
   * Loads stealth mode settings section
   */


  const loadStealthModeSection = () => {
    const enabledFilterIds = collectEnabledFilterIds();
    const blockKnownTrackers = enabledFilterIds.indexOf(utils.filters.ids.TRACKING_FILTER_ID) >= 0;
    const stripTrackingParameters = enabledFilterIds.indexOf(utils.filters.ids.URL_TRACKING_FILTER_ID) >= 0;
    const section = {
      stealth: {
        'stealth_disable_stealth_mode': settings.getDisableStealthMode(),
        'stealth-hide-referrer': settings.getHideReferrer(),
        'stealth-hide-search-queries': settings.getHideSearchQueries(),
        'stealth-send-do-not-track': settings.getSendDoNotTrack(),
        'stealth-block-webrtc': settings.isWebRTCDisabled(),
        'stealth-remove-x-client': settings.isRemoveXClientData(),
        'stealth-block-third-party-cookies': settings.getSelfDestructThirdPartyCookies(),
        'stealth-block-third-party-cookies-time': settings.getSelfDestructThirdPartyCookiesTime(),
        'stealth-block-first-party-cookies': settings.getSelfDestructFirstPartyCookies(),
        'stealth-block-first-party-cookies-time': settings.getSelfDestructFirstPartyCookiesTime(),
        'block-known-trackers': blockKnownTrackers,
        'strip-tracking-parameters': stripTrackingParameters
      }
    };
    return section;
  };
  /**
   * Loads general settings section
   */


  const loadGeneralSettingsSection = function () {
    const enabledFilterIds = collectEnabledFilterIds(); // TODO update self search settings on filter status change

    const allowAcceptableAds = enabledFilterIds.indexOf(utils.filters.ids.SEARCH_AND_SELF_PROMO_FILTER_ID) >= 0;
    const section = {
      'general-settings': {
        'app-language': backgroundPage.app.getLocale(),
        'allow-acceptable-ads': allowAcceptableAds,
        'show-blocked-ads-count': settings.showPageStatistic(),
        'autodetect-filters': settings.isAutodetectFilters(),
        'safebrowsing-enabled': settings.safebrowsingInfoEnabled(),
        'filters-update-period': settings.getFiltersUpdatePeriod(),
        'appearance-theme': settings.getAppearanceTheme()
      }
    };
    return section;
  };
  /**
   * Loads extension specific settings section
   */


  const loadExtensionSpecificSettingsSection = function () {
    const section = {
      'extension-specific-settings': {
        'use-optimized-filters': settings.isUseOptimizedFiltersEnabled(),
        'collect-hits-count': settings.collectHitsCount(),
        'show-context-menu': settings.showContextMenu(),
        'show-info-about-adguard': settings.isShowInfoAboutAdguardFullVersion(),
        'show-app-updated-info': settings.isShowAppUpdatedNotification(),
        'hide-rate-adguard': settings.isHideRateBlock(),
        'user-rules-editor-wrap': settings.isUserRulesEditorWrap()
      }
    };
    return section;
  };
  /**
   * Applies general section settings to application
   * @param section Section
   */


  const applyGeneralSettingsSection = async function (section) {
    const set = section['general-settings'];
    settings.changeShowPageStatistic(!!set['show-blocked-ads-count']);
    settings.changeAutodetectFilters(!!set['autodetect-filters']);
    settings.changeEnableSafebrowsing(!!set['safebrowsing-enabled']);
    settings.setFiltersUpdatePeriod(set['filters-update-period']);
    settings.setAppearanceTheme(set['appearance-theme']);

    if (set['allow-acceptable-ads']) {
      await application.addAndEnableFilters([utils.filters.ids.SEARCH_AND_SELF_PROMO_FILTER_ID]);
    } else {
      application.disableFilters([utils.filters.ids.SEARCH_AND_SELF_PROMO_FILTER_ID]);
    }
  };
  /**
   * Applies extension specific section settings to application
   * @param section
   */


  const applyExtensionSpecificSettingsSection = function (section) {
    const set = section['extension-specific-settings'];
    settings.changeUseOptimizedFiltersEnabled(!!set['use-optimized-filters']);
    settings.changeCollectHitsCount(!!set['collect-hits-count']);
    settings.changeShowContextMenu(!!set['show-context-menu']);
    settings.changeShowInfoAboutAdguardFullVersion(!!set['show-info-about-adguard']);
    settings.changeShowAppUpdatedNotification(!!set['show-app-updated-info']);
    settings.changeHideRateBlock(!!set['hide-rate-adguard']);
    settings.changeUserRulesEditorWrap(!!set['user-rules-editor-wrap']);
  };
  /**
   * Applies stealth mode section settings to application
   * @param section
   */


  const applyStealthModeSection = async section => {
    const set = section['stealth'];

    if (!set) {
      // use default settings
      return;
    } // set "block webrtc" setting as soon as possible. AG-9980
    // don't set the actual value to avoid requesting permissions


    if (settings.isWebRTCDisabled() !== !!set['stealth-block-webrtc']) {
      settings.setWebRTCDisabled(!!set['stealth-block-webrtc']);
    }

    settings.setDisableStealthMode(!!set['stealth_disable_stealth_mode']);
    settings.setHideReferrer(!!set['stealth-hide-referrer']);
    settings.setHideSearchQueries(!!set['stealth-hide-search-queries']);
    settings.setSendDoNotTrack(!!set['stealth-send-do-not-track']);
    settings.setRemoveXClientData(!!set['stealth-remove-x-client']);
    settings.setSelfDestructThirdPartyCookies(!!set['stealth-block-third-party-cookies']);
    settings.setSelfDestructThirdPartyCookiesTime(set['stealth-block-third-party-cookies-time']);
    settings.setSelfDestructFirstPartyCookies(!!set['stealth-block-first-party-cookies']);
    settings.setSelfDestructFirstPartyCookiesTime(set['stealth-block-first-party-cookies-time']);

    if (set['strip-tracking-parameters']) {
      await application.addAndEnableFilters([utils.filters.ids.URL_TRACKING_FILTER_ID]);
    } else {
      application.disableFilters([utils.filters.ids.URL_TRACKING_FILTER_ID]);
    }
  };
  /**
   * Initial data needed to add custom filter from the scratch
   * @typedef {Object} CustomFilterInitial
   * @property {string} customUrl - url of the custom filter
   * @property {boolean} enabled - state of custom filter
   * @property {number} [filterId] - identifier of the filter
   * @property {boolean} [trusted] - trusted flag of the filter
   * @property {string} [title] - title of the filter
   */

  /**
   * Add a custom filter
   * @param {CustomFilterInitial} customFilterData - initial data of imported custom filter
   * @returns {Promise<any>} SubscriptionFilter
   */


  const addCustomFilter = async customFilterData => {
    const {
      customUrl,
      title,
      trusted,
      enabled
    } = customFilterData;
    const options = {
      title,
      trusted,
      enabled
    };
    const filter = await application.loadCustomFilter(customUrl, options);
    return filter;
  };

  const addCustomFilters = async absentCustomFiltersInitials => {
    const result = []; // eslint-disable-next-line no-restricted-syntax

    for (const customFilterInitial of absentCustomFiltersInitials) {
      try {
        // eslint-disable-next-line no-await-in-loop
        const customFilter = await addCustomFilter(customFilterInitial);
        log.info(`Settings sync: Custom filter was added: ${customFilter.customUrl}`);
        result.push({
          error: null,
          filter: customFilter
        });
      } catch (e) {
        const {
          customUrl
        } = customFilterInitial;
        const message = `Settings sync: Error occurred while downloading: ${customUrl} - ${e.message}`;
        log.info(message);
        result.push({
          error: message
        });
      }
    }

    return result;
  };
  /**
   * Remove existing custom filters before adding new custom filters
   */


  const removeCustomFilters = filterIds => {
    filterIds.forEach(filterId => {
      application.removeFilter(filterId);
    });
    log.info(`Settings sync: Next filters were removed: ${filterIds}`);
  };
  /**
   * Returns filterId which not listed in the filtersToAdd list, but listed in the existingFilters
   * @param existingFilters
   * @param filtersToAdd
   * @returns {array<number>}
   */


  const getCustomFiltersToRemove = (existingFilters, filtersToAdd) => {
    const customUrlsToAdd = filtersToAdd.map(f => f.customUrl);
    const filtersToRemove = existingFilters.filter(f => !customUrlsToAdd.includes(f.customUrl));
    return filtersToRemove.map(f => f.filterId);
  };
  /**
   * Adds custom filters if there were not added one by one to the subscriptions list
   * @param {Array<CustomFilterInitial>} customFiltersInitials
   * @returns {Promise<any>} Promise object which represents array with filters
   */


  const syncCustomFilters = async customFiltersInitials => {
    const presentCustomFilters = customFilters.getCustomFilters();
    const enrichedFiltersInitials = customFiltersInitials.map(filterToAdd => {
      presentCustomFilters.forEach(existingFilter => {
        if (existingFilter.customUrl === filterToAdd.customUrl) {
          filterToAdd.filterId = existingFilter.filterId;
        }
      });
      return filterToAdd;
    });
    const customFiltersToAdd = enrichedFiltersInitials.filter(f => !f.filterId);
    const existingCustomFilters = enrichedFiltersInitials.filter(f => f.filterId);
    const redundantExistingCustomFiltersIds = getCustomFiltersToRemove(presentCustomFilters, customFiltersInitials);

    if (redundantExistingCustomFiltersIds.length > 0) {
      removeCustomFilters(redundantExistingCustomFiltersIds);
    }

    if (customFiltersToAdd.length === 0) {
      return enrichedFiltersInitials;
    }

    const customFiltersAddResult = await addCustomFilters(customFiltersToAdd); // get results without errors, in order to do not enable filters with errors

    const addedCustomFiltersWithoutError = customFiltersAddResult.filter(f => f.error === null).map(f => f.filter);
    const addedCustomFiltersIds = addedCustomFiltersWithoutError.map(f => f.filterId);
    log.info(`Settings sync: Were added custom filters: ${addedCustomFiltersIds}`);
    return [...existingCustomFilters, ...addedCustomFiltersWithoutError];
  };
  /**
   * Enables filters by filterId and disables those filters which were not in the list of enabled filters
   * @param {array<number>} filterIds - ids to enable
   * @returns {Promise<any>}
   */


  const syncEnabledFilters = async filterIds => {
    await application.addAndEnableFilters(filterIds, {
      forceRemote: true
    });
    const enabledFilters = application.getEnabledFilters();
    const filtersToDisable = enabledFilters.filter(enabledFilter => !filterIds.includes(enabledFilter.filterId)).map(filter => filter.filterId);
    application.disableFilters(filtersToDisable);
  };
  /**
   * Enables groups by groupId and disable those groups which were not in the list
   * @param {array<number>} enabledGroups
   * @param {boolean} drop enabled flag
   */


  const syncEnabledGroups = (enabledGroups, drop) => {
    enabledGroups.forEach(groupId => {
      categories.enableFiltersGroup(groupId);
    });
    log.info(`Settings sync: Next groups were enabled: ${enabledGroups}`); // disable groups not listed in the imported list

    const groups = subscriptions.getGroups();
    const groupIdsToDisable = groups.map(group => group.groupId).filter(groupId => !enabledGroups.includes(groupId));
    groupIdsToDisable.forEach(groupId => {
      categories.disableFiltersGroup(groupId, drop);
    });
  };
  /**
   * Applies filters section settings to application
   * @param section Section
   * @param dropGroupsEnabled
   */


  const applyFiltersSection = async function (section, dropGroupsEnabled) {
    const allowlistSection = section.filters['whitelist'] || {};
    const allowlistDomains = allowlistSection.domains || [];
    const blacklistDomains = allowlistSection['inverted-domains'] || []; // Apply allowlist/blacklist domains, allowlist mode and allowlist enabled state

    allowlist.configure({
      allowlist: allowlistDomains,
      blocklist: blacklistDomains,
      mode: !allowlistSection.inverted,
      enabled: typeof allowlistSection.enabled === 'undefined' ? true : !!allowlistSection.enabled
    });
    const userFilterSection = section.filters['user-filter'] || {};
    const userRules = userFilterSection.rules || '';
    const userFilterEnabled = typeof userFilterSection.enabled === 'undefined' ? true : userFilterSection.enabled; // Apply user rules

    settings.setUserFilterEnabled(userFilterEnabled);
    userrules.updateUserRulesText(userRules); // Apply custom filters

    const customFiltersData = section.filters['custom-filters'] || []; // STEP 1 sync custom filters

    const availableCustomFilters = await syncCustomFilters(customFiltersData); // STEP 2 get filters with enabled flag from export data

    const customFilterIdsToEnable = availableCustomFilters.filter(availableCustomFilter => {
      const filterData = customFiltersData.find(filter => {
        if (!filter.customUrl) {
          // eslint-disable-next-line max-len
          throw new Error(`Custom filter should always have custom URL: ${JSON.stringify(filter)}`);
        }

        return filter.customUrl === availableCustomFilter.customUrl;
      });
      return filterData && filterData.enabled;
    }).map(filter => filter.filterId); // STEP 3 sync enabled filters

    const enabledFilterIds = section.filters['enabled-filters'] || [];
    await syncEnabledFilters([...enabledFilterIds, ...customFilterIdsToEnable]); // STEP 4 sync enabled groups

    const enabledGroups = section.filters['enabled-groups'] || [];
    syncEnabledGroups(enabledGroups, dropGroupsEnabled);
  };
  /**
   * Exports settings set in json format
   */


  const loadSettingsBackupJson = async function () {
    const result = {
      'protocol-version': BACKUP_PROTOCOL_VERSION
    };
    const generalSettingsSection = loadGeneralSettingsSection();
    result['general-settings'] = generalSettingsSection['general-settings'];
    const extensionSpecificSettingsSection = loadExtensionSpecificSettingsSection();
    result['extension-specific-settings'] = extensionSpecificSettingsSection['extension-specific-settings'];
    const filtersSection = await loadFiltersSection();
    result['filters'] = filtersSection['filters'];
    const stealthSection = loadStealthModeSection();
    result['stealth'] = stealthSection['stealth'];
    return JSON.stringify(result);
  };
  /**
   * Validates data
   *
   * @param data
   */


  const validateJSON = data => {
    const valid = validator_default()(data);

    if (!valid) {
      log.error((validator_default()).errors);
      return false;
    }

    return true;
  };
  /**
   * Imports settings set from json format
   * @param {string} json
   */


  const applySettingsBackupJson = async function (json) {
    function onFinished(success) {
      if (success) {
        log.info('Settings import finished successfully');
      } else {
        log.error('Error importing settings');
      }

      listeners.notifyListeners(listeners.SETTINGS_UPDATED, success);
    }

    let input = null;

    try {
      input = JSON.parse(json);
    } catch (ex) {
      log.error('Error parsing input json {0}, {1}', json, ex);
      onFinished(false);
      return false;
    }

    if (!input || input['protocol-version'] !== BACKUP_PROTOCOL_VERSION || !validateJSON(input)) {
      log.error('Json input is invalid {0}', json);
      onFinished(false);
      return false;
    }

    try {
      // apply stealth settings as soon as possible due to WebRTC permissions. AG-9980
      await applyStealthModeSection(input);
      await applyGeneralSettingsSection(input);
      applyExtensionSpecificSettingsSection(input);
      await applyFiltersSection(input);
      onFinished(true);
      return true;
    } catch (e) {
      log.error(e);
      onFinished(false);
      return false;
    }
  };
  /**
   * Applies default settings
   *
   * @return {Promise<boolean>}
   */


  const applyDefaultSettings = async () => {
    const input = defaultSettings;

    try {
      await applyGeneralSettingsSection(input);
      applyExtensionSpecificSettingsSection(input);
      await applyFiltersSection(input, true);
      await applyStealthModeSection(input);
      await application.addAndEnableFilters(subscriptions.getLangSuitableFilters());
      return true;
    } catch (e) {
      log.error(e);
      return false;
    }
  }; // EXPOSE


  return {
    /**
     * Loads settings backup json
     */
    loadSettingsBackup: loadSettingsBackupJson,

    /**
     * Applies settings backup json
     */
    applySettingsBackup: applySettingsBackupJson,

    /**
     * Applies default settings json
     */
    applyDefaultSettings
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/update-service.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */












/**
 * Service that manages extension version information and handles
 * extension update. For instance we may need to change storage schema on update.
 */

const applicationUpdateService = function () {
  /**
   * Helper to execute promises one by one
   *
   * @param methods Methods to execute
   * @private
   */
  async function executeMethods(methods) {
    try {
      // eslint-disable-next-line no-restricted-syntax
      for (const method of methods) {
        // eslint-disable-next-line no-await-in-loop
        await method();
      }
    } catch (e) {
      // if catch error while updating, reset settings and reload extension
      await settingsProvider.applyDefaultSettings();
      backgroundPage.runtime.reload();
    }
  }

  function handleUndefinedGroupStatuses() {
    const filters = subscriptions.getFilters();
    const filtersStateInfo = filtersState.getFiltersState();
    const enabledFilters = filters.filter(filter => {
      const {
        filterId
      } = filter;
      return !!(filtersStateInfo[filterId] && filtersStateInfo[filterId].enabled);
    });
    const groupState = filtersState.getGroupsState();
    enabledFilters.forEach(filter => {
      const {
        groupId
      } = filter;

      if (typeof groupState[groupId] === 'undefined') {
        application.enableGroup(filter.groupId);
      }
    });
  }

  function handleDefaultUpdatePeriodSetting() {
    const previousDefaultValue = 48 * 60 * 60 * 1000;
    const currentUpdatePeriod = settings.getFiltersUpdatePeriod();

    if (currentUpdatePeriod === previousDefaultValue) {
      settings.setFiltersUpdatePeriod(settings.DEFAULT_FILTERS_UPDATE_PERIOD);
    }
  }

  function clearCaches() {
    safebrowsing_browsers.clearCache();
  }
  /**
   * From that version we store already converted rule texts in storage
   */


  async function onUpdateRuleConverter() {
    const filtersStateInfo = filtersState.getFiltersState();
    const installedFiltersIds = Object.keys(filtersStateInfo).map(filterId => Number.parseInt(filterId, 10));
    const reloadRulesPromises = installedFiltersIds.map(async filterId => {
      if (filterId === utils.filters.USER_FILTER_ID) {
        return;
      }

      let loadedRulesText = await rulesStorage.read(filterId);

      if (!loadedRulesText) {
        loadedRulesText = [];
      }

      log.info('Reloading and converting {0} rules for filter {1}', loadedRulesText.length, filterId);
      const converted = tsurlfilter_browser.RuleConverter.convertRules(loadedRulesText.join('\n')).split('\n');
      log.debug('Saving {0} rules to filter {1}', converted.length, filterId);
      await rulesStorage.write(filterId, converted);
    });
    await Promise.all(reloadRulesPromises);
  }
  /**
   * Function removes obsolete filters from the storage
   * @returns {Promise<any>}
   */


  async function handleObsoleteFiltersRemoval() {
    const filtersStateInfo = filtersState.getFiltersState();
    const allFiltersMetadata = subscriptions.getFilters();
    const installedFiltersIds = Object.keys(filtersStateInfo).map(filterId => Number.parseInt(filterId, 10));
    const existingFiltersIds = installedFiltersIds.filter(filterId => {
      return allFiltersMetadata.find(f => f.filterId === filterId);
    });
    const filtersIdsToRemove = installedFiltersIds.filter(id => {
      return !existingFiltersIds.includes(id);
    });
    filtersIdsToRemove.forEach(filterId => filtersState.removeFilter(filterId));
    const removePromises = filtersIdsToRemove.map(async filterId => {
      await rulesStorage.remove(filterId);
      log.info(`Filter with id: ${filterId} removed from the storage`);
    });
    await Promise.all(removePromises);
  }
  /**
   * Async returns extension run info
   *
   * {{isFirstRun: boolean, isUpdate: (boolean|*), currentVersion: (Prefs.version|*), prevVersion: *}}
   */


  const getRunInfo = function () {
    const prevVersion = browserUtils.getAppVersion();
    const currentVersion = backgroundPage.app.getVersion();
    browserUtils.setAppVersion(currentVersion);
    const isFirstRun = currentVersion !== prevVersion && !prevVersion;
    const isUpdate = !!(currentVersion !== prevVersion && prevVersion);
    return {
      isFirstRun,
      isUpdate,
      currentVersion,
      prevVersion
    };
  };
  /**
   * Handle extension update
   * @param runInfo   Run info
   */


  const onUpdate = async function (runInfo) {
    const methods = [];
    log.info(`The extension was updated from ${runInfo.prevVersion}`);

    if (browserUtils.isGreaterVersion('3.0.3', runInfo.prevVersion)) {
      methods.push(handleUndefinedGroupStatuses);
    }

    if (browserUtils.isGreaterVersion('3.3.5', runInfo.prevVersion)) {
      methods.push(handleDefaultUpdatePeriodSetting);
    }

    if (browserUtils.isGreaterVersion('4.0.67', runInfo.prevVersion)) {
      methods.push(onUpdateRuleConverter);
    } // On every update remove if necessary obsolete filters


    methods.push(handleObsoleteFiltersRemoval); // On every update clear persisted caches

    methods.push(clearCaches);
    await executeMethods(methods);
  };

  return {
    getRunInfo,
    onUpdate
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/filters/filters-update.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */








/**
 * Filters update service
 */

const filtersUpdate = (() => {
  /**
   * Delay before doing first filters update check -- 5 minutes
   */
  const UPDATE_FILTERS_DELAY = 5 * 60 * 1000; // Get filters update period

  let filtersUpdatePeriod = settings.getFiltersUpdatePeriod();
  /**
   * Gets expires in sec end return in ms
   * If expires was less then minimumExpiresTime or we couldn't parse its value,
   * then return minimumExpiresTime
   * @param {*} expires
   * @returns {number}
   */

  const normalizeExpires = expires => {
    const minimumExpiresSec = 60 * 60;
    expires = Number.parseInt(expires, 10);

    if (Number.isNaN(expires) || expires < minimumExpiresSec) {
      expires = minimumExpiresSec;
    }

    return expires * 1000;
  };
  /**
   * Select filters for update. It depends on the time of last update,
   * on the filter enable status and group enable status
   * @param forceUpdate Force update flag.
   * @param filtersToUpdate Optional array of filters
   * @returns object
   */


  const selectFilterIdsToUpdate = (forceUpdate, filtersToUpdate) => {
    const filterIds = [];
    const customFilterIds = [];
    const filters = filtersToUpdate || subscriptions.getFilters();

    const needUpdate = filter => {
      const {
        lastCheckTime
      } = filter;
      let {
        expires
      } = filter;

      if (!lastCheckTime) {
        return true;
      }

      expires = normalizeExpires(expires);

      if (filtersUpdatePeriod === settings.DEFAULT_FILTERS_UPDATE_PERIOD) {
        return lastCheckTime + expires <= Date.now();
      }

      return lastCheckTime + filtersUpdatePeriod <= Date.now();
    };

    for (let i = 0; i < filters.length; i += 1) {
      const filter = filters[i];
      const group = subscriptions.getGroup(filter.groupId);

      if (filter.installed && filter.enabled && group.enabled) {
        if (forceUpdate || needUpdate(filter)) {
          if (filter.customUrl) {
            customFilterIds.push(filter.filterId);
          } else {
            filterIds.push(filter.filterId);
          }
        }
      }
    }

    return {
      filterIds,
      customFilterIds
    };
  };
  /**
   * Loads filter versions from remote server
   *
   * @param filterIds Filter identifiers
   * @private
   */


  const loadFiltersMetadataFromBackend = async filterIds => {
    if (filterIds.length === 0) {
      return [];
    }

    try {
      const filterMetadataList = await subscriptions.getFiltersMetadata(filterIds);
      log.debug('Retrieved response from server for {0} filters, result: {1} metadata', filterIds.length, filterMetadataList.length);
      return filterMetadataList;
    } catch (e) {
      const errorMessage = `Error retrieved response from server for filters ${filterIds}, cause: ${e.message}`;
      log.error(errorMessage);
      throw new Error(errorMessage);
    }
  };
  /**
   * Loads filter rules
   *
   * @param filterMetadata Filter metadata
   * @param forceRemote Force download filter rules from remote server
   * (if false try to download local copy of rules if it's possible)
   * @private
   */


  async function loadFilterRules(filterMetadata, forceRemote) {
    const filter = subscriptions.getFilter(filterMetadata.filterId);
    filter._isDownloading = true;
    listeners.notifyListeners(listeners.START_DOWNLOAD_FILTER, filter);
    let filterRules;

    try {
      filterRules = await backend.downloadFilterRules(filter.filterId, forceRemote, settings.isUseOptimizedFiltersEnabled());
    } catch (e) {
      log.error('Error retrieving response from the server for filter {0}, cause: {1}:', filter.filterId, e || '');
      delete filter._isDownloading;
      listeners.notifyListeners(listeners.ERROR_DOWNLOAD_FILTER, filter);
      return false;
    }

    log.info('Retrieved response from server for filter {0}, rules count: {1}', filter.filterId, filterRules.length);
    delete filter._isDownloading;
    filter.version = filterMetadata.version;
    filter.lastUpdateTime = filterMetadata.timeUpdated;
    filter.lastCheckTime = forceRemote ? Date.now() : filterMetadata.timeUpdated;
    filter.loaded = true;
    filter.expires = filterMetadata.expires; // notify listeners

    listeners.notifyListeners(listeners.SUCCESS_DOWNLOAD_FILTER, filter);
    listeners.notifyListeners(listeners.UPDATE_FILTER_RULES, filter, filterRules);
    return true;
  }
  /**
   * Loads filters (ony-by-one) from the remote server
   *
   * @param filterMetadataList List of filter metadata to load
   * @private
   */


  const loadFiltersFromBackend = async filterMetadataList => {
    const promises = filterMetadataList.map(async filterMetadata => {
      const result = await loadFilterRules(filterMetadata, true);

      if (result) {
        return filterMetadata.filterId;
      }

      throw new Error('An error occurred');
    });
    const filterIds = await Promise.all(promises);
    return filterIds;
  };
  /**
   * Update filters with custom urls
   *
   * @param customFilterIds
   */


  async function updateCustomFilters(customFilterIds) {
    if (customFilterIds.length === 0) {
      return [];
    }

    const promises = customFilterIds.map(async filterId => {
      const filter = subscriptions.getFilter(filterId);
      const updatedFilterId = await customFilters.updateCustomFilter(filter.customUrl, {});

      if (updatedFilterId) {
        return filter;
      }

      return null;
    });
    const filters = await Promise.all(promises);
    const updatedFilters = filters.filter(f => f);

    if (updatedFilters.length > 0) {
      const filterIdsString = updatedFilters.map(f => f.filterId).join(', ');
      log.info(`Updated custom filters with ids: ${filterIdsString}`);
    }

    return updatedFilters;
  }
  /**
   * Filters update options
   * @typedef {Object} UpdateProps
   * @property [boolean] forceUpdate - if should ignore update period
   * @property [boolean] ignoreVersion - if should ignore filter version, used on switch of optimized filters
   * @property [Filter[]] filters - array of filters to update
   */

  /**
   * Downloads and saves metadata from backend
   * @return {Promise<void>}
   */


  const updateMetadata = async () => {
    log.info('Downloading metadata from backend..');
    await subscriptions.reloadMetadataFromBackend();
    await subscriptions.reloadI18nMetadataFromBackend();
    log.info('Metadata updated from backend');
  };
  /**
   * Checks filters updates.
   *
   * @param [UpdateProps]
   */


  const checkAntiBannerFiltersUpdate = async ({
    forceUpdate,
    ignoreVersion,
    filters
  } = {}) => {
    // Don't update in background if request filter isn't running
    if (!forceUpdate && !antiBannerService.isRunning()) {
      return [];
    } // On force initiated on first run on by user's direct call


    if (forceUpdate && !filters) {
      await updateMetadata();
    }

    log.info('Start checking filters updates'); // Select filters for update

    const toUpdate = selectFilterIdsToUpdate(forceUpdate, filters);
    const filterIdsToUpdate = toUpdate.filterIds;
    const customFilterIdsToUpdate = toUpdate.customFilterIds;
    const totalToUpdate = filterIdsToUpdate.length + customFilterIdsToUpdate.length;

    if (totalToUpdate === 0) {
      log.info('There is no filters to update');
      return [];
    }

    log.info('Checking updates for {0} filters', totalToUpdate);
    /**
     * Loads filters with changed version
     * @param filterMetadataList
     */

    const loadFiltersFromBackendCallback = async filterMetadataList => {
      const filterIds = await loadFiltersFromBackend(filterMetadataList);
      const filters = filterIds.map(subscriptions.getFilter).filter(f => f);
      const customFilters = await updateCustomFilters(customFilterIdsToUpdate);
      return filters.concat(customFilters);
    };
    /**
     * Method is called after we have got server response
     * Now we check filters version and update filter if needed
     * @param filterMetadataList
     * @param forceUpdate
     */


    const selectFilterMetadataListToUpdate = (filterMetadataList, forceUpdate) => {
      const filterMetadataListToUpdate = [];

      for (let i = 0; i < filterMetadataList.length; i += 1) {
        const filterMetadata = filterMetadataList[i];
        const filter = subscriptions.getFilter(filterMetadata.filterId);

        if (filter && filterMetadata) {
          if (forceUpdate || filterMetadata.version && browserUtils.isGreaterVersion(filterMetadata.version, filter.version)) {
            log.info(`Updating filter ${filter.filterId} to version ${filterMetadata.version}`);
            filter.lastUpdateTime = Date.now();
            filterMetadataListToUpdate.push(filterMetadata);
          } else {
            // remember that this filter version was checked
            filter.lastCheckTime = Date.now();
          }
        }
      }

      return filterMetadataListToUpdate;
    }; // Retrieve current filters metadata for update


    const filterMetadataList = await loadFiltersMetadataFromBackend(filterIdsToUpdate);
    const filterMetadataListToUpdate = selectFilterMetadataListToUpdate(filterMetadataList, ignoreVersion);
    const loadedFilters = await loadFiltersFromBackendCallback(filterMetadataListToUpdate);
    return loadedFilters;
  }; // Scheduling job


  let scheduleUpdateTimeoutId;

  function scheduleUpdate() {
    const checkTimeout = 1000 * 60 * 30;

    if (scheduleUpdateTimeoutId) {
      clearTimeout(scheduleUpdateTimeoutId);
    } // don't update filters if filters update period is equal to 0


    if (filtersUpdatePeriod === 0) {
      return;
    }

    scheduleUpdateTimeoutId = setTimeout(async () => {
      try {
        await checkAntiBannerFiltersUpdate();
      } catch (ex) {
        log.error('Error update filters, cause {0}', ex);
      }

      scheduleUpdate();
    }, checkTimeout);
  }
  /**
   * Schedules filters update job
   *
   * @param isFirstRun App first run flag
   * @private
   */


  function scheduleFiltersUpdate(isFirstRun) {
    filtersUpdatePeriod = settings.getFiltersUpdatePeriod(); // First run delay

    if (isFirstRun) {
      setTimeout(checkAntiBannerFiltersUpdate, UPDATE_FILTERS_DELAY, {
        forceUpdate: isFirstRun
      });
    }

    scheduleUpdate();
  }

  return {
    checkAntiBannerFiltersUpdate,
    scheduleFiltersUpdate,
    loadFilterRules
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/filter/antibanner.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */














/**
 * Creating service that manages our filter rules.
 */

const antiBannerService = (() => {
  // Request filter contains all filter rules
  // This class does the actual filtering (checking URLs, constructing CSS/JS to inject, etc)
  let requestFilter = new RequestFilter(); // Service is not initialized yet

  let requestFilterInitTime = 0; // Application is running flag

  let applicationRunning = false; // Application initialized flag (Sets on first call of 'start' method)

  let applicationInitialized = false;
  /**
   * Delay on application updated event
   */

  const APP_UPDATED_NOTIFICATION_DELAY = 60 * 1000;
  const FILTERS_CHANGE_DEBOUNCE_PERIOD = 1000;
  const RELOAD_FILTERS_DEBOUNCE_PERIOD = 1000;
  /**
   * List of events which cause RequestFilter re-creation
   * @type {Array}
   */

  const UPDATE_REQUEST_FILTER_EVENTS = [listeners.UPDATE_FILTER_RULES, listeners.FILTER_ENABLE_DISABLE, listeners.FILTER_GROUP_ENABLE_DISABLE, listeners.ADD_RULES, listeners.REMOVE_RULE];

  const isUpdateRequestFilterEvent = el => UPDATE_REQUEST_FILTER_EVENTS.indexOf(el.event) >= 0;
  /**
   * List of events which cause saving filter rules to the rules storage
   * @type {Array}
   */


  const SAVE_FILTER_RULES_TO_STORAGE_EVENTS = [listeners.UPDATE_FILTER_RULES, listeners.ADD_RULES, listeners.REMOVE_RULE];

  const isSaveRulesToStorageEvent = function (el) {
    return SAVE_FILTER_RULES_TO_STORAGE_EVENTS.indexOf(el.event) >= 0;
  };

  let reloadedRules = false;
  /**
   * AntiBannerService initialize method. Process install, update or simple run.
   * @param options Constructor options
   */

  async function initialize(options) {
    /**
     * Waits and notifies listener with application updated event
     * @param runInfo
     */
    const notifyApplicationUpdated = function (runInfo) {
      setTimeout(() => {
        listeners.notifyListeners(listeners.APPLICATION_UPDATED, runInfo);
      }, APP_UPDATED_NOTIFICATION_DELAY);
    };
    /**
     * This method is called when filter subscriptions have been loaded from remote server.
     * It is used to recreate RequestFilter object.
     */


    const initRequestFilter = async function () {
      subscriptions.loadFiltersVersionAndStateInfo();
      subscriptions.loadGroupsStateInfo();
      await createRequestFilter();
      addFiltersChangeEventListener();
    };
    /**
     * Callback for subscriptions loaded event
     */


    const onSubscriptionLoaded = async function (runInfo) {
      // Subscribe to events which lead to update filters (e.g. switch to optimized and back to default)
      subscribeToFiltersChangeEvents();

      if (runInfo.isFirstRun) {
        // Add event listener for filters change
        addFiltersChangeEventListener(); // Run callback
        // Request filter will be initialized during install

        if (typeof options.onInstall === 'function') {
          await options.onInstall();
        }
      } else if (runInfo.isUpdate) {
        // Updating storage schema on extension update (if needed)
        await applicationUpdateService.onUpdate(runInfo);
        await initRequestFilter(); // Show updated version popup

        notifyApplicationUpdated(runInfo);
      } else {
        // Init RequestFilter object
        await initRequestFilter();
      } // Schedule filters update job


      filtersUpdate.scheduleFiltersUpdate(runInfo.isFirstRun);
    };
    /**
     * Init extension common info.
     */


    const runInfo = await applicationUpdateService.getRunInfo();
    await subscriptions.init();
    await onSubscriptionLoaded(runInfo);
  }
  /**
   * Initialize application (process install or update) . Create and start request filter
   * @param options
   */


  const start = async function (options) {
    if (applicationRunning === true) {
      return;
    }

    applicationRunning = true;

    if (!applicationInitialized) {
      await initialize(options);
      applicationInitialized = true;
      return;
    }

    await createRequestFilter();
  };
  /**
   * Request Filter info
   */


  const getRequestFilterInfo = function () {
    let rulesCount = 0;

    if (requestFilter) {
      rulesCount = requestFilter.getRulesCount();
    }

    return {
      rulesCount
    };
  };
  /**
   * Clear request filter
   */


  const stop = async function () {
    applicationRunning = false;
    requestFilter = new RequestFilter();
    await engine.startEngine([]);
    listeners.notifyListeners(listeners.REQUEST_FILTER_UPDATED, getRequestFilterInfo());
  };
  /**
   * Checks application has been initialized
   * @returns {boolean}
   */


  const isInitialized = function () {
    return applicationInitialized;
  };
  /**
   * Getter for request filter
   */


  const getRequestFilter = function () {
    return requestFilter;
  };
  /**
   * Gets filter by ID.
   * Throws exception if filter not found.
   *
   * @param filterId Filter identifier
   * @returns {*} Filter got from subscriptions.getFilter OR null for no filter found
   * @private
   */


  function getFilterById(filterId) {
    const filterMetadata = subscriptions.getFilter(filterId);

    if (!filterMetadata) {
      log.info(`Filter with id: ${filterId} not found`);
      return null;
    }

    return filterMetadata;
  }
  /**
   * Loads filter from storage (if in extension package) or from backend
   *
   * @param filterId Filter identifier
   * @param forceRemote Force download filter rules from backend
   */


  const addAntiBannerFilter = async (filterId, forceRemote = false) => {
    const filterMetadata = getFilterById(filterId);

    if (!filterMetadata) {
      return false;
    }

    if (filterMetadata.installed && !forceRemote) {
      return true;
    }

    const onFilterLoaded = success => {
      if (success) {
        filterMetadata.installed = true;
        listeners.notifyListeners(listeners.FILTER_ADD_REMOVE, filterMetadata);
      }

      return success;
    };

    if (filterMetadata.loaded && !forceRemote) {
      return onFilterLoaded(true);
    }

    if (filterMetadata.customUrl) {
      const {
        title,
        trusted,
        enabled
      } = filterMetadata;
      await customFilters.updateCustomFilter(filterMetadata.customUrl, {
        title,
        trusted,
        enabled
      });
      return onFilterLoaded(true);
    }

    const result = await filtersUpdate.loadFilterRules(filterMetadata, forceRemote);
    return onFilterLoaded(result);
  };
  /**
   * Reloads filters from backend
   *
   * @private
   */


  async function reloadAntiBannerFilters() {
    await filtersUpdate.checkAntiBannerFiltersUpdate({
      forceUpdate: true,
      ignoreVersion: true
    });
  }
  /**
   * Called when filters were loaded from the storage
   *
   * @param rulesFilterMap Map for populating rules (filterId -> rules collection)
   */


  async function onFiltersLoadedFromStorage(rulesFilterMap) {
    const start = new Date().getTime();
    log.info('Starting request filter initialization..');
    const newRequestFilter = new RequestFilter();

    if (requestFilterInitTime === 0) {
      // Setting the time of request filter very first initialization
      requestFilterInitTime = new Date().getTime();
      listeners.notifyListeners(listeners.APPLICATION_INITIALIZED);
    }
    /**
     * Checks by filter id if filter is enabled and has rules
     * @param rulesFilterMap
     * @param filterId
     * @return {boolean}
     */


    const hasFilterRules = (rulesFilterMap, filterId) => {
      const enabledFilterIds = Object.keys(rulesFilterMap);
      const foundFilterId = enabledFilterIds.find(enabledFilterId => enabledFilterId === filterId);

      if (foundFilterId) {
        const rules = enabledFilterIds[foundFilterId];

        if (rules && rules.length > 0) {
          return true;
        }
      }

      return false;
    };
    /**
     * Checks rulesFilterMap is empty (no one of filters are enabled)
     * @param rulesFilterMap
     * @returns {boolean}
     */


    function isEmptyRulesFilterMap(rulesFilterMap) {
      const enabledFilterIds = Object.keys(rulesFilterMap);

      if (enabledFilterIds.length === 0) {
        return true;
      } // User filter is enabled by default, but it may not contain any rules


      return !hasFilterRules(utils.filters.USER_FILTER_ID);
    }
    /**
     * STEP 3: Called when request filter has been filled with rules.
     * This is the last step of request filter initialization.
     */


    const requestFilterInitialized = function () {
      // Request filter is ready
      requestFilter = newRequestFilter;
      listeners.notifyListeners(listeners.REQUEST_FILTER_UPDATED, getRequestFilterInfo());
      log.info('Finished request filter initialization in {0} ms. Rules count: {1}', new Date().getTime() - start, newRequestFilter.getRulesCount());
      /**
       * If no one of filters is enabled, don't reload rules,
       * except when there are enabled stealth mode rules
       */

      if (isEmptyRulesFilterMap(rulesFilterMap) && !stealthService.hasFilterRules()) {
        return;
      }

      if (newRequestFilter.getRulesCount() === 0 && !reloadedRules) {
        // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/205
        log.info('No rules have been found - checking filter updates');
        reloadAntiBannerFilters();
        reloadedRules = true;
      } else if (newRequestFilter.getRulesCount() > 0 && reloadedRules) {
        log.info('Filters reloaded, deleting reloadRules flag');
        reloadedRules = false;
      }
    };
    /**
     * Fills engine with rules
     */


    const startTSUrlFilterEngine = async () => {
      const lists = [];
      let userFilterList; // eslint-disable-next-line guard-for-in,no-restricted-syntax

      for (let filterId in rulesFilterMap) {
        // To number
        filterId = Number(filterId);
        const isTrustedFilter = subscriptions.isTrustedFilter(filterId);
        const rulesTexts = rulesFilterMap[filterId].join('\n');
        const filterList = new tsurlfilter_browser.StringRuleList(filterId, rulesTexts, false, !isTrustedFilter, !isTrustedFilter);

        if (filterId === utils.filters.USER_FILTER_ID) {
          userFilterList = filterList;
        } else {
          lists.push(filterList);
        }
      } // We push user filter list in the end in order to make possible script rules to work
      // AG-9443


      if (userFilterList) {
        lists.push(userFilterList);
      } // append stealth mode rules


      const stealthModeList = stealthService.getStealthModeRuleList();
      lists.push(stealthModeList);
      await engine.startEngine(lists);
      requestFilterInitialized();
    };

    await startTSUrlFilterEngine();
  }
  /**
   * Create new request filter and add distinct rules from the storage.
   *
   * @private
   */


  async function createRequestFilter() {
    if (applicationRunning === false) {
      return;
    }

    const start = new Date().getTime();
    log.info('Starting loading filter rules from the storage'); // Prepare map for filter rules
    // Map key is filter ID
    // Map value is array with filter rules

    const rulesFilterMap = Object.create(null);
    /**
     * STEP 2: Called when all filter rules have been loaded from storage
     */

    const loadAllFilterRulesDone = async () => {
      log.info('Finished loading filter rules from the storage in {0} ms', new Date().getTime() - start);
      await onFiltersLoadedFromStorage(rulesFilterMap);
    };
    /**
     * Loads filter rules from storage
     *
     * @param filterId Filter identifier
     * @param rulesFilterMap Map for loading rules
     * @returns {*} Deferred object
     */


    const loadFilterRulesFromStorage = async (filterId, rulesFilterMap) => {
      let rulesText = await rulesStorage.read(filterId);

      if (rulesText) {
        if (Number(filterId) === utils.filters.USER_FILTER_ID) {
          rulesText = userrules.convertRules(rulesText);
        }

        rulesFilterMap[filterId] = rulesText;
      }
    };
    /**
     * STEP 1: load all filters from the storage.
     */


    const loadFilterRules = async function () {
      const promises = [];
      const filters = subscriptions.getFilters();

      for (let i = 0; i < filters.length; i += 1) {
        const filter = filters[i];
        const group = subscriptions.getGroup(filter.groupId);

        if (filter.enabled && group.enabled) {
          promises.push(loadFilterRulesFromStorage(filter.filterId, rulesFilterMap));
        }
      }

      if (settings.getUserFilterEnabled()) {
        // get user filter rules from storage
        promises.push(loadFilterRulesFromStorage(utils.filters.USER_FILTER_ID, rulesFilterMap));
      } // Load all filters and then recreate request filter


      await Promise.all(promises);
      await loadAllFilterRulesDone();
    };

    loadFilterRules();
  }
  /**
   * Adds event listener for filters changes.
   * If filter is somehow changed this method checks if we should save changes to the storage
   * and if we should recreate RequestFilter.
   *
   * @private
   */


  function addFiltersChangeEventListener() {
    let filterEventsHistory = [];
    let onFilterChangeTimeout = null;

    const processEventsHistory = async function () {
      const filterEvents = filterEventsHistory.slice(0);
      filterEventsHistory = [];
      onFilterChangeTimeout = null;
      const needCreateRequestFilter = filterEvents.some(isUpdateRequestFilterEvent); // Split by filterId

      const eventsByFilter = Object.create(null);

      for (let i = 0; i < filterEvents.length; i += 1) {
        const filterEvent = filterEvents[i]; // don't add group events

        if (!filterEvent.filter) {
          continue;
        }

        if (!(filterEvent.filter.filterId in eventsByFilter)) {
          eventsByFilter[filterEvent.filter.filterId] = [];
        }

        eventsByFilter[filterEvent.filter.filterId].push(filterEvent);
      }

      const promises = []; // eslint-disable-next-line no-restricted-syntax

      for (const filterId of Object.keys(eventsByFilter)) {
        const needSaveRulesToStorage = eventsByFilter[filterId].some(isSaveRulesToStorageEvent);

        if (!needSaveRulesToStorage) {
          continue;
        } // eslint-disable-next-line no-use-before-define


        const promise = processSaveFilterRulesToStorageEvents(filterId, eventsByFilter[filterId]);
        promises.push(promise);
      }

      if (needCreateRequestFilter) {
        // Rules will be added to request filter lazy,
        // listeners will be notified about REQUEST_FILTER_UPDATED later
        await Promise.all(promises);
        await createRequestFilter();
      } else {
        // Rules are already in request filter, notify listeners
        listeners.notifyListeners(listeners.REQUEST_FILTER_UPDATED, getRequestFilterInfo());
      }
    };

    const processFilterEvent = function (event, filter, rules) {
      filterEventsHistory.push({
        event,
        filter,
        rules
      });

      if (onFilterChangeTimeout !== null) {
        clearTimeout(onFilterChangeTimeout);
      }

      onFilterChangeTimeout = setTimeout(processEventsHistory, FILTERS_CHANGE_DEBOUNCE_PERIOD);
    };

    const processGroupEvent = function (event, group) {
      filterEventsHistory.push({
        event,
        group
      });

      if (onFilterChangeTimeout !== null) {
        clearTimeout(onFilterChangeTimeout);
      }

      onFilterChangeTimeout = setTimeout(processEventsHistory, FILTERS_CHANGE_DEBOUNCE_PERIOD);
    };

    listeners.addListener((event, filter, rules) => {
      switch (event) {
        case listeners.ADD_RULES:
        case listeners.REMOVE_RULE:
        case listeners.UPDATE_FILTER_RULES:
        case listeners.FILTER_ENABLE_DISABLE:
          processFilterEvent(event, filter, rules);
          break;

        default:
          break;
      }
    });
    listeners.addListener((event, group) => {
      switch (event) {
        case listeners.FILTER_GROUP_ENABLE_DISABLE:
          processGroupEvent(event, group);
          break;

        default:
          break;
      }
    });
  }
  /**
   * Saves updated filter rules to the storage.
   *
   * @param filterId Filter id
   * @param events Events (what has changed?)
   * @private
   */


  async function processSaveFilterRulesToStorageEvents(filterId, events) {
    let loadedRulesText = await rulesStorage.read(filterId);

    for (let i = 0; i < events.length; i += 1) {
      if (!loadedRulesText) {
        loadedRulesText = [];
      }

      const event = events[i];
      const eventType = event.event;
      const eventRules = event.rules; // eslint-disable-next-line default-case

      switch (eventType) {
        case listeners.ADD_RULES:
          // ditch empty first editor line while adding rule
          // AG-10727
          loadedRulesText = loadedRulesText.length === 1 && loadedRulesText[0] === '' ? eventRules : loadedRulesText.concat(eventRules);
          log.debug('Add {0} rules to filter {1}', eventRules.length, filterId);
          break;

        case listeners.REMOVE_RULE:
          {
            const actionRule = eventRules[0];
            utils.collections.removeAll(loadedRulesText, actionRule);
            log.debug('Remove {0} rule from filter {1}', actionRule, filterId);
            break;
          }

        case listeners.UPDATE_FILTER_RULES:
          loadedRulesText = eventRules;
          log.debug('Update filter {0} rules count to {1}', filterId, eventRules.length);
          break;
      }
    }

    let rulesTextToSave = loadedRulesText;

    if (Number(filterId) !== utils.filters.USER_FILTER_ID) {
      log.debug('Converting {0} rules for filter {1}', loadedRulesText.length, filterId);
      rulesTextToSave = tsurlfilter_browser.RuleConverter.convertRules(loadedRulesText.join('\n')).split('\n');
    }

    log.debug('Saving {0} rules to filter {1}', rulesTextToSave.length, filterId);
    await rulesStorage.write(filterId, rulesTextToSave); // notify that user rules were saved, to update saving button on options page

    if (Number(filterId) === utils.filters.USER_FILTER_ID) {
      listeners.notifyListeners(listeners.USER_FILTER_UPDATED);
    }
  }
  /**
   * Subscribe to events which lead to filters update.
   * @private
   */


  function subscribeToFiltersChangeEvents() {
    // on USE_OPTIMIZED_FILTERS setting change we need to reload filters
    const onUsedOptimizedFiltersChange = utils.concurrent.debounce(reloadAntiBannerFilters, RELOAD_FILTERS_DEBOUNCE_PERIOD);
    settings.onUpdated.addListener(async setting => {
      switch (setting) {
        case settings.USE_OPTIMIZED_FILTERS:
          onUsedOptimizedFiltersChange();
          break;

        case settings.FILTERS_UPDATE_PERIOD:
          filtersUpdate.scheduleFiltersUpdate();
          break;

        case settings.USER_FILTER_ENABLED:
          await createRequestFilter();
          break;

        default:
          break;
      }
    });
  }
  /**
   * Get request filter initialization time
   * @returns {number}
   */


  const getRequestFilterInitTime = function () {
    return requestFilterInitTime;
  };
  /**
   * Is Application running
   */


  const isRunning = () => applicationRunning;

  return {
    start,
    stop,
    isInitialized,
    isRunning,
    addAntiBannerFilter,
    getRequestFilter,
    getRequestFilterInitTime,
    getRequestFilterInfo
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/application.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */










/**
 * AdGuard application class
 */

const application = (() => {
  /**
   * Timeout for recently updated filters and again enabled filters - 5 minutes
   */
  const ENABLED_FILTERS_SKIP_TIMEOUT = 5 * 60 * 1000;

  const start = async options => {
    await antiBannerService.start(options);
  };

  const stop = async () => {
    await antiBannerService.stop();
  };
  /**
   * Checks application has been initialized
   * @returns {boolean}
   */


  const isInitialized = () => antiBannerService.isInitialized();
  /**
   * Offer filters on extension install, select default filters and filters by locale and country
   */


  const offerFilters = () => {
    // These filters are enabled by default
    const filterIds = [utils.filters.ENGLISH_FILTER_ID, utils.filters.SEARCH_AND_SELF_PROMO_FILTER_ID];

    if (prefs.mobile) {
      filterIds.push(utils.filters.MOBILE_ADS_FILTER_ID);
    }

    const langSuitableFilters = subscriptions.getLangSuitableFilters();
    filterIds.push(...langSuitableFilters);
    return filterIds;
  };
  /**
   * List of enabled filters.
   * User filter and allowlist filter are always enabled so they are excluded.
   *
   * @returns {Array} List of enabled filters
   */


  const getEnabledFilters = () => subscriptions.getFilters().filter(f => f.installed && f.enabled);

  const getEnabledFiltersFromEnabledGroups = () => {
    const filters = subscriptions.getFilters();
    const enabledGroupsIds = subscriptions.getGroups().filter(g => g.enabled).map(g => g.groupId);
    return filters.filter(f => f.enabled && enabledGroupsIds.includes(f.groupId));
  };
  /**
   * Checks if specified filter is enabled
   *
   * @param filterId Filter identifier
   * @returns {*} true if enabled
   */


  const isFilterEnabled = function (filterId) {
    const filter = subscriptions.getFilter(filterId);
    return filter && filter.enabled;
  };
  /**
   * Checks if specified filter is installed (downloaded)
   *
   * @param filterId Filter id
   * @returns {*} true if installed
   */


  const isFilterInstalled = function (filterId) {
    const filter = subscriptions.getFilter(filterId);
    return filter && filter.installed;
  };
  /**
   * Force checks updates for filters if specified or all filters
   *
   * @param {Object[]} [filters] optional list of filters
   */


  const checkFiltersUpdates = async filters => {
    if (filters) {
      // Skip recently downloaded filters
      const outdatedFilters = filters.filter(f => (f.lastCheckTime ? Date.now() - f.lastCheckTime > ENABLED_FILTERS_SKIP_TIMEOUT : true // but always check for updates for custom filters
      ) || f.groupId === ANTIBANNER_GROUPS_ID.CUSTOM_FILTERS_GROUP_ID);

      if (outdatedFilters.length > 0) {
        try {
          const filters = await filtersUpdate.checkAntiBannerFiltersUpdate({
            forceUpdate: true,
            filters: outdatedFilters
          });
          return filters;
        } catch (e) {
          log.error(e.message);
          throw e;
        }
      } else {
        return [];
      }
    } else {
      try {
        const filters = await filtersUpdate.checkAntiBannerFiltersUpdate({
          forceUpdate: true
        });
        return filters;
      } catch (e) {
        log.error(e.message);
        throw e;
      }
    }
  };
  /**
   * Enable group
   * @param {number} groupId filter group identifier
   */


  const enableGroup = function (groupId) {
    const group = subscriptions.getGroup(groupId);

    if (!group || group.enabled) {
      return;
    }

    group.enabled = true;
    listeners.notifyListeners(listeners.FILTER_GROUP_ENABLE_DISABLE, group);
  };
  /**
   * Disable group
   * @param {number} groupId filter group identifier
   * @param {boolean} drop
   */


  const disableGroup = (groupId, drop) => {
    const group = subscriptions.getGroup(groupId);

    if (!group || !group.enabled) {
      return;
    }

    group.enabled = false;

    if (drop) {
      delete group.enabled;
    }

    listeners.notifyListeners(listeners.FILTER_GROUP_ENABLE_DISABLE, group);
  };
  /**
   * Enable filter
   *
   * @param {Number} filterId Filter identifier
   * @param {{forceGroupEnable: boolean}} [options]
   * @returns {boolean} true if filter was enabled successfully
   */


  const enableFilter = (filterId, options) => {
    const filter = subscriptions.getFilter(filterId);

    if (!filter || filter.enabled || !filter.installed) {
      return false;
    }

    filter.enabled = true;
    /**
     * we enable group if it was never enabled or disabled early
     */

    const {
      groupId
    } = filter;
    const forceGroupEnable = options && options.forceGroupEnable;

    if (!subscriptions.groupHasEnabledStatus(groupId) || forceGroupEnable) {
      enableGroup(groupId);
    }

    listeners.notifyListeners(listeners.FILTER_ENABLE_DISABLE, filter);
    return true;
  };
  /**
   * Successively add filters from filterIds and then enable successfully added filters
   * @param filterIds Filter identifiers
   * @param {{forceGroupEnable: boolean, forceRemote: boolean }} [options]
   */


  const addAndEnableFilters = async (filterIds, options) => {
    const enabledFilters = [];

    if (!filterIds || filterIds.length === 0) {
      return enabledFilters;
    }

    filterIds = utils.collections.removeDuplicates(filterIds.slice(0));

    for (let i = 0; i < filterIds.length; i += 1) {
      const filterId = filterIds[i]; // eslint-disable-next-line no-await-in-loop

      const success = await antiBannerService.addAntiBannerFilter(filterId, options && options.forceRemote);

      if (success) {
        const changed = enableFilter(filterId, options);

        if (changed) {
          const filter = subscriptions.getFilter(filterId);
          enabledFilters.push(filter);
        }
      }
    }

    return enabledFilters;
  };
  /**
   * Disables filters by id
   *
   * @param {Array.<Number>} filterIds Filter identifiers
   * @returns {boolean} true if filter was disabled successfully
   */


  const disableFilters = function (filterIds) {
    // Copy array to prevent parameter mutation
    filterIds = utils.collections.removeDuplicates(filterIds.slice(0));

    for (let i = 0; i < filterIds.length; i += 1) {
      const filterId = filterIds[i];
      const filter = subscriptions.getFilter(filterId);

      if (!filter || !filter.enabled || !filter.installed) {
        continue;
      }

      filter.enabled = false;
      listeners.notifyListeners(listeners.FILTER_ENABLE_DISABLE, filter);
    }
  };
  /**
   * Uninstalls filters
   *
   * @param {Array.<Number>} filterIds Filter identifiers
   * @returns {boolean} true if filter was removed successfully
   */


  const uninstallFilters = function (filterIds) {
    // Copy array to prevent parameter mutation
    filterIds = utils.collections.removeDuplicates(filterIds.slice(0));

    for (let i = 0; i < filterIds.length; i += 1) {
      const filterId = filterIds[i];
      const filter = subscriptions.getFilter(filterId);

      if (!filter || !filter.installed) {
        continue;
      }

      log.debug('Uninstall filter {0}', filter.filterId);
      filter.enabled = false;
      filter.installed = false;
      listeners.notifyListeners(listeners.FILTER_ENABLE_DISABLE, filter);
      listeners.notifyListeners(listeners.FILTER_ADD_REMOVE, filter);
    }
  };
  /**
   * Removes filter
   *
   * @param {Number} filterId Filter identifier
   */


  const removeFilter = function (filterId) {
    const filter = subscriptions.getFilter(filterId);

    if (!filter || filter.removed) {
      return;
    }

    if (!filter.customUrl) {
      log.error('Filter {0} is not custom and could not be removed', filter.filterId);
      return;
    }

    log.debug('Remove filter {0}', filter.filterId);
    filter.enabled = false;
    filter.installed = false;
    filter.removed = true;
    listeners.notifyListeners(listeners.FILTER_ENABLE_DISABLE, filter);
    listeners.notifyListeners(listeners.FILTER_ADD_REMOVE, filter);
  };
  /**
   * Loads filter rules from url, then tries to parse header to filter metadata
   * and adds filter object to subscriptions from it.
   * These custom filters will have special attribute customUrl, from there it could be downloaded and updated.
   *
   * @param url custom url, there rules are
   * @param options object containing title of custom filter
   */


  const loadCustomFilter = async function (url, options) {
    log.info('Downloading custom filter from {0}', url);

    if (!url) {
      throw new Error('No url provided');
    }

    const filterId = await customFilters.updateCustomFilter(url, options);

    if (filterId) {
      log.info('Custom filter downloaded');
      const filter = subscriptions.getFilter(filterId); // In case filter is loaded again and was removed before

      delete filter.removed;
      return filter;
    }

    throw new Error('No filter downloaded');
  };

  const loadCustomFilterInfo = async (url, options) => {
    log.info(`Downloading custom filter info from ${url}`);

    if (!url) {
      throw new Error('No url provided');
    }

    const res = await customFilters.getCustomFilterInfo(url, options);

    if (res !== null && res !== void 0 && res.filter) {
      log.info('Custom filter data downloaded');
      return res;
    }

    if (res !== null && res !== void 0 && res.errorAlreadyExists) {
      log.error('Custom filter already exists');
      return {
        error: translator.getMessage('options_antibanner_custom_filter_already_exists')
      };
    }

    if (res !== null && res !== void 0 && res.error) {
      log.error('Error occurred', res.error);
      return res;
    }

    throw new Error('Error occurred during custom filter download');
  };

  return {
    start,
    stop,
    isInitialized,
    offerFilters,
    getEnabledFilters,
    isFilterEnabled,
    isFilterInstalled,
    checkFiltersUpdates,
    addAndEnableFilters,
    disableFilters,
    uninstallFilters,
    removeFilter,
    enableGroup,
    disableGroup,
    loadCustomFilter,
    loadCustomFilterInfo,
    getEnabledFiltersFromEnabledGroups
  };
})();
;// CONCATENATED MODULE: ./Extension/src/background/utils/notifications.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */







/**
 * Object that manages user settings.
 * @constructor
 */

const notifications = function () {
  const VIEWED_NOTIFICATIONS = 'viewed-notifications';
  const LAST_NOTIFICATION_TIME = 'viewed-notification-time';
  const BIRTHDAY_13_ID = 'birthday13';
  const birthday13Notification = {
    id: BIRTHDAY_13_ID,
    locales: {
      en: {
        title: 'AdGuard',
        desc: 'Anniversary Quiz',
        btn: 'Play'
      },
      ru: {
        title: 'Нам 13 лет!',
        desc: 'Отпразднуем?',
        btn: 'Вперёд!'
      },
      es: {
        title: 'Test de cumpleaños',
        desc: 'de AdGuard',
        btn: 'Ponte a prueba'
      },
      de: {
        title: 'AdGuard-Quiz',
        desc: 'zum 13. Geburtstag',
        btn: "Los geht's!"
      },
      fr: {
        title: 'AdGuard fête ses 13',
        desc: 'ans !',
        btn: 'Test festif ici'
      },
      it: {
        title: 'AdGuard celebra i',
        desc: 'suoi 13 anni!',
        btn: 'Test festivo qui'
      },
      ko: {
        title: 'AdGuard 생일 퀴즈',
        btn: '퀴즈 시작'
      },
      zh_cn: {
        title: 'AdGuard 生日会',
        desc: '知识竞赛',
        btn: '我要参加！'
      },
      zh_tw: {
        title: 'AdGuard 生日派對',
        desc: '知識競賽',
        btn: '我要參加！'
      },
      ja: {
        title: 'AdGuard',
        desc: '創業13周年クイズ',
        btn: '答えてみる'
      },
      uk: {
        title: 'Вікторина до дня',
        desc: 'народження AdGuard',
        btn: 'Взяти участь'
      },
      pt_pt: {
        title: 'Quiz de aniversário',
        desc: 'AdGuard',
        btn: 'Teste-se'
      },
      pt_br: {
        title: 'Quiz de aniversário',
        desc: 'AdGuard',
        btn: 'Teste-se'
      },
      ar: {
        title: 'اختبار عيد ميلاد',
        desc: 'AdGuard',
        btn: 'اختبر نفسك'
      },
      be: {
        title: 'Тэст дня нараджэння',
        btn: 'Праверце сябе'
      },
      id: {
        title: 'Kuis ulang tahun',
        desc: 'AdGuard',
        btn: 'Uji dirimu'
      },
      pl: {
        title: 'Quiz urodzinowy',
        desc: 'AdGuard',
        btn: 'Sprawdź się'
      },
      tr: {
        title: 'AdGuard doğum günü',
        desc: 'testi',
        btn: 'Kendini test et'
      },
      vi: {
        title: 'Câu đố sinh nhật',
        desc: 'AdGuard',
        btn: 'Tự kiểm tra'
      }
    },
    text: '',
    url: 'https://adguard.com/forward.html?action=birthday13&app=browser_extension',
    from: '31 May 2022 12:00:00',
    to: '5 June 2022 23:59:00',
    type: 'animated',

    get icons() {
      return lazyGet(birthday13Notification, 'icons', () => ({
        ICON_GREEN: {
          '19': backgroundPage.getURL('assets/icons/b13-on-19.png'),
          '38': backgroundPage.getURL('assets/icons/b13-on-38.png')
        },
        ICON_GRAY: {
          '19': backgroundPage.getURL('assets/icons/b13-off-19.png'),
          '38': backgroundPage.getURL('assets/icons/b13-off-38.png')
        }
      }));
    }

  };
  /**
   * @typedef Notification
   * @type object
   * @property {string} id
   * @property {object} locales
   * @property {string} url
   * @property {string} text
   * @property {string} from
   * @property {string} to
   * @property {string} bgColor;
   * @property {string} textColor;
   * @property {string} badgeBgColor;
   * @property {string} badgeText;
   * @property {string} type;
   */

  const notifications = {
    birthday13: birthday13Notification
  };
  /**
   * Gets the last time a notification was shown.
   * If it was not shown yet, initialized with the current time.
   */

  const getLastNotificationTime = function () {
    let lastTime = storage_localStorage.getItem(LAST_NOTIFICATION_TIME) || 0;

    if (lastTime === 0) {
      lastTime = new Date().getTime();
      storage_localStorage.setItem(LAST_NOTIFICATION_TIME, lastTime);
    }

    return lastTime;
  };

  const normalizeLanguage = locale => {
    if (!locale) {
      return null;
    }

    return locale.toLowerCase().replace('-', '_');
  };
  /**
   * Scans notification locales and returns the one matching navigator.language
   * @param {*} notification notification object
   * @returns {string} matching text or null
   */


  const getNotificationText = function (notification) {
    const language = normalizeLanguage(browser_polyfill_default().i18n.getUILanguage());

    if (!language) {
      return null;
    }

    const languageCode = language.split('_')[0];

    if (!languageCode) {
      return null;
    }

    return notification.locales[language] || notification.locales[languageCode];
  };
  /**
   * Scans notifications list and prepares them to be used (or removes expired)
   */


  const initNotifications = function () {
    const notificationsKeys = Object.keys(notifications);

    for (let i = 0; i < notificationsKeys.length; i += 1) {
      const notificationKey = notificationsKeys[i];
      const notification = notifications[notificationKey];
      notification.text = getNotificationText(notification);
      const to = new Date(notification.to).getTime();
      const expired = new Date().getTime() > to;

      if (!notification.text || expired) {
        // Remove expired and invalid
        delete notifications[notificationKey];
      }
    }
  }; // Prepare the notifications


  initNotifications();
  let currentNotification;
  let notificationCheckTime;
  const checkTimeoutMs = 10 * 60 * 1000; // 10 minutes

  const minPeriod = 30 * 60 * 1000; // 30 minutes

  const DELAY = 30 * 1000; // clear notification in 30 seconds

  let timeoutId;
  /**
   * Marks current notification as viewed
   * @param {boolean} withDelay if true, do this after a 30 sec delay
   */

  const setNotificationViewed = async function (withDelay) {
    if (withDelay) {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => {
        setNotificationViewed(false);
      }, DELAY);
      return;
    }

    if (currentNotification) {
      const viewedNotifications = storage_localStorage.getItem(VIEWED_NOTIFICATIONS) || [];
      const {
        id
      } = currentNotification; // TODO remove if for the next promo action, used for hotfix

      if (!viewedNotifications.includes(BIRTHDAY_13_ID) && window.localStorage.getItem(VIEWED_NOTIFICATIONS) === BIRTHDAY_13_ID) {
        viewedNotifications.push(BIRTHDAY_13_ID);
      }

      if (!viewedNotifications.includes(id)) {
        viewedNotifications.push(id);
        storage_localStorage.setItem(VIEWED_NOTIFICATIONS, viewedNotifications);
        const tab = await tabsApi.getActive();

        if (tab) {
          uiService.updateTabIconAndContextMenu(tab);
        }

        currentNotification = null;
      }
    }
  };
  /**
   * Finds out notification for current time and checks if notification wasn't shown yet
   *
   * @returns {null|Notification} - notification
   */


  const getCurrentNotification = function () {
    // Do not display notification on Firefox
    if (browserUtils.isFirefoxBrowser()) {
      return null;
    }

    const currentTime = new Date().getTime();
    const timeSinceLastNotification = currentTime - getLastNotificationTime();

    if (timeSinceLastNotification < minPeriod) {
      // Just a check to not show the notification too often
      return null;
    } // Check not often than once in 10 minutes


    const timeSinceLastCheck = currentTime - notificationCheckTime;

    if (notificationCheckTime > 0 && timeSinceLastCheck <= checkTimeoutMs) {
      return currentNotification;
    } // Update the last notification check time


    notificationCheckTime = currentTime;
    const notificationsKeys = Object.keys(notifications);
    const viewedNotifications = storage_localStorage.getItem(VIEWED_NOTIFICATIONS) || [];

    for (let i = 0; i < notificationsKeys.length; i += 1) {
      const notificationKey = notificationsKeys[i];
      const notification = notifications[notificationKey];
      const from = new Date(notification.from).getTime();
      const to = new Date(notification.to).getTime();

      if (from < currentTime && to > currentTime && !viewedNotifications.includes(notification.id)) {
        currentNotification = notification;
        return currentNotification;
      }
    }

    currentNotification = null;
    return currentNotification;
  };

  return {
    getCurrentNotification,
    setNotificationViewed
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/utils/filtering-log-window-state.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Object that manages filtering log size and position.
 * @constructor
 */
const filteringLogWindowState = function () {
  const FILTERING_LOG_WINDOW_STATE = 'filtering-log-window-state';

  const setState = windowState => {
    if (!windowState) {
      return;
    }

    localStorage.setItem(FILTERING_LOG_WINDOW_STATE, JSON.stringify(windowState));
  };

  const getState = () => {
    const windowState = localStorage.getItem(FILTERING_LOG_WINDOW_STATE);
    return JSON.parse(windowState);
  };

  return {
    setState,
    getState
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/ui-service.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */



















/**
 * UI service
 */

const uiService = function () {
  const alertStylesUrl = backgroundPage.getURL('/assets/css/alert-popup.css');
  const browserActionTitle = translator.getMessage('name');
  const contextMenuCallbackMappings = {
    'context_block_site_ads': function () {
      openAssistant();
    },
    'context_block_site_element': function () {
      openAssistant(true);
    },
    'context_security_report': async function () {
      const tab = await tabsApi.getActive();

      if (tab) {
        openSiteReportTab(tab.url);
      }
    },
    'context_complaint_website': async function () {
      const tab = await tabsApi.getActive();

      if (tab) {
        openAbuseTab(tab.url);
      }
    },
    'context_site_filtering_on': async function () {
      const tab = await tabsApi.getActive();

      if (tab) {
        unAllowlistTab(tab);
      }
    },
    'context_site_filtering_off': async function () {
      const tab = await tabsApi.getActive();

      if (tab) {
        allowlistTab(tab);
      }
    },
    'context_enable_protection': function () {
      changeApplicationFilteringDisabled(false);
    },
    'context_disable_protection': function () {
      changeApplicationFilteringDisabled(true);
    },
    'context_open_settings': function () {
      openSettingsTab();
    },
    'context_open_log': function () {
      openFilteringLog();
    },
    'context_update_antibanner_filters': function () {
      checkFiltersUpdates();
    }
  };

  const extensionStoreLink = function () {
    let browser = 'chrome';

    if (browserUtils.isOperaBrowser()) {
      browser = 'opera';
    } else if (browserUtils.isFirefoxBrowser()) {
      browser = 'firefox';
    } else if (browserUtils.isEdgeChromiumBrowser()) {
      browser = 'edge';
    }

    const action = `${browser}_store`;
    return `https://adguard.com/forward.html?action=${action}&from=options_screen&app=browser_extension`;
  }();

  const THANKYOU_PAGE_URL = 'https://welcome.adguard.com/v2/thankyou.html';
  /**
   * Update icon for tab
   * @param tab Tab
   * @param options Options for icon or badge values
   */

  async function updateTabIcon(tab, options) {
    let icon;
    let badge;
    let badgeColor = '#555';

    if (tab.tabId === BACKGROUND_TAB_ID) {
      return;
    }

    try {
      if (options) {
        icon = options.icon;
        badge = options.badge;
      } else {
        let blocked;
        let disabled;
        const tabInfo = frames_frames.getFrameInfo(tab);
        disabled = tabInfo.applicationFilteringDisabled;
        disabled = disabled || tabInfo.documentAllowlisted;

        if (!disabled && settings.showPageStatistic()) {
          blocked = tabInfo.totalBlockedTab.toString();
        } else {
          blocked = '0';
        }

        if (disabled) {
          icon = prefs.ICONS.ICON_GRAY;
        } else {
          icon = prefs.ICONS.ICON_GREEN;
        }

        badge = utils.workaround.getBlockedCountText(blocked); // If there's an active notification, indicate it on the badge

        const notification = notifications.getCurrentNotification();

        if (notification) {
          badge = notification.badgeText || badge;
          badgeColor = notification.badgeBgColor || badgeColor;
          const hasSpecialIcons = !!notification.icons;

          if (hasSpecialIcons) {
            if (disabled) {
              icon = notification.icons.ICON_GRAY;
            } else {
              icon = notification.icons.ICON_GREEN;
            }
          }
        }
      }

      await backgroundPage.browserAction.setBrowserAction(tab, icon, badge, badgeColor, browserActionTitle);
    } catch (ex) {
      log.error('Error while updating icon for tab {0}: {1}', tab.tabId, new Error(ex));
    }
  } // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1915


  let lastCallArgs = null;
  let isWorking = false;
  const updateTabIconAsync = utils.concurrent.debounce(async (...args) => {
    if (isWorking) {
      lastCallArgs = args;
      return;
    }

    isWorking = true;
    await updateTabIcon(...args);

    if (lastCallArgs) {
      args = lastCallArgs;
      lastCallArgs = null;
      await updateTabIcon(...args);
    }

    isWorking = false;
  }, 100);
  /**
   * Update extension browser action popup window
   * @param tab - active tab
   */

  function updatePopupStats(tab) {
    const tabInfo = frames_frames.getFrameInfo(tab);

    if (!tabInfo) {
      return;
    }

    runtimeImpl.sendMessage({
      type: 'updateTotalBlocked',
      tabInfo
    }).catch(() => {// throws errors if popup is closed, ignore them
    });
  }

  const updatePopupStatsAsync = utils.concurrent.debounce(tab => {
    updatePopupStats(tab);
  }, 250);
  /**
   * Creates context menu item
   * @param title Title id
   * @param options Create options
   */

  function addMenu(title, options) {
    const createProperties = {
      contexts: ['all'],
      title: translator.getMessage(title)
    };

    if (options) {
      if (options.id) {
        createProperties.id = options.id;
      }

      if (options.parentId) {
        createProperties.parentId = options.parentId;
      }

      if (options.disabled) {
        createProperties.enabled = false;
      }

      if (options.messageArgs) {
        createProperties.title = translator.getMessage(title, options.messageArgs);
      }

      if (options.contexts) {
        createProperties.contexts = options.contexts;
      }

      if ('checkable' in options) {
        createProperties.checkable = options.checkable;
      }

      if ('checked' in options) {
        createProperties.checked = options.checked;
      }
    }

    let callback;

    if (options && options.action) {
      callback = contextMenuCallbackMappings[options.action];
    } else {
      callback = contextMenuCallbackMappings[title];
    }

    if (typeof callback === 'function') {
      createProperties.onclick = callback;
    }

    backgroundPage.contextMenus.create(createProperties);
  }

  function customizeContextMenu(tab) {
    function addSeparator() {
      backgroundPage.contextMenus.create({
        type: 'separator'
      });
    }

    const tabInfo = frames_frames.getFrameInfo(tab);

    if (tabInfo.applicationFilteringDisabled) {
      addMenu('context_site_protection_disabled');
      addSeparator();
      addMenu('context_open_log');
      addMenu('context_open_settings');
      addMenu('context_enable_protection');
    } else if (tabInfo.urlFilteringDisabled) {
      addMenu('context_site_filtering_disabled');
      addSeparator();
      addMenu('context_open_log');
      addMenu('context_open_settings');
      addMenu('context_update_antibanner_filters');
    } else {
      if (tabInfo.documentAllowlisted && !tabInfo.userAllowlisted) {
        addMenu('context_site_exception');
      } else if (tabInfo.canAddRemoveRule) {
        if (tabInfo.documentAllowlisted) {
          addMenu('context_site_filtering_on');
        } else {
          addMenu('context_site_filtering_off');
        }
      }

      addSeparator();

      if (!tabInfo.documentAllowlisted) {
        addMenu('context_block_site_ads');
        addMenu('context_block_site_element', {
          contexts: ['image', 'video', 'audio']
        });
      }

      addMenu('context_security_report');
      addMenu('context_complaint_website');
      addSeparator();
      addMenu('context_update_antibanner_filters');
      addSeparator();
      addMenu('context_open_settings');
      addMenu('context_open_log');
      addMenu('context_disable_protection');
    }
  }

  function customizeMobileContextMenu(tab) {
    const tabInfo = frames_frames.getFrameInfo(tab);

    if (tabInfo.applicationFilteringDisabled) {
      addMenu('popup_site_protection_disabled_android', {
        action: 'context_enable_protection',
        checked: true,
        checkable: true
      });
      addMenu('popup_open_log_android', {
        action: 'context_open_log'
      });
      addMenu('popup_open_settings', {
        action: 'context_open_settings'
      });
    } else if (tabInfo.urlFilteringDisabled) {
      addMenu('context_site_filtering_disabled');
      addMenu('popup_open_log_android', {
        action: 'context_open_log'
      });
      addMenu('popup_open_settings', {
        action: 'context_open_settings'
      });
      addMenu('context_update_antibanner_filters');
    } else {
      addMenu('popup_site_protection_disabled_android', {
        action: 'context_disable_protection',
        checked: false,
        checkable: true
      });

      if (tabInfo.documentAllowlisted && !tabInfo.userAllowlisted) {
        addMenu('popup_in_allowlist_android');
      } else if (tabInfo.canAddRemoveRule) {
        if (tabInfo.documentAllowlisted) {
          addMenu('popup_site_filtering_state', {
            action: 'context_site_filtering_on',
            checkable: true,
            checked: false
          });
        } else {
          addMenu('popup_site_filtering_state', {
            action: 'context_site_filtering_off',
            checkable: true,
            checked: true
          });
        }
      }

      if (!tabInfo.documentAllowlisted) {
        addMenu('popup_block_site_ads_android', {
          action: 'context_block_site_ads'
        });
      }

      addMenu('popup_open_log_android', {
        action: 'context_open_log'
      });
      addMenu('popup_security_report_android', {
        action: 'context_security_report'
      });
      addMenu('popup_open_settings', {
        action: 'context_open_settings'
      });
      addMenu('context_update_antibanner_filters');
    }
  }
  /**
   * Update context menu for tab
   * @param tab Tab
   */


  function updateTabContextMenu(tab) {
    // Isn't supported by Android WebExt
    if (!backgroundPage.contextMenus) {
      return;
    }

    backgroundPage.contextMenus.removeAll();

    if (settings.showContextMenu()) {
      if (prefs.mobile) {
        customizeMobileContextMenu(tab);
      } else {
        customizeContextMenu(tab);
      }

      if (typeof backgroundPage.contextMenus.render === 'function') {
        // In some case we need to manually render context menu
        backgroundPage.contextMenus.render();
      }
    }
  }

  function closeAllPages() {
    tabsApi.forEach(tab => {
      if (tab.url.indexOf(backgroundPage.getURL('')) >= 0) {
        tabsApi.remove(tab.tabId);
      }
    });
  }

  function getPageUrl(page) {
    return backgroundPage.getURL(`pages/${page}`);
  }

  const isAdguardTab = tab => {
    const {
      url
    } = tab;
    let parsedUrl;

    try {
      parsedUrl = new URL(url);
    } catch (e) {
      log.error(e);
      return false;
    }

    const schemeUrl = backgroundPage.app.getUrlScheme();
    return parsedUrl.protocol.indexOf(schemeUrl) > -1;
  };

  const showAlertMessagePopup = async (title, text, alertStyles) => {
    const tab = await tabsApi.getActive();

    if (tab) {
      tabsApi.sendMessage(tab.tabId, {
        type: 'show-alert-popup',
        isAdguardTab: isAdguardTab(tab),
        title,
        text,
        alertStyles
      });
    }
  };
  /**
   * Depending on version numbers select proper message for description
   *
   * @param currentVersion
   * @param previousVersion
   */


  function getUpdateDescriptionMessage(currentVersion, previousVersion) {
    if (browserUtils.getMajorVersionNumber(currentVersion) > browserUtils.getMajorVersionNumber(previousVersion) || browserUtils.getMinorVersionNumber(currentVersion) > browserUtils.getMinorVersionNumber(previousVersion)) {
      return translator.getMessage('options_popup_version_update_description_major');
    }

    return translator.getMessage('options_popup_version_update_description_minor');
  }
  /**
   * Shows application updated popup
   *
   * @param currentVersion
   * @param previousVersion
   * @param alertStyles
   */


  const showApplicationUpdatedPopup = async (currentVersion, previousVersion, alertStyles) => {
    const promoNotification = notifications.getCurrentNotification();

    if (!promoNotification && browserUtils.getMajorVersionNumber(currentVersion) === browserUtils.getMajorVersionNumber(previousVersion) && browserUtils.getMinorVersionNumber(currentVersion) === browserUtils.getMinorVersionNumber(previousVersion)) {
      // In case of no promo available or versions equivalence
      return;
    }

    let offer = translator.getMessage('options_popup_version_update_offer');
    let offerDesc = '';
    let offerButtonHref = 'https://adguard.com/forward.html?action=learn_about_adguard&from=version_popup&app=browser_extension';
    let offerButtonText = translator.getMessage('options_popup_version_update_offer_button_text');

    if (promoNotification) {
      offer = promoNotification.text.title;
      offerDesc = promoNotification.text.desc;
      offerButtonText = promoNotification.text.btn;
      offerButtonHref = `${promoNotification.url}&from=version_popup`;
    }

    const message = {
      type: 'show-version-updated-popup',
      title: translator.getMessage('options_popup_version_update_title_text', {
        current_version: currentVersion
      }),
      description: getUpdateDescriptionMessage(currentVersion, previousVersion),
      changelogHref: 'https://adguard.com/forward.html?action=github_version_popup&from=version_popup&app=browser_extension',
      changelogText: translator.getMessage('options_popup_version_update_changelog_text'),
      showPromoNotification: !!promoNotification,
      offer,
      offerDesc,
      offerButtonText,
      offerButtonHref,
      disableNotificationText: translator.getMessage('options_popup_version_update_disable_notification'),
      alertStyles
    };
    await sendMessageToActiveTab(message);
  };

  let sendMessageTries = 0;
  const MAX_TRIES = 500; // 2500 sec

  const TRIES_TIMEOUT = 5000;
  /**
   * Tries to send message to an active tab,
   * in case of updated app, the content script on not-reloaded tab will not be able to send success callback,
   * so then we postpone the try by TRIES_TIMEOUT.
   *
   * @param message
   */

  const sendMessageToActiveTab = async message => {
    const result = await trySendMessageToActiveTab(message);

    if (result) {
      return;
    }

    sendMessageTries += 1;

    if (sendMessageTries > MAX_TRIES) {
      // Give up trying
      log.warn('Reached max tries on attempts to show application popup');
      return;
    }

    setTimeout(async () => {
      await sendMessageToActiveTab(message);
    }, TRIES_TIMEOUT);
  };

  const trySendMessageToActiveTab = async message => {
    const tab = await tabsApi.getActive();

    if (!tab) {
      return false;
    }

    message.isAdguardTab = isAdguardTab(tab);
    const result = await tabsApi.sendMessage(tab.tabId, message);

    if (!result) {
      return false;
    }

    return true;
  };

  function getFiltersUpdateResultMessage(success, updatedFilters) {
    let title = '';
    let text = '';

    if (success && updatedFilters) {
      if (updatedFilters.length === 0) {
        title = '';
        text = translator.getMessage('options_popup_update_not_found');
      } else {
        title = '';
        text = updatedFilters.sort((a, b) => {
          if (a.groupId === b.groupId) {
            return a.displayNumber - b.displayNumber;
          }

          return a.groupId === b.groupId;
        }).map(filter => `${filter.name}`).join(', ');

        if (updatedFilters.length > 1) {
          text += ` ${translator.getMessage('options_popup_update_filters')}`;
        } else {
          text += ` ${translator.getMessage('options_popup_update_filter')}`;
        }
      }
    } else {
      title = translator.getMessage('options_popup_update_title_error');
      text = translator.getMessage('options_popup_update_error');
    }

    return {
      title,
      text
    };
  }

  function getFiltersEnabledResultMessage(enabledFilters) {
    const title = translator.getMessage('alert_popup_filter_enabled_title');
    const text = [];
    enabledFilters.sort((a, b) => a.displayNumber - b.displayNumber);

    for (let i = 0; i < enabledFilters.length; i += 1) {
      const filter = enabledFilters[i];
      text.push(translator.getMessage('alert_popup_filter_enabled_desc', {
        filter_name: filter.name
      }));
    }

    return {
      title,
      text
    };
  }
  /**
   * Updates extension icon and context menu for tab
   * @param {Object} tab
   * @param {boolean} reloadFrameData
   * @param {boolean} [changeIcon=true]
   */


  const updateTabIconAndContextMenu = function (tab, reloadFrameData, changeIcon = true) {
    if (reloadFrameData) {
      frames_frames.reloadFrameData(tab);
    } // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1917


    if (changeIcon) {
      updateTabIconAsync(tab);
    }

    updateTabContextMenu(tab);
  };

  const openExportRulesTab = function (hash) {
    openTab(getPageUrl(`export.html#${hash}`));
  };
  /**
   * Open settings tab with hash parameters or without them
   * @param anchor
   * @param hashParameters
   */


  const openSettingsTab = function (anchor, hashParameters = {}) {
    if (anchor) {
      hashParameters.anchor = anchor;
    }

    const options = {
      activateSameTab: true,
      hashParameters
    };
    openTab(getPageUrl('options.html'), options);
  };

  const openSiteReportTab = function (url) {
    const domain = utils.url.toPunyCode(utils.url.getDomainName(url));

    if (domain) {
      openTab(`https://adguard.com/site.html?domain=${encodeURIComponent(domain)}&utm_source=extension&aid=16593`);
    }
  };
  /**
   * Generates query string with stealth options information
   * @returns {string}
   */


  const getStealthString = filterIds => {
    const stealthOptions = [{
      queryKey: 'ext_hide_referrer',
      settingKey: settings.HIDE_REFERRER
    }, {
      queryKey: 'hide_search_queries',
      settingKey: settings.HIDE_SEARCH_QUERIES
    }, {
      queryKey: 'DNT',
      settingKey: settings.SEND_DO_NOT_TRACK
    }, {
      queryKey: 'x_client',
      settingKey: settings.BLOCK_CHROME_CLIENT_DATA
    }, {
      queryKey: 'webrtc',
      settingKey: settings.BLOCK_WEBRTC
    }, {
      queryKey: 'third_party_cookies',
      settingKey: settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES,
      settingValueKey: settings.SELF_DESTRUCT_THIRD_PARTY_COOKIES_TIME
    }, {
      queryKey: 'first_party_cookies',
      settingKey: settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES,
      settingValueKey: settings.SELF_DESTRUCT_FIRST_PARTY_COOKIES_TIME
    }];
    const stealthEnabled = !settings.getProperty(settings.DISABLE_STEALTH_MODE);

    if (!stealthEnabled) {
      return `&stealth.enabled=${stealthEnabled}`;
    }

    let stealthOptionsString = stealthOptions.map(option => {
      const {
        queryKey,
        settingKey,
        settingValueKey
      } = option;
      const setting = settings.getProperty(settingKey);
      let settingString;

      if (!setting) {
        return '';
      }

      if (!settingValueKey) {
        settingString = setting;
      } else {
        settingString = settings.getProperty(settingValueKey);
      }

      return `stealth.${queryKey}=${encodeURIComponent(settingString)}`;
    }).filter(string => string.length > 0).join('&'); // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1937

    const isRemoveUrlParamsEnabled = filterIds.includes(ANTIBANNER_FILTERS_ID.URL_TRACKING_FILTER_ID);

    if (isRemoveUrlParamsEnabled) {
      stealthOptionsString = `${stealthOptionsString}&stealth.strip_url=true`;
    }

    return `&stealth.enabled=${stealthEnabled}&${stealthOptionsString}`;
  };
  /**
   * Generates query string with browsing security information
   * @returns {string}
   */


  const getBrowserSecurityString = () => {
    const isEnabled = !settings.getProperty(settings.DISABLE_SAFEBROWSING);
    return `&browsing_security.enabled=${isEnabled}`;
  };
  /**
   * Appends hash parameters if they exists
   * @param rowUrl
   * @param hashParameters
   * @returns {string} prepared url
   */


  const appendHashParameters = (rowUrl, hashParameters) => {
    if (!hashParameters) {
      return rowUrl;
    }

    if (rowUrl.indexOf('#') > -1) {
      log.warn(`Hash parameters can't be applied to the url with hash: '${rowUrl}'`);
      return rowUrl;
    }

    let hashPart;
    const {
      anchor
    } = hashParameters;

    if (anchor) {
      delete hashParameters[anchor];
    }

    const hashString = Object.keys(hashParameters).map(key => `${key}=${hashParameters[key]}`).join('&');

    if (hashString.length <= 0) {
      hashPart = anchor && anchor.length > 0 ? `#${anchor}` : '';
      return rowUrl + hashPart;
    }

    hashPart = anchor && anchor.length > 0 ? `replacement=${anchor}&${hashString}` : hashString;
    hashPart = encodeURIComponent(hashPart);
    return `${rowUrl}#${hashPart}`;
  };

  const openTab = async (url, options = {}) => {
    const {
      activateSameTab,
      inBackground,
      inNewWindow,
      type,
      hashParameters,
      width,
      height,
      top,
      left,
      isFullscreen
    } = options;
    url = appendHashParameters(url, hashParameters);

    const onTabFound = async tab => {
      if (tab.url !== url) {
        await tabsApi.reload(tab.tabId, url);
      }

      if (!inBackground) {
        await tabsApi.activate(tab.tabId);
      }

      return tab;
    };

    url = utils.strings.contains(url, '://') ? url : backgroundPage.getURL(url);
    const tabs = await tabsApi.getAll(); // try to find between opened tabs

    if (activateSameTab) {
      for (let i = 0; i < tabs.length; i += 1) {
        const tab = tabs[i];

        if (utils.url.urlEquals(tab.url, url)) {
          return onTabFound(tab);
        }
      }
    }

    const tab = await tabsApi.create({
      url,
      type: type || 'normal',
      active: !inBackground,
      inNewWindow,
      width,
      height,
      top,
      left,
      isFullscreen
    });
    return tab;
  };
  /**
   * Opens site complaint report tab
   * https://github.com/AdguardTeam/ReportsWebApp#pre-filling-the-app-with-query-parameters
   * @param url
   */


  const openAbuseTab = function (url) {
    let browser;
    let browserDetails;
    const supportedBrowsers = ['Chrome', 'Firefox', 'Opera', 'Safari', 'IE', 'Edge'];

    if (supportedBrowsers.includes(prefs.browser)) {
      browser = prefs.browser;
    } else {
      browser = 'Other';
      browserDetails = prefs.browser;
    }

    const filterIds = application.getEnabledFiltersFromEnabledGroups().map(filter => filter.filterId);
    openTab(`https://reports.adguard.com/new_issue.html?product_type=Ext&product_version=${encodeURIComponent(backgroundPage.app.getVersion())}&browser=${encodeURIComponent(browser)}${browserDetails ? `&browser_detail=${encodeURIComponent(browserDetails)}` : ''}&url=${encodeURIComponent(url)}&filters=${encodeURIComponent(filterIds.join('.'))}${getStealthString(filterIds)}${getBrowserSecurityString()}`);
  };

  const openFilteringLog = async function (tabId) {
    const FILTERING_LOG_PAGE = 'filtering-log.html';
    const windowState = filteringLogWindowState.getState();
    const options = {
      activateSameTab: true,
      type: 'popup',
      ...windowState
    };

    if (!tabId) {
      const tab = await tabsApi.getActive();

      if (tab) {
        const {
          tabId
        } = tab;
        await openTab(getPageUrl(FILTERING_LOG_PAGE) + (tabId ? `#${tabId}` : ''), options);
      }

      return;
    }

    await openTab(getPageUrl(FILTERING_LOG_PAGE) + (tabId ? `#${tabId}` : ''), options);
  };
  /**
   * Opens user rules editor in the separate window in fullscreen
   * @return {Promise<void>}
   */


  const openFullscreenUserRules = async () => {
    const theme = settings.getProperty('appearance-theme');
    const FULLSCREEN_USER_RULES_PAGE = `fullscreen-user-rules.html?theme=${theme}`;
    const options = {
      activateSameTab: true,
      inNewWindow: true
    };
    await openTab(getPageUrl(FULLSCREEN_USER_RULES_PAGE), options);
  };

  const openThankYouPage = async () => {
    const params = browserUtils.getExtensionParams();
    params.push(`_locale=${encodeURIComponent(backgroundPage.app.getLocale())}`);
    const thankyouUrl = `${THANKYOU_PAGE_URL}?${params.join('&')}`; // TODO move url in constants

    const filtersDownloadUrl = getPageUrl('filter-download.html');
    const tabs = await tabsApi.getAll(); // Finds the filter-download page and reload it within the thank-you page URL

    for (let i = 0; i < tabs.length; i += 1) {
      const tab = tabs[i];

      if (tab.url === filtersDownloadUrl) {
        // In YaBrowser don't activate found page
        if (!browserUtils.isYaBrowser()) {
          tabsApi.activate(tab.tabId);
        }

        tabsApi.reload(tab.tabId, thankyouUrl);
        return;
      }
    }

    await openTab(thankyouUrl);
  };

  const openExtensionStore = async function () {
    await openTab(extensionStoreLink);
  };

  const openFiltersDownloadPage = function () {
    openTab(getPageUrl('filter-download.html'), {
      inBackground: browserUtils.isYaBrowser()
    });
  };

  const openCustomFiltersModal = async (url, title) => {
    let path = 'options.html#filters?group=0';

    if (title) {
      path += `&title=${title}`;
    }

    path += `&subscribe=${encodeURIComponent(url)}`;
    const tab = await openTab(getPageUrl(path), {
      activateSameTab: true
    });
    await tabsApi.reload(tab.tabId);
  };

  const allowlistTab = function (tab) {
    const tabInfo = frames_frames.getFrameInfo(tab);
    allowlist.allowlistUrl(tabInfo.url);
    updateTabIconAndContextMenu(tab, true);
    tabsApi.reload(tab.tabId);
  };

  const unAllowlistTab = function (tab) {
    const tabInfo = frames_frames.getFrameInfo(tab);
    userrules.unAllowlistFrame(tabInfo);
    updateTabIconAndContextMenu(tab, true);
    tabsApi.reload(tab.tabId);
  };

  const changeApplicationFilteringDisabled = async function (disabled) {
    settings.changeFilteringDisabled(disabled);
    const tab = await tabsApi.getActive();

    if (tab) {
      // third arg is 'false' for no icon change to avoid icon blink
      updateTabIconAndContextMenu(tab, true, false);
      tabsApi.reload(tab.tabId);
    }
  };
  /**
   * Checks filters updates and returns updated filter
   * @param {Object[]} [filters] optional list of filters
   * @param {boolean} [showPopup = true] show update filters popup
   * @return {Object[]} [filters] list of updated filters
   */


  const checkFiltersUpdates = async (filters, showPopup = true) => {
    const showPopupEvent = listeners.UPDATE_FILTERS_SHOW_POPUP;

    try {
      const updatedFilters = await application.checkFiltersUpdates(filters);

      if (showPopup) {
        listeners.notifyListeners(showPopupEvent, true, updatedFilters);
        listeners.notifyListeners(listeners.FILTERS_UPDATE_CHECK_READY, updatedFilters);
      } else if (updatedFilters && updatedFilters.length > 0) {
        const updatedFilterStr = updatedFilters.map(f => `Filter ID: ${f.filterId}`).join(', ');
        log.info(`Filters were auto updated: ${updatedFilterStr}`);
      }

      return updatedFilters;
    } catch (e) {
      if (showPopup) {
        listeners.notifyListeners(showPopupEvent, false);
        listeners.notifyListeners(listeners.FILTERS_UPDATE_CHECK_READY);
      }

      return [];
    }
  };

  const getAssistantToken = (() => {
    const assistantToken = nanoid();
    return () => {
      return assistantToken;
    };
  })();

  const initAssistant = async selectElement => {
    const options = {
      addRuleCallbackName: MESSAGE_TYPES.CONTENT_SCRIPT_ADD_USER_RULE,
      selectElement,
      token: getAssistantToken()
    }; // init assistant

    const tab = await tabsApi.getActive();

    if (tab) {
      tabsApi.sendMessage(tab.tabId, {
        type: 'initAssistant',
        options
      });
    }
  };
  /**
   * The `openAssistant` function uses the `tabs.executeScript` function to inject
   * the Assistant code into a page without using messaging.
   * We do it dynamically and not include assistant file into the default content scripts
   * in order to reduce the overall memory usage.
   *
   * @param {boolean} selectElement - if true select the element on which the Mousedown event was
   */


  const openAssistant = async selectElement => {
    // Load Assistant code to the active tab immediately
    await tabsApi.executeScriptFile(null, {
      file: '/pages/assistant.js'
    });
    await initAssistant(selectElement);
  };

  const init = async () => {
    const response = await fetch(alertStylesUrl);
    const alertStyles = await response.text(); // update icon on event received

    listeners.addListener((event, tab, reset) => {
      if (event !== listeners.UPDATE_TAB_BUTTON_STATE || !tab) {
        return;
      }

      let options;

      if (reset) {
        options = {
          icon: prefs.ICONS.ICON_GREEN,
          badge: ''
        };
      }

      updateTabIconAsync(tab, options);
    }); // Update tab icon and context menu while loading

    tabsApi.onUpdated.addListener(async tab => {
      const {
        tabId
      } = tab; // BrowserAction is set separately for each tab

      updateTabIconAsync(tab);
      const aTab = await tabsApi.getActive();

      if (aTab) {
        if (aTab.tabId !== tabId) {
          return;
        } // ContextMenu is set for all tabs, so update it only for current tab


        updateTabContextMenu(aTab);
      }
    }); // Update tab icon and context menu on active tab changed

    tabsApi.onActivated.addListener(tab => {
      updateTabIconAndContextMenu(tab, true);
    }); // Update icon and popup stats on ads blocked

    listeners.addListener(async (event, rule, tab, blocked) => {
      if (event !== listeners.ADS_BLOCKED || !tab) {
        return;
      }

      pageStats.updateStats(rule.getFilterListId(), blocked, new Date());
      const tabBlocked = frames_frames.updateBlockedAdsCount(tab, blocked);

      if (tabBlocked === null) {
        return;
      }

      updateTabIconAsync(tab);
      const activeTab = await tabsApi.getActive();

      if (activeTab) {
        if (tab.tabId === activeTab.tabId) {
          updatePopupStatsAsync(activeTab);
        }
      }
    }); // Update context menu on change user settings

    settings.onUpdated.addListener(async setting => {
      if (setting === settings.DISABLE_SHOW_CONTEXT_MENU) {
        const tab = await tabsApi.getActive();

        if (tab) {
          updateTabContextMenu(tab);
        }
      }
    }); // Update tab icon and context menu on application initialization

    listeners.addListener(async event => {
      if (event === listeners.APPLICATION_INITIALIZED) {
        const tab = await tabsApi.getActive();

        if (tab) {
          updateTabIconAndContextMenu(tab);
        }
      }
    }); // on application updated event

    listeners.addListener((event, info) => {
      if (event === listeners.APPLICATION_UPDATED) {
        if (settings.isShowAppUpdatedNotification()) {
          showApplicationUpdatedPopup(info.currentVersion, info.prevVersion, alertStyles);
        }
      }
    }); // on filter auto-enabled event

    listeners.addListener((event, enabledFilters) => {
      if (event === listeners.ENABLE_FILTER_SHOW_POPUP) {
        const result = getFiltersEnabledResultMessage(enabledFilters);
        showAlertMessagePopup(result.title, result.text, alertStyles);
      }
    }); // on filter enabled event

    listeners.addListener((event, payload) => {
      switch (event) {
        case listeners.FILTER_ENABLE_DISABLE:
          if (payload.enabled) {
            checkFiltersUpdates([payload], false);
          }

          break;

        case listeners.FILTER_GROUP_ENABLE_DISABLE:
          if (payload.enabled && payload.filters) {
            const enabledFilters = payload.filters.filter(f => f.enabled);
            checkFiltersUpdates(enabledFilters, false);
          }

          break;

        default:
          break;
      }
    }); // on filters updated event

    listeners.addListener((event, success, updatedFilters) => {
      if (event === listeners.UPDATE_FILTERS_SHOW_POPUP) {
        const result = getFiltersUpdateResultMessage(success, updatedFilters);
        showAlertMessagePopup(result.title, result.text, alertStyles);
      }
    }); // close all page on unload

    unload.when(closeAllPages);
  };

  return {
    init,
    openExportRulesTab,
    openSettingsTab,
    openSiteReportTab,
    openFilteringLog,
    openFullscreenUserRules,
    openThankYouPage,
    openExtensionStore,
    openFiltersDownloadPage,
    openCustomFiltersModal,
    openAbuseTab,
    updateTabIconAndContextMenu,
    allowlistTab,
    unAllowlistTab,
    changeApplicationFilteringDisabled,
    checkFiltersUpdates,
    openAssistant,
    openTab,
    showAlertMessagePopup,
    getAssistantToken
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/startup.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */










/**
 * Extension initialize logic. Called from start.js
 */

const startup = async function () {
  async function onLocalStorageLoaded() {
    log.info('Starting adguard... Version: {0}. Id: {1}', backgroundPage.app.getVersion(), backgroundPage.app.getId()); // Initialize popup button

    backgroundPage.browserAction.setPopup({
      popup: backgroundPage.getURL('pages/popup.html')
    }); // Set uninstall page url
    // eslint-disable-next-line max-len

    const uninstallUrl = 'https://adguard.com/forward.html?action=adguard_uninstal_ext&from=background&app=browser_extension';

    try {
      await browser_polyfill_default().runtime.setUninstallURL(uninstallUrl);
    } catch (e) {
      log.error(e);
    }

    allowlist.init();
    filtering_log_browsers.init();
    await uiService.init();
    stealthService.init();
    /**
     * Start application
     */

    application.start({
      async onInstall() {
        // Process installation

        /**
         * Show UI installation page
         */
        uiService.openFiltersDownloadPage(); // Retrieve filters and install them

        const filterIds = application.offerFilters();
        await application.addAndEnableFilters(filterIds); // enable language-specific group by default

        await application.enableGroup(ANTIBANNER_GROUPS_ID.LANGUAGE_FILTERS_GROUP_ID);
      }

    });
  }

  await rulesStorage.init();
  await storage_localStorage.init();
  onLocalStorageLoaded();
};
;// CONCATENATED MODULE: ./Extension/src/background/start.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


/**
 * Extension startup entry point
 */

const start = () => {
  log.info('Initializing adguard');
  startup();
};
// EXTERNAL MODULE: ./node_modules/core-js/modules/es.typed-array.set.js
var es_typed_array_set = __webpack_require__(7168);
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/cookie-service.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */




/**
 * Returns cookie rules matching request details
 *
 * @param tab
 * @param url
 * @param referrer
 * @return {NetworkRule[]}
 */

const getCookieRules = (tab, url, referrer) => {
  return webRequestService.getCookieRules(tab, url, referrer, RequestTypes.DOCUMENT);
};
/**
 * Returns cookie rules data for content script
 *
 * Steps:
 * - content script requests matching cookie rules for the frame(in which this script is executed)
 * - service returns matching set of rules data to content script
 * - the rules are applied with TSUrlFilterContentScript.CookieController
 * - filtering log receives callback with applied rules data
 *
 * The important point is:
 * - there is no way to run cookie controller script via chrome.tabs.executeScript cause one only could be executed
 * for all frames or main frame only. But it's not correct cause there should be different rules
 * for each frame.
 *
 * @param tab
 * @param url
 * @param referrer
 * @returns {Array|null} serialized rules data
 */

const getCookieRulesDataForContentScript = (tab, url, referrer) => {
  const cookieRules = getCookieRules(tab, url, referrer);

  if (!cookieRules) {
    return null;
  }

  const blockingRules = cookieRules.filter(rule => {
    const cookieModifier = rule.getAdvancedModifier();
    return !cookieModifier.getSameSite() && !cookieModifier.getMaxAge();
  });
  return blockingRules.map(rule => {
    return {
      ruleText: rule.getText(),
      match: rule.getAdvancedModifierValue(),
      isThirdParty: rule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.ThirdParty),
      filterId: rule.getFilterListId(),
      isAllowlist: rule.isAllowlist()
    };
  });
};
/**
 * Cookie filtering service
 */

const cookieService = new tsurlfilter_browser.CookieFiltering(filtering_log_browsers);
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/headers-service.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */





/**
 * Returns $removeheader rules matching request details
 *
 * @param tab
 * @param url
 * @param referrer
 * @return {NetworkRule[]}
 */

const getRemoveHeaderRules = (tab, url, referrer) => {
  return filteringApi.getRemoveHeaderRules({
    requestUrl: url,
    frameUrl: referrer,
    requestType: RequestTypes.DOCUMENT,
    frameRule: frames_frames.getFrameRule(tab)
  });
};
/**
 * Headers filtering service
 */

const headersService = new tsurlfilter_browser.HeadersService(filtering_log_browsers);
;// CONCATENATED MODULE: ./Extension/src/background/content-filtering/content-filtering.chrome.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */
const chromeContentFiltering = undefined;
/* harmony default export */ const content_filtering_chrome = (chromeContentFiltering);
;// CONCATENATED MODULE: ./Extension/src/background/webrequest.js


/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint-disable max-len */




















const webrequestInit = function () {
  const CSP_HEADER_NAME = 'Content-Security-Policy';
  /**
   * In the case of the tabs.insertCSS API support we're trying to collapse a blocked element from the background page.
   * In order to do it we need to have a mapping requestType<->tagNames.
   */

  const REQUEST_TYPE_COLLAPSE_TAG_NAMES = {
    [RequestTypes.SUBDOCUMENT]: ['frame', 'iframe'],
    [RequestTypes.IMAGE]: ['img']
  };
  /**
   * In the newer versions of Firefox and Chromium we're able to inject CSS and scripts
   * using a better approach -- `browser.tabs.insertCSS` and `browser.tabs.executeScript`
   * instead of the traditional one (messaging to the content script).
   */

  const shouldUseInsertCSSAndExecuteScript = prefs.features.canUseInsertCSSAndExecuteScript;
  /**
   * Retrieve referrer url from request details.
   * Extract referrer by priority:
   * 1. referrerUrl in requestDetails
   * 2. url of frame where request was created
   * 3. url of main frame
   *
   * @param requestDetails
   * @returns {*|Frame}
   */

  function getReferrerUrl(requestDetails) {
    return requestDetails.referrerUrl || frames_frames.getFrameUrl(requestDetails.tab, requestDetails.requestFrameId) || frames_frames.getMainFrameUrl(requestDetails.tab);
  }
  /**
   * Process request
   *
   * @param {RequestDetails} requestDetails
   * @returns {boolean|{Object}} False if request must be blocked, object if url was redirected
   */


  function onBeforeRequest(requestDetails) {
    var _requestRule;

    if (backgroundPage.app.isOwnRequest(requestDetails.referrerUrl)) {
      return;
    }

    const {
      tab,
      requestId,
      originUrl,
      requestType,
      frameId,
      requestFrameId = 0,
      method
    } = requestDetails;
    const {
      tabId
    } = tab;
    let {
      requestUrl
    } = requestDetails;

    if (requestType === RequestTypes.DOCUMENT || requestType === RequestTypes.SUBDOCUMENT) {
      frames_frames.recordFrame(tab, frameId, requestUrl, requestType);
    }

    if (requestType === RequestTypes.DOCUMENT) {
      // Reset tab button state
      listeners.notifyListeners(listeners.UPDATE_TAB_BUTTON_STATE, tab, true);
      /**
       * Just to remember!
       * In the case of the "about:newtab" pages we don't receive onResponseReceived event for the main_frame
       * Also if chrome://newtab is overwritten, we won't receive any webRequest events for the main_frame
       * Unfortunately, we can't do anything in this case and just must remember about it
       */

      /**
       * Binds rule to the main_frame request
       * In integration mode, rule from the headers will override this value
       */

      const tabRequestRule = frames_frames.getFrameRule(tab);

      if (tabRequestRule) {
        requestContextStorage.update(requestId, {
          requestRule: tabRequestRule
        });
      }
    }

    if (!utils.url.isHttpOrWsRequest(requestUrl)) {
      // Do not mess with other extensions
      return;
    }

    const referrerUrl = getReferrerUrl(requestDetails); // truncate too long urls
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1493

    const MAX_URL_LENGTH = 1024 * 16;

    if (requestUrl.length > MAX_URL_LENGTH) {
      requestUrl = requestUrl.slice(0, MAX_URL_LENGTH);
    } // Record request for other types


    const context = requestContextStorage.record({
      requestId,
      requestUrl,
      referrerUrl,
      originUrl,
      // TODO: use single requestType field
      requestType,
      engineRequestType: RequestTypes.transformRequestType(requestType),
      tab,
      method
    });
    let requestRule = webRequestService.getRuleForRequest(tab, requestUrl, referrerUrl, requestType);

    if (!((_requestRule = requestRule) !== null && _requestRule !== void 0 && _requestRule.isDocumentAllowlistRule())) {
      cookieService.onBeforeRequest(requestDetails, getCookieRules(tab, requestUrl, referrerUrl) || []);
    }

    requestRule = webRequestService.postProcessRequest(tab, requestUrl, referrerUrl, requestType, requestRule);

    if (requestRule) {
      requestContextStorage.update(requestId, {
        requestRule
      });
    }

    if (requestRule && !requestRule.isAllowlist() && requestRule.isOptionEnabled(tsurlfilter_browser.NetworkRuleOption.Popup) && requestType === RequestTypes.DOCUMENT) {
      const isNewTab = tabsApi.isNewPopupTab(tabId);

      if (isNewTab) {
        tabsApi.remove(tabId);
        return {
          cancel: true
        };
      }
    }

    const response = webRequestService.getBlockedResponseByRule(requestRule, requestType, requestUrl);

    if (!response) {
      /*
       Strip url by $removeparam rules
       $removeparam rules are applied after URL blocking rules
       https://github.com/AdguardTeam/CoreLibs/issues/1462
      */
      const cleansedUrl = webRequestService.removeParamFromUrl(tab, requestUrl, referrerUrl, requestType, method);

      if (cleansedUrl) {
        return {
          redirectUrl: cleansedUrl
        };
      }
    }

    if (response && response.documentBlockedPage) {
      // Here we do not use redirectUrl because it is not working in firefox without specifying it
      // as the web_accessible_resources.
      documentFilterService.showDocumentBlockPage(tabId, response.documentBlockedPage);
      return {
        cancel: true
      };
    }

    if (response && response.cancel) {
      collapseElement(tabId, requestFrameId, requestUrl, referrerUrl, requestType);
    } // Content filtering will be undefined for chromium based builds
    // Do not launch content filtering for blocked requests


    if (!(response !== null && response !== void 0 && response.cancel) && content_filtering_chrome) {
      const replaceRules = webRequestService.getReplaceRules(tab, requestUrl, referrerUrl, requestType) || [];
      const htmlRules = webRequestService.getContentRules(tab, referrerUrl) || [];

      if (replaceRules.length > 0 || htmlRules.length > 0) {
        const supportedStreamFilterRequestTypes = [RequestTypes.DOCUMENT, RequestTypes.SUBDOCUMENT, RequestTypes.STYLESHEET, RequestTypes.SCRIPT, RequestTypes.XMLHTTPREQUEST, RequestTypes.OTHER];

        if (supportedStreamFilterRequestTypes.includes(requestType)) {
          content_filtering_chrome.onBeforeRequest(backgroundPage.webRequest.filterResponseData(requestId), context, replaceRules || [], htmlRules || []);
        }
      }
    }

    return response;
  }
  /**
   * Tries to collapse a blocked element using tabs.insertCSS.
   *
   * This method of collapsing has numerous advantages over the traditional one.
   * First of all, it prevents blocked elements flickering as it occurs earlier.
   * Second, it is harder to detect as there's no custom <style> node required.
   *
   * However, we're still keeping the old approach intact - we have not enough information
   * here to properly collapse elements that use relative URLs (<img src='../path_to_element'>).
   *
   * @param {number} tabId Tab id
   * @param {number} requestFrameId Id of a frame request was sent from
   * @param {string} requestUrl Request URL
   * @param {string} referrerUrl Referrer URL
   * @param {string} requestType A member of RequestTypes
   */


  function collapseElement(tabId, requestFrameId, requestUrl, referrerUrl, requestType) {
    if (!shouldUseInsertCSSAndExecuteScript) {
      return;
    }

    const tagNames = REQUEST_TYPE_COLLAPSE_TAG_NAMES[requestType];

    if (!tagNames) {
      // Collapsing is not supported for this request type
      return;
    } // Collapsing is not supported for the requests which happen out of the tabs, e.g. other extensions


    if (tabId === -1) {
      return;
    } // Strip the protocol and host name (for first-party requests) from the selector


    const thirdParty = tsurlfilter_browser.isThirdPartyRequest(requestUrl, referrerUrl);
    let srcUrlStartIndex = requestUrl.indexOf('//');

    if (!thirdParty) {
      srcUrlStartIndex = requestUrl.indexOf('/', srcUrlStartIndex + 2);
    }

    const srcUrl = requestUrl.substring(srcUrlStartIndex);
    const collapseStyle = '{ display: none!important; visibility: hidden!important; height: 0px!important; min-height: 0px!important; }';
    let css = '';
    let iTagNames = tagNames.length;

    while (iTagNames) {
      iTagNames -= 1;
      css += `${tagNames[iTagNames]}[src$="${srcUrl}"] ${collapseStyle}\n`;
    }

    tabsApi.insertCssCode(tabId, requestFrameId, css);
  }
  /**
   * Called before request is sent to the remote endpoint.
   * This method is used to modify headers for stealth service
   * and also to record referrer header in frame data.
   *
   * @param requestDetails Request details
   * @returns {*} headers to send
   */


  function onBeforeSendHeaders(requestDetails) {
    const {
      tab,
      requestId,
      requestUrl,
      requestType,
      requestHeaders
    } = requestDetails;
    requestContextStorage.update(requestId, {
      requestHeaders
    });
    let requestHeadersModified = false;

    if (requestType === RequestTypes.DOCUMENT) {
      // Save ref header
      const refHeader = browserUtils.findHeaderByName(requestHeaders, 'Referer');

      if (refHeader) {
        frames_frames.recordFrameReferrerHeader(tab, refHeader.value);
      }
    }

    cookieService.onBeforeSendHeaders(requestDetails);

    if (stealthService.processRequestHeaders(requestId, requestHeaders)) {
      requestHeadersModified = true;
    }

    if (headersService.onBeforeSendHeaders(requestDetails, getRemoveHeaderRules(tab, requestUrl, getReferrerUrl(requestDetails)))) {
      requestHeadersModified = true;
    }

    if (requestHeadersModified) {
      requestContextStorage.update(requestId, {
        modifiedRequestHeaders: requestHeaders
      });
      return {
        requestHeaders
      };
    }

    return {};
  }
  /**
   * Safebrowsing check
   *
   * @param tab
   * @param mainFrameUrl
   */


  async function filterSafebrowsing(tab, mainFrameUrl) {
    if (frames_frames.isTabProtectionDisabled(tab) || frames_frames.isTabAllowlistedForSafebrowsing(tab)) {
      return;
    }

    const referrerUrl = browserUtils.getSafebrowsingBackUrl(tab);
    const incognitoTab = frames_frames.isIncognitoTab(tab);
    const safebrowsingUrl = await safebrowsing_browsers.checkSafebrowsingFilter(mainFrameUrl, referrerUrl);

    if (!safebrowsingUrl) {
      return;
    } // Chrome doesn't allow open extension url in incognito mode


    if (incognitoTab && browserUtils.isChromium()) {
      // Closing tab before opening a new one may lead to browser crash (Chromium)
      uiService.openTab(safebrowsingUrl).then(() => {
        tabsApi.remove(tab.tabId);
      });
    } else {
      tabsApi.reload(tab.tabId, safebrowsingUrl);
    }
  }
  /**
   * On headers received callback function.
   * We do check request for safebrowsing
   * and check if websocket connections should be blocked.
   * Do not make this function async, otherwise csp rules won't apply in time
   *
   * @param requestDetails Request details
   * @returns {{responseHeaders: *}} Headers to send
   */


  function onHeadersReceived(requestDetails) {
    const {
      tab,
      requestUrl,
      requestType,
      requestId,
      statusCode
    } = requestDetails;
    let responseHeaders = requestDetails.responseHeaders || [];
    const referrerUrl = getReferrerUrl(requestDetails);
    const contentType = browserUtils.getHeaderValueByName(responseHeaders, 'content-type');
    requestContextStorage.update(requestId, {
      responseHeaders,
      statusCode,
      contentType
    });
    webRequestService.processRequestResponse(tab, requestUrl, referrerUrl, requestType, responseHeaders); // Safebrowsing check

    if (requestType === RequestTypes.DOCUMENT // Don't apply safebrowsing filter in case of redirect
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/995
    && statusCode !== 301 && statusCode !== 302) {
      // Do not await function bellow, otherwise csp rules won't apply in time
      // Issue AG-6230
      filterSafebrowsing(tab, requestUrl);
    }

    let responseHeadersModified = false;

    if (requestType === RequestTypes.DOCUMENT || requestType === RequestTypes.SUBDOCUMENT) {
      const cspHeaders = getCSPHeaders(requestDetails);

      if (cspHeaders && cspHeaders.length > 0) {
        responseHeaders = responseHeaders.concat(cspHeaders);
        responseHeadersModified = true;
      }
    }

    if (cookieService.onHeadersReceived(requestDetails)) {
      responseHeadersModified = true;
    }

    if (headersService.onHeadersReceived(requestDetails, getRemoveHeaderRules(tab, requestUrl, referrerUrl))) {
      responseHeadersModified = true;
    }

    if (responseHeadersModified) {
      requestContextStorage.update(requestId, {
        modifiedResponseHeaders: responseHeaders
      });
      return {
        responseHeaders
      };
    }
  }
  /**
   * Modify CSP header to block WebSocket, prohibit data: and blob: frames and WebWorkers
   * @param requestDetails
   * @returns {{responseHeaders: *}} CSP headers
   */


  function getCSPHeaders(requestDetails) {
    // Please note, that we do not modify response headers in Edge before Creators update:
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/401
    // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8796739/
    if (browserUtils.isEdgeBeforeCreatorsUpdate()) {
      return;
    }

    const {
      tab
    } = requestDetails;
    const {
      requestId
    } = requestDetails;
    const {
      requestUrl
    } = requestDetails;
    const {
      requestType
    } = requestDetails;
    const frameUrl = frames_frames.getFrameUrl(tab, requestDetails.frameId);
    const cspHeaders = [];
    /**
     * Retrieve $CSP rules specific for the request
     * https://github.com/adguardteam/adguardbrowserextension/issues/685
     */

    const cspRules = webRequestService.getCspRules(tab, requestUrl, frameUrl, requestType);

    if (cspRules) {
      for (let i = 0; i < cspRules.length; i += 1) {
        const rule = cspRules[i]; // Don't forget: getCspRules returns all $csp rules, we must directly check that the rule is blocking.

        if (webRequestService.isRequestBlockedByRule(rule)) {
          cspHeaders.push({
            name: CSP_HEADER_NAME,
            value: rule.getAdvancedModifierValue()
          });
        }
      }

      if (cspRules.length > 0) {
        requestContextStorage.update(requestId, {
          cspRules
        });
      }
    }
    /**
     * Websocket connection is blocked by connect-src directive
     * https://www.w3.org/TR/CSP2/#directive-connect-src
     *
     * Web Workers is blocked by child-src directive
     * https://www.w3.org/TR/CSP2/#directive-child-src
     * https://www.w3.org/TR/CSP3/#directive-worker-src
     * We have to use child-src as fallback for worker-src, because it isn't supported
     * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/worker-src#Browser_compatibility
     *
     * We also need the frame-src restriction since CSPs are not inherited from the parent for documents with data: and blob: URLs
     * https://bugs.chromium.org/p/chromium/issues/detail?id=513860
     */


    return cspHeaders;
  }
  /**
   * Intercepts csp_report requests.
   * Check the URL of the report.
   * For chromium and firefox:
   * If it's sent to a third party, block it right away.
   * For firefox only:
   * If it contains moz://extension with our extension ID, block it as well.
   * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1792
   * @param {RequestDetails} details
   * @returns {{cancel: boolean}}
   */


  function handleCspReportRequests(details) {
    const {
      requestBody,
      requestUrl,
      originUrl,
      requestId,
      referrerUrl,
      requestType,
      tab
    } = details;
    const requestContext = requestContextStorage.get(requestId);

    if (!requestContext) {
      // Record request for other types
      requestContextStorage.record({
        requestId,
        requestUrl,
        referrerUrl,
        originUrl,
        requestType,
        tab
      });
    } // block if request is third party


    const thirdParty = tsurlfilter_browser.isThirdPartyRequest(requestUrl, originUrl);

    if (frames_frames.shouldStopRequestProcess(tab)) {
      return;
    }

    if (thirdParty) {
      requestContextStorage.update(requestId, {
        cspReportBlocked: true
      });
      return {
        cancel: true
      };
    } // block if requestBody contains moz://extension with our extension ID


    if (browserUtils.isFirefoxBrowser()) {
      try {
        const extensionUrl = backgroundPage.app.getExtensionUrl();
        const report = String.fromCharCode.apply(null, new Uint8Array(requestBody.raw[0].bytes));

        if (report.indexOf(extensionUrl) !== -1) {
          requestContextStorage.update(requestId, {
            cspReportBlocked: true
          });
          return {
            cancel: true
          };
        }
      } catch (e) {
        log.debug('Unable to parse CSP report request body content', details.url);
      }
    }
  }
  /**
   * Add listeners described above.
   */


  backgroundPage.webRequest.onBeforeRequest.addListener(onBeforeRequest, ['<all_urls>']);
  /**
   * Handler for csp reports urls
   */

  backgroundPage.webRequest.onBeforeRequest.addListener(handleCspReportRequests, ['<all_urls>'], ['csp_report'], ['requestBody']);
  backgroundPage.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, ['<all_urls>']);
  backgroundPage.webRequest.onHeadersReceived.addListener(onHeadersReceived, ['<all_urls>']);
  /**
   * If page uses service worker then it can do not fire main DOCUMENT request, that's why we check
   * frame data before scripts are injected
   * This listener should be added before any other listener of onCommitted event
   * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1459
   * @param details
   */

  const onCommittedCheckFrameUrl = details => {
    const {
      tab,
      requestType,
      frameId,
      requestUrl
    } = details;

    if (requestType !== RequestTypes.DOCUMENT || tab.tabId === BACKGROUND_TAB_ID) {
      return;
    }

    frames_frames.checkAndRecordMainFrame(tab, frameId, requestUrl, requestType);
  };

  backgroundPage.webNavigation.onCommitted.addListener(onCommittedCheckFrameUrl);
  let handlerBehaviorTimeout = null;
  listeners.addListener(event => {
    switch (event) {
      case listeners.ADD_RULES:
      case listeners.REMOVE_RULE:
      case listeners.UPDATE_FILTER_RULES:
      case listeners.UPDATE_ALLOWLIST_FILTER_RULES:
      case listeners.FILTER_ENABLE_DISABLE:
        if (handlerBehaviorTimeout !== null) {
          clearTimeout(handlerBehaviorTimeout);
        }

        handlerBehaviorTimeout = setTimeout(() => {
          handlerBehaviorTimeout = null;
          backgroundPage.webRequest.handlerBehaviorChanged();
        }, 3000);
        break;

      default: // do noting

    }
  });

  if (shouldUseInsertCSSAndExecuteScript) {
    /**
     * Applying CSS/JS rules from the background page.
     * This function implements the algorithm suggested here: https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1029
     * For faster script injection, we prepare scriptText onHeadersReceived event (we can't use onBeforeRequest
     * event because we can't detect adguard application headers early in order to know should extension inject scripts or no),
     * save it and try to inject twice:
     * first time onResponseStarted event - this event fires early, but is not reliable
     * second time onCommitted event - this event fires on when part of document has been received, this event is reliable
     * Every time we try to inject script we check if script wasn't yet executed
     * We use browser.tabs.insertCSS and browser.tabs.executeScript functions to inject our CSS/JS rules.
     * This method can be used in modern Chrome and FF only.
     * Bellow are presented rough event flows in Chrome and Firefox
     * This flows are were tested for Chrome 67.0.3396.87 (64 bit) and Firefox 60.0.2 (64-bit)
     * FLOWS MAY BE MODIFIED IN THE FUTURE
     *
                                            Chrome flow description
                                         +--------------------------------+
                                        |                                |
                                        | webRequest.onHeadersReceived   |     Prepare injection
                                        |                                |
                                        +---------------+----------------+
                                                        |
                                        +---------------v--------------+
                                        |                              |
                                        | webRequest.onResponseStarted |     Try to inject JS
                                        |                              |
                                        +------------------------------+
         onCommitted event belongs to     +------------------------------+
        WebNavigation events and fires   |                              |
        independently from               | webNavigation.onCommitted    |     Inject JS and CSS
        onResponseStarted event.         |                              |     Remove injection
        Thats why we try to inject       +------------------------------+
        two times
                                        +------------------------------+
                                        |                              |
                                        | webRequest.onErrorOccured    |     Remove injections on error
                                        |                              |
                                        +------------------------------+
                                             Firefox flow description
         onCommitted event in Firefox for +------------------------------+
        sub_frames fires before          |                              |
        onHeadersReceived event          | webNavigation.onCommitted     |
        That's why we inject our code    |                              |
        on onCompletedEvent              +------------------------------+
                                         +--------------------------------+
                                        |                                |
                                        | webRequest.onHeadersReceived   |      Prepare injection
                                        |                                |
                                        +--------------+-----------------+
                                                       |
                                        +--------------v---------------+
                                        |                              |
                                        | webRequest.onResponseStarted |      Try to inject JS code
                                        |                              |
                                        +------------------------------+
                                         +------------------------------+
                                        |                              |
                                        | webNavigation.onCommitted     |      Inject JS and CSS for main_frame
                                        |                              |      Remove injection
                                        +------------------------------+
                                         +------------------------------+
                                        |                              |
                                        | webRequest.onCompleted       |      Inject JS and CSS for sub_frame
                                        |                              |      Remove injection
                                        +------------------------------+
                                         +------------------------------+
                                        |                              |
                                        | webRequest.onErrorOccured    |     Remove injections on error
                                        |                              |
                                        +------------------------------+
        On tab close we clear our injections for corresponding tab
        Also our injections removes old injections for iframes when user navigates to other page in the same tab
         In Firefox and Chrome if page has iframes without remote source we can not get rules for this iframe with usual methods,
        That's why we get rules for main frame and inject them.
                                        +- ----------------------------------+
                                        |                                    |     Get injection for main iframe
                                        |  webNavigation.onDOMContentLoaded  |     inject it in the frame without
                                        |                                    |     remote source
                                        +- ----------------------------------+
     */
    (function () {
      /**
       * This object is used:
       * 1. to save js and css texts when onHeadersReceived event fires
       * by key corresponding to tabId and frameId
       * 2. to get js and css texts for injection
       * After injection corresponding js and css texts are removed from the object
       */
      const injections = {
        /**
         * @typedef Injection
         * @property {Boolean} ready value depends on are css and js texts ready or not. If false we should retry get them later
         * @property {String} [jsScriptText] prepared JS code text for injection
         * @property {String} [cssText] prepared CSS code text for injection
         */

        /**
         * Saves css, js and ready flag in injection object
         * @param tabId
         * @param frameId
         * @param {Injection} injection
         */
        set(tabId, frameId, injection) {
          if (frameId === 0) {
            delete this[tabId];
          }

          if (!this[tabId]) {
            this[tabId] = {};
          }

          this[tabId][frameId] = injection;
        },

        get(tabId, frameId) {
          if (this[tabId]) {
            return this[tabId][frameId];
          }

          return undefined;
        },

        /**
         * Removes injection corresponding to tabId and frameId
         * @param {Number} tabId
         * @param {Number} frameId
         */
        removeTabFrameInjection(tabId, frameId) {
          if (this[tabId]) {
            delete this[tabId][frameId];

            if (Object.keys(this[tabId]).length === 0) {
              delete this[tabId];
            }
          }
        },

        /**
         * Removes all injections corresponding to tabId
         * @param {Number} tabId
         */
        removeTabInjection(tabId) {
          delete this[tabId];
        }

      };
      /**
       * Taken from
       * {@link https://github.com/seanl-adg/InlineResourceLiteral/blob/master/index.js#L136}
       * {@link https://github.com/joliss/js-string-escape/blob/master/index.js}
       */

      const reJsEscape = /["'\\\n\r\u2028\u2029]/g;

      function escapeJs(match) {
        switch (match) {
          case '"':
          case "'":
          case '\\':
            return `\\${match}`;

          case '\n':
            return '\\n\\\n';
          // Line continuation character for ease
          // of reading inlined resource.

          case '\r':
            return '';
          // Carriage returns won't have
          // any semantic meaning in JS

          case '\u2028':
            return '\\u2028';

          case '\u2029':
            return '\\u2029';

          default: // do nothing

        }
      }
      /**
       * We use changing variable name because global properties
       * can be modified across isolated worlds of extension content page and tab page
       * https://bugs.chromium.org/p/project-zero/issues/detail?id=1225&desc=6
       */


      const variableName = `scriptExecuted${Date.now()}`;

      function buildScriptText(scriptText) {
        if (!scriptText) {
          return null;
        }
        /**
         * Executes scripts in a scope of the page.
         * In order to prevent multiple script execution checks if script was already executed
         * Sometimes in Firefox when content-filtering is applied to the page race condition happens.
         * This causes an issue when the page doesn't have its document.head or document.documentElement at the moment of
         * injection. So script waits for them. But if a quantity of frame-requests reaches FRAME_REQUESTS_LIMIT then
         * script stops waiting with the error.
         * Description of the issue: https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1004
         */


        const injectedScript = `(function() {\
                    if (window.${variableName}) {\
                        return;\
                    }\
                    var script = document.createElement("script");\
                    script.setAttribute("type", "text/javascript");\
                    script.textContent = "${scriptText.replace(reJsEscape, escapeJs)}";\
                    var FRAME_REQUESTS_LIMIT = 500;\
                    var frameRequests = 0;\
                    function waitParent () {\
                        frameRequests += 1;\
                        var parent = document.head || document.documentElement;\
                        if (parent) {\
                            try {\
                                parent.appendChild(script);\
                                parent.removeChild(script);\
                            } catch (e) {\
                            } finally {\
                                window.${variableName} = true;\
                                return true;\
                            }\
                        }\
                        if(frameRequests < FRAME_REQUESTS_LIMIT) {\
                            requestAnimationFrame(waitParent);\
                        } else {\
                            console.log("AdGuard: document.head or document.documentElement were unavailable too long");\
                        }\
                    }\
                    waitParent();\
                })()`;
        return injectedScript;
      }
      /**
       * @param {SelectorsData} selectorsData Selectors data
       * @returns {string} CSS to be supplied to insertCSS or null if selectors data is empty
       */


      function buildCssText(selectorsData) {
        if (!selectorsData || !selectorsData.css) {
          return null;
        }

        return selectorsData.css.join('\n');
      }
      /**
       * Checks requestType, tabId and event
       * We don't inject CSS or JS if request wasn't related to tab, or if request type
       * is not equal to DOCUMENT or SUBDOCUMENT.
       * @param {String} requestType
       * @param {Number} tabId
       * @param {String} eventName
       * @returns {Boolean}
       */


      function shouldSkipInjection(requestType, tabId, eventName) {
        /**
         * onCompleted event is used only to inject code to the Firefox iframes
         * because in current Firefox implementation webNavigation.onCommitted event for iframes
         * occures early than webRequest.onHeadersReceived event
         * if onCompleted event fired with requestType DOCUMENT then we skip it, because we
         * use onCompleted event only for SUBDOCUMENTS
         */
        if (eventName === 'onCompleted' && requestType === RequestTypes.DOCUMENT) {
          return true;
        }

        if (tabId === BACKGROUND_TAB_ID) {
          return true;
        }

        if (requestType !== RequestTypes.DOCUMENT && requestType !== RequestTypes.SUBDOCUMENT) {
          return true;
        }

        return false;
      }

      const REQUEST_FILTER_READY_TIMEOUT = 100;
      /**
       * Prepares injection content (scripts and css) for a given frame.
       * @param {RequestDetails} details
       */

      function prepareInjection(details) {
        const {
          requestType
        } = details;
        const {
          tab
        } = details;
        const {
          tabId
        } = tab;

        if (shouldSkipInjection(requestType, tabId)) {
          return;
        }

        const {
          frameId
        } = details;
        const url = details.requestUrl;
        const result = webRequestService.processGetSelectorsAndScripts({
          tabId
        }, url, true);

        if (result.requestFilterReady === false) {
          injections.set(tabId, frameId, {
            ready: false
          });
        } else {
          injections.set(tabId, frameId, {
            ready: true,
            jsScriptText: buildScriptText(result.scripts),
            cssText: buildCssText(result.selectors),
            url
          });
        }
      }
      /**
       * Injects js code in the page on responseStarted event only if event was fired from the main_frame
       * @param {RequestDetails} details Details about the webrequest event
       */


      function tryInjectOnResponseStarted(details) {
        const {
          tab
        } = details;
        const {
          tabId
        } = tab;
        const {
          requestType
        } = details;
        const {
          frameId
        } = details;

        if (shouldSkipInjection(requestType, tabId)) {
          return;
        }

        const injection = injections.get(tabId, frameId);

        if (injection && injection.jsScriptText) {
          // grep "localScriptRulesService" for details about script source
          tabsApi.executeScriptCode(tabId, frameId, injection.jsScriptText);
        }
      }
      /**
       * Function checks if injection corresponds to url
       * This check could be useful when injections were prepared in the onBeforeRequest
       * or onHeadersReceived events and then there was redirection and document request
       * didn't fired in webRequest events
       * @param injection
       * @param url
       * @returns {boolean}
       */


      function isInjectionForUrl(injection, url) {
        return injection && injection.url === url;
      }
      /**
       * Injects necessary CSS and scripts into the web page.
       * @param {RequestDetails} details Details about the navigation event
       * @param {String} eventName Event name
       */


      function tryInject(details, eventName) {
        const {
          tab
        } = details;
        const {
          tabId
        } = tab;
        const {
          frameId
        } = details;
        const {
          requestType
        } = details;
        const frameUrl = details.requestUrl;

        if (shouldSkipInjection(requestType, tabId, eventName)) {
          return;
        }

        const injection = injections.get(tabId, frameId);

        if (injection && !injection.ready) {
          /**
           * If injection is not ready yet, we call prepareScripts and tryInject functions again
           * setTimeout callback lambda function accepts onCommitted details and eventName
           */
          setTimeout((details, eventName) => {
            prepareInjection(details);
            tryInject(details, eventName);
          }, REQUEST_FILTER_READY_TIMEOUT, details, eventName);
          injections.removeTabFrameInjection(tabId, frameId);
          return;
        }
        /**
         * webRequest api doesn't see requests served from service worker like they are served from the cache
         * https://bugs.chromium.org/p/chromium/issues/detail?id=766433
         * that's why we can't prepare injections when webRequest events fire
         * also we should check if injection url is correct
         * so we try to prepare this injection in the onCommit event again
         */


        if (requestType === RequestTypes.DOCUMENT && (!injection || !isInjectionForUrl(injection, frameUrl))) {
          prepareInjection(details);
          tryInject(details, eventName);
          return;
        }
        /**
         * Sometimes it can happen that onCommitted event fires earlier than onHeadersReceived
         * for example onCommitted event for iframes in Firefox
         */


        if (!injection) {
          return;
        }

        if (injection.jsScriptText) {
          // grep "localScriptRulesService" for details about script source
          tabsApi.executeScriptCode(tabId, frameId, injection.jsScriptText);
        }

        if (injection.cssText) {
          tabsApi.insertCssCode(tabId, frameId, injection.cssText);
        }

        const mainFrameUrl = frames_frames.getMainFrameUrl({
          tabId
        });

        if (isIframeWithoutSrc(frameUrl, frameId, mainFrameUrl)) {
          log.warn('Unexpected onCommitted event from this frame - frameId: {0}, frameUrl: {1}. See https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1046', frameId, frameUrl);
        }

        injections.removeTabFrameInjection(tabId, frameId);
      }
      /**
       * Removes injection if onErrorOccured event fires for corresponding tabId and frameId
       * @param {RequestDetails} details
       */


      function removeInjection(details) {
        const {
          requestType
        } = details;
        const {
          tab
        } = details;
        const {
          tabId
        } = tab;

        if (shouldSkipInjection(requestType, tabId)) {
          return;
        }

        const {
          frameId
        } = details;
        injections.removeTabFrameInjection(tabId, frameId);
      }
      /**
       * Checks if iframe does not have a remote source
       * or is src is about:blank, javascript:'', etc
       * We don't include iframes with 'src=data:' because chrome and firefox don't allow to inject
       * in iframes with this type of src, this bug is reported here
       * https://bugs.chromium.org/p/chromium/issues/detail?id=55084
       * @param {string} frameUrl url
       * @param {number} frameId unique id of frame in the tab
       * @param {string} mainFrameUrl url of tab where iframe exists
       */


      function isIframeWithoutSrc(frameUrl, frameId, mainFrameUrl) {
        return (frameUrl === mainFrameUrl || frameUrl === 'about:blank' || frameUrl === 'about:srcdoc' // eslint-disable-next-line no-script-url
        || frameUrl.indexOf('javascript:') > -1) && frameId !== MAIN_FRAME_ID;
      }
      /**
       * This method injects css and js code in iframes without remote source
       * Usual webRequest callbacks don't fire for iframes without remote source
       * Also urls in these iframes may be "about:blank", "about:srcdoc", etc.
       * Due to this reason we prepare injections for them as for mainframe
       * and inject them only when onDOMContentLoaded fires
       * https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1046
       * @param {{tabId: Number, url: String, processId: Number, frameId: Number, timeStamp: Number}} details
       */


      function tryInjectInIframesWithoutSrc(details) {
        const {
          frameId,
          tabId,
          url: frameUrl
        } = details;
        /**
         * Get url of the tab where iframe exists
         */

        const mainFrameUrl = frames_frames.getMainFrameUrl({
          tabId
        });

        if (mainFrameUrl && isIframeWithoutSrc(frameUrl, frameId, mainFrameUrl)) {
          const result = webRequestService.processGetSelectorsAndScripts({
            tabId
          }, mainFrameUrl, true);

          if (result.requestFilterReady === false) {
            setTimeout(details => {
              tryInjectInIframesWithoutSrc(details);
            }, REQUEST_FILTER_READY_TIMEOUT, details);
            return;
          }

          const jsScriptText = buildScriptText(result.scripts);
          const cssText = buildCssText(result.selectors);

          if (jsScriptText) {
            // grep "localScriptRulesService" for details about script source
            tabsApi.executeScriptCode(tabId, frameId, jsScriptText);
          }

          if (cssText) {
            tabsApi.insertCssCode(tabId, frameId, cssText);
          }
        }
      }
      /**
       * https://developer.chrome.com/extensions/webRequest
       * https://developer.chrome.com/extensions/webNavigation
       */


      backgroundPage.webRequest.onHeadersReceived.addListener(prepareInjection, ['<all_urls>']);
      backgroundPage.webRequest.onResponseStarted.addListener(tryInjectOnResponseStarted, ['<all_urls>']);
      backgroundPage.webNavigation.onCommitted.addListener(tryInject);
      backgroundPage.webRequest.onErrorOccurred.addListener(removeInjection, ['<all_urls>']);
      backgroundPage.webNavigation.onDOMContentLoaded.addListener(tryInjectInIframesWithoutSrc); // In the current Firefox version (60.0.2), the onCommitted even fires earlier than
      // onHeadersReceived for SUBDOCUMENT requests
      // This is true only for SUBDOCUMENTS i.e. iframes
      // so we inject code when onCompleted event fires

      if (browserUtils.isFirefoxBrowser()) {
        backgroundPage.webRequest.onCompleted.addListener(details => {
          tryInject(details, 'onCompleted');
        }, ['<all_urls>']);
      } // Remove injections when tab is closed


      tabsApi.onRemoved.addListener(injections.removeTabInjection);
    })();
  }
  /**
   * Request context recording
   */


  backgroundPage.webRequest.onCompleted.addListener(requestDetails => {
    const {
      requestId,
      statusCode
    } = requestDetails;
    cookieService.onCompleted(requestDetails);

    if (statusCode) {
      requestContextStorage.onRequestCompleted(requestId, statusCode);
    } else {
      requestContextStorage.onRequestCompleted(requestId);
    }
  }, ['<all_urls>']);
  backgroundPage.webRequest.onErrorOccurred.addListener(requestDetails => {
    cookieService.onErrorOccurred(requestDetails);
    requestContextStorage.onRequestCompleted(requestDetails.requestId);
  }, ['<all_urls>']);
  /**
   * Handles redirect separately:
   * If a request is redirected to a data:// URL, onBeforeRedirect is the last reported event.
   * https://developer.chrome.com/extensions/webRequest#life_cycle
   */

  backgroundPage.webRequest.onBeforeRedirect.addListener(({
    requestId,
    redirectUrl
  }) => {
    if (redirectUrl && redirectUrl.indexOf('data:') === 0) {
      requestContextStorage.onRequestCompleted(requestId);
    }
  }, ['<all_urls>']);
  /**
   * Subscribe script is executed when onCommitted event fires,
   * because this event is the most reliable
   */

  backgroundPage.webNavigation.onCommitted.addListener(details => {
    const {
      tab,
      requestType,
      frameId
    } = details;

    if (requestType !== RequestTypes.DOCUMENT && requestType !== RequestTypes.SUBDOCUMENT || tab.tabId === BACKGROUND_TAB_ID) {
      return;
    } // load subscribe script on dom content load


    tabsApi.executeScriptFile(tab.tabId, {
      file: '/content-script/subscribe.js',
      frameId
    });
  });
};

const webrequest = {
  init: webrequestInit
};
;// CONCATENATED MODULE: ./Extension/src/background/filter/request-sanitizer.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */




/**
 * Request sanitizer helper
 * Removes track-able data from extension initiated requests
 */

const requestSanitizer = function () {
  /**
   * On before send headers listener
   *
   * @param req
   * @return {{requestHeaders: *}}
   */
  const safeFilter = req => {
    const {
      requestHeaders,
      initiator,
      tabId,
      originUrl
    } = req;

    if (tabId !== BACKGROUND_TAB_ID) {
      return;
    }

    let requestHeadersModified = false; // Chrome provides "initiator" and firefox "originUrl"

    const origin = initiator || originUrl;

    if (backgroundPage.app.isOwnRequest(origin)) {
      requestHeadersModified = browserUtils.removeHeader(requestHeaders, 'Cookie');
    }

    if (requestHeadersModified) {
      return {
        requestHeaders
      };
    }
  };

  const init = () => {
    // Firefox doesn't allow to use "extraHeaders" extra option,
    //  but chrome requires it in order to get access to "Cookie" header
    const onBeforeSendHeadersExtraInfoSpec = ['requestHeaders', 'blocking'];

    if (typeof (browser_polyfill_default()).webRequest.OnBeforeSendHeadersOptions !== 'undefined' && browser_polyfill_default().webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) {
      onBeforeSendHeadersExtraInfoSpec.push('extraHeaders');
    }

    browser_polyfill_default().webRequest.onBeforeSendHeaders.addListener(safeFilter, {
      urls: ['<all_urls>'],
      tabId: BACKGROUND_TAB_ID
    }, onBeforeSendHeadersExtraInfoSpec);
  };

  return {
    init
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/filter/services/locale-detect.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */








/**
 * Initialize LocaleDetectService.
 *
 * This service is used to auto-enable language-specific filters.
 */

const localeDetect = function () {
  const browsingLanguages = [];
  const SUCCESS_HIT_COUNT = 3;
  const MAX_HISTORY_LENGTH = 10;
  const domainToLanguagesMap = {
    // Russian
    'ru': 'ru',
    'ua': 'ru',
    'by': 'ru',
    'kz': 'ru',
    // English
    'com': 'en',
    'au': 'en',
    'uk': 'en',
    'nz': 'en',
    // German
    'de': 'de',
    'at': 'de',
    // Japanese
    'jp': 'ja',
    // Dutch
    'nl': 'nl',
    // French
    'fr': 'fr',
    // Spanish
    'es': 'es',
    // Italian
    'it': 'it',
    // Portuguese
    'pt': 'pt',
    // Polish
    'pl': 'pl',
    // Czech
    'cz': 'cs',
    // Bulgarian
    'bg': 'bg',
    // Lithuanian
    'lt': 'lt',
    // Latvian
    'lv': 'lv',
    // Arabic
    'eg': 'ar',
    'dz': 'ar',
    'kw': 'ar',
    'ae': 'ar',
    // Slovakian
    'sk': 'sk',
    // Romanian
    'ro': 'ro',
    // Suomi
    'fi': 'fi',
    // Icelandic
    'is': 'is',
    // Norwegian
    'no': 'no',
    // Greek
    'gr': 'el',
    // Hungarian
    'hu': 'hu',
    // Hebrew
    'il': 'he',
    // Chinese
    'cn': 'zh',
    // Indonesian
    'id': 'id',
    // Turkish
    'tr': 'tr'
  };
  /**
   * Called when LocaleDetectorService has detected language-specific filters we can enable.
   *
   * @param filterIds List of detected language-specific filters identifiers
   * @private
   */

  async function onFilterDetectedByLocale(filterIds) {
    if (!filterIds) {
      return;
    }

    const enabledFilters = await application.addAndEnableFilters(filterIds, {
      forceGroupEnable: true
    });

    if (enabledFilters.length > 0) {
      listeners.notifyListeners(listeners.ENABLE_FILTER_SHOW_POPUP, enabledFilters);
    }
  }
  /**
   * Stores language in the special array containing languages of the last visited pages.
   * If user has visited enough pages with a specified language we call special callback
   * to auto-enable filter for this language
   *
   * @param language Page language
   * @private
   */


  function detectLanguage(language) {
    /**
     * For an unknown language "und" will be returned
     * https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/detectLanguage
     */
    if (!language || language === 'und') {
      return;
    }

    browsingLanguages.push({
      language,
      time: Date.now()
    });

    if (browsingLanguages.length > MAX_HISTORY_LENGTH) {
      browsingLanguages.shift();
    }

    const history = browsingLanguages.filter(h => {
      return h.language === language;
    });

    if (history.length >= SUCCESS_HIT_COUNT) {
      const filterIds = subscriptions.getFilterIdsForLanguage(language);
      onFilterDetectedByLocale(filterIds);
    }
  }
  /**
   * Detects language for the specified page
   * @param tab    Tab
   * @param url    Page URL
   */


  async function detectTabLanguage(tab, url) {
    if (!settings.isAutodetectFilters() || settings.isFilteringDisabled()) {
      return;
    } // Check language only for http://... tabs


    if (!utils.url.isHttpRequest(url)) {
      return;
    } // tabs.detectLanguage doesn't work in Opera
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/997


    if (!browserUtils.isOperaBrowser()) {
      if (tab.tabId && (browser_polyfill_default()).tabs && (browser_polyfill_default()).tabs.detectLanguage) {
        // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/detectLanguage
        try {
          const language = await browser_polyfill_default().tabs.detectLanguage(tab.tabId);
          detectLanguage(language);
        } catch (e) {// do nothing
        }

        return;
      }
    } // Detecting language by top-level domain if extension API language detection is unavailable
    // Ignore hostnames which length is less or equal to 8
    // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1354


    const host = utils.url.getDomainName(url);

    if (host && host.length > 8) {
      const parts = host ? host.split('.') : [];
      const tld = parts[parts.length - 1];
      const lang = domainToLanguagesMap[tld];
      detectLanguage(lang);
    }
  }

  const init = () => {
    // Locale detect
    tabsApi.onUpdated.addListener(tab => {
      if (tab.status === 'complete') {
        detectTabLanguage(tab, tab.url);
      }
    });
  };

  return {
    init
  };
}();
;// CONCATENATED MODULE: ./Extension/src/background/fullscreen-user-rules-editor.js


/**
 * Module used to keep track of userrules editor opened in the fullscreen mode
 */

class FullscreenUserRulesEditor {
  constructor() {
    this.openPagesCount = 0;
  }

  onOpenPage() {
    this.openPagesCount += 1;
    this.onPagesCountChanged();
  }

  onClosePage() {
    if (this.openPagesCount <= 0) {
      return;
    }

    this.openPagesCount -= 1;
    this.onPagesCountChanged();
  }

  onPagesCountChanged() {
    listeners.notifyListeners(NOTIFIER_TYPES.FULLSCREEN_USER_RULES_EDITOR_UPDATED, this.isOpen());
  }

  isOpen() {
    return this.openPagesCount > 0;
  }

}

const fullscreenUserRulesEditor = new FullscreenUserRulesEditor();
;// CONCATENATED MODULE: ./Extension/src/background/utils/editor-storage.js
/**
 * Module used to persist user rules editor content
 * during switches between common and fullscreen modes
 */
class EditorStorage {
  constructor() {
    this.content = null;

    this.setContent = content => {
      this.content = content;
    };

    this.getContent = () => {
      return this.content;
    };
  }

}

const editorStorage = new EditorStorage();
;// CONCATENATED MODULE: ./Extension/src/background/message-handler.js
/**
 * This file is part of Adguard Browser Extension (https://github.com/AdguardTeam/AdguardBrowserExtension).
 *
 * Adguard Browser Extension is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Adguard Browser Extension 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 Adguard Browser Extension. If not, see <http://www.gnu.org/licenses/>.
 */


































const onPortConnection = port => {
  switch (true) {
    case port.name.startsWith(FILTERING_LOG):
      {
        filtering_log_browsers.onOpenFilteringLogPage();
        break;
      }

    case port.name.startsWith(FULLSCREEN_USER_RULES_EDITOR):
      {
        fullscreenUserRulesEditor.onOpenPage();
        break;
      }

    default:
      {
        throw new Error(`There is no such pages ${port.name}`);
      }
  }
};

const onPortDisconnection = port => {
  switch (true) {
    case port.name.startsWith(FILTERING_LOG):
      {
        filtering_log_browsers.onCloseFilteringLogPage();
        break;
      }

    case port.name.startsWith(FULLSCREEN_USER_RULES_EDITOR):
      {
        fullscreenUserRulesEditor.onClosePage();
        break;
      }

    default:
      {
        throw new Error(`There is no such pages ${port.name}`);
      }
  }
};
/**
 * This handler used to subscribe for notifications from popup page
 * https://developer.chrome.com/extensions/messaging#connect
 * We can't use simple one-time connections, because they can intercept each other
 * Causing issues like AG-2074
 */


const longLivedMessageHandler = port => {
  let listenerId;
  log.info(`Port: "${port.name}" connected`);
  onPortConnection(port);
  port.onMessage.addListener(message => {
    const {
      type,
      data
    } = message;

    if (type === MESSAGE_TYPES.ADD_LONG_LIVED_CONNECTION) {
      const {
        events
      } = data;
      listenerId = listeners.addSpecifiedListener(events, async (...data) => {
        const type = MESSAGE_TYPES.NOTIFY_LISTENERS;

        try {
          port.postMessage({
            type,
            data
          });
        } catch (e) {
          log.error(e.message);
        }
      });
    }
  });
  port.onDisconnect.addListener(() => {
    onPortDisconnection(port);
    listeners.removeListener(listenerId);
    log.info(`Port: "${port.name}" disconnected`);
  });
};

const createMessageHandler = () => {
  /**
   * Contains event listeners from content pages
   */
  const eventListeners = Object.create(null);
  /**
   * Adds event listener from content page
   * @param events
   * @param sender
   */

  function processAddEventListener(events, sender) {
    const listenerId = listeners.addSpecifiedListener(events, (...args) => {
      const sender = eventListeners[listenerId];

      if (sender) {
        tabsApi.sendMessage(sender.tab.tabId, {
          type: MESSAGE_TYPES.NOTIFY_LISTENERS,
          data: args
        });
      }
    });
    eventListeners[listenerId] = sender;
    return {
      listenerId
    };
  }
  /**
   * Constructs objects that uses on extension pages, like: options.html, thankyou.html etc
   */


  function processInitializeFrameScriptRequest() {
    const AntiBannerFiltersId = utils.filters.ids;
    const enabledFilters = {};
    Object.values(AntiBannerFiltersId).forEach(filterId => {
      const enabled = application.isFilterEnabled(filterId);

      if (enabled) {
        enabledFilters[filterId] = true;
      }
    });
    return {
      userSettings: settings.getAllSettings(),
      enabledFilters,
      filtersMetadata: subscriptions.getFilters(),
      requestFilterInfo: filteringApi.getRequestFilterInfo(),
      environmentOptions: {
        isMacOs: browserUtils.isMacOs(),
        canBlockWebRTC: stealthService.canBlockWebRTC(),
        isChrome: browserUtils.isChromeBrowser(),
        Prefs: {
          locale: backgroundPage.app.getLocale(),
          mobile: prefs.mobile || false
        },
        appVersion: backgroundPage.app.getVersion()
      },
      constants: {
        AntiBannerFiltersId: utils.filters.ids,
        EventNotifierTypes: listeners.events
      }
    };
  }
  /**
   * Saves css hits from content-script.
   * Message includes stats field. [{filterId: 1, ruleText: 'rule1'}, {filterId: 2, ruleText: 'rule2'}...]
   * @param tab
   * @param stats
   */


  function processSaveCssHitStats(tab, stats) {
    if (!webRequestService.isCollectingCosmeticRulesHits(tab)) {
      return;
    }

    const frameUrl = frames_frames.getMainFrameUrl(tab);

    for (let i = 0; i < stats.length; i += 1) {
      const stat = stats[i];
      const rule = new tsurlfilter_browser.CosmeticRule(stat.ruleText, stat.filterId);
      webRequestService.recordRuleHit(tab, rule, frameUrl);
      filtering_log_browsers.addCosmeticEvent({
        tab,
        element: stat.element,
        frameUrl: tab.url,
        requestType: RequestTypes.DOCUMENT,
        requestRule: rule,
        timestamp: Date.now()
      });
    }
  }

  const processGetOptionsData = () => {
    return {
      settings: settings.getAllSettings(),
      appVersion: backgroundPage.app.getVersion(),
      filtersMetadata: categories.getFiltersMetadata(),
      filtersInfo: antiBannerService.getRequestFilterInfo(),
      environmentOptions: {
        isChrome: browserUtils.isChromeBrowser()
      },
      constants: {
        AntiBannerFiltersId: utils.filters.ids
      },
      fullscreenUserRulesEditorIsOpen: fullscreenUserRulesEditor.isOpen()
    };
  };
  /**
   * For dangerous (which can change user rules) messages we also check their origin
   * @param message
   * @param sender
   * @return {boolean}
   */


  const isMessageAllowed = (message, sender) => {
    const OPTIONS_PAGE_DANGEROUS_MESSAGES = [MESSAGE_TYPES.SUBSCRIBE_TO_CUSTOM_FILTER, MESSAGE_TYPES.SAVE_USER_RULES, MESSAGE_TYPES.APPLY_SETTINGS_JSON, MESSAGE_TYPES.FILTERING_LOG_ADD_USER_RULE, MESSAGE_TYPES.DEVTOOLS_ADD_USER_RULE]; // Dangerous messages are allowed only from own pages (popup, options, filtering log, devtools)

    if (OPTIONS_PAGE_DANGEROUS_MESSAGES.includes(message === null || message === void 0 ? void 0 : message.type)) {
      var _sender$tab;

      // Allow empty sender. Empty sender can be in the messages from devtools and popup
      // There is always sender for messages sent by content script
      const isSenderEmpty = !sender || sender && Object.keys(sender).length === 0;

      if (isSenderEmpty) {
        return true;
      }

      const url = (_sender$tab = sender.tab) === null || _sender$tab === void 0 ? void 0 : _sender$tab.url;
      const isOwnUrl = url && backgroundPage.app.isOwnRequest(url);
      const isDevtoolsUrl = url && url.startsWith('devtools://');
      return isOwnUrl || isDevtoolsUrl;
    }

    return true;
  };
  /**
   * Main function for processing messages from content-scripts
   *
   * @param message
   * @param sender
   * @returns {*}
   */


  const handleMessage = async (message, sender) => {
    if (!isMessageAllowed(message, sender)) {
      log.error('Message: {0} is not allowed for the sender: {1} ', message, sender);
      return;
    }

    const {
      data,
      type
    } = message;

    switch (type) {
      case MESSAGE_TYPES.GET_OPTIONS_DATA:
        {
          return processGetOptionsData();
        }

      case MESSAGE_TYPES.UN_ALLOWLIST_FRAME:
        {
          const {
            frameInfo
          } = data;
          userrules.unAllowlistFrame(frameInfo);
          break;
        }

      case MESSAGE_TYPES.CREATE_EVENT_LISTENER:
        {
          const {
            events
          } = data;
          return processAddEventListener(events, sender);
        }

      case MESSAGE_TYPES.REMOVE_LISTENER:
        {
          const {
            listenerId
          } = data;
          listeners.removeListener(listenerId);
          delete eventListeners[listenerId];
          break;
        }

      case MESSAGE_TYPES.INITIALIZE_FRAME_SCRIPT:
        return processInitializeFrameScriptRequest();

      case MESSAGE_TYPES.CHANGE_USER_SETTING:
        settings.setProperty(message.key, message.value);
        break;

      case MESSAGE_TYPES.CHECK_REQUEST_FILTER_READY:
        return {
          ready: filteringApi.isReady()
        };

      case MESSAGE_TYPES.ADD_AND_ENABLE_FILTER:
        {
          const {
            filterId
          } = data;
          return application.addAndEnableFilters([filterId], {
            forceRemote: true
          });
        }

      case MESSAGE_TYPES.DISABLE_ANTIBANNER_FILTER:
        {
          const {
            filterId,
            remove
          } = data;

          if (remove) {
            application.uninstallFilters([filterId]);
          } else {
            application.disableFilters([filterId]);
          }

          break;
        }

      case MESSAGE_TYPES.REMOVE_ANTIBANNER_FILTER:
        {
          const {
            filterId
          } = data;
          application.removeFilter(filterId);
          break;
        }

      case MESSAGE_TYPES.ENABLE_FILTERS_GROUP:
        {
          const {
            groupId
          } = data;
          await categories.enableFiltersGroup(groupId);
          break;
        }

      case MESSAGE_TYPES.DISABLE_FILTERS_GROUP:
        {
          const {
            groupId
          } = data;
          categories.disableFiltersGroup(groupId);
          break;
        }

      case MESSAGE_TYPES.GET_ALLOWLIST_DOMAINS:
        {
          const allowlistDomains = allowlist.getAllowlistDomains();
          const appVersion = backgroundPage.app.getVersion();
          return {
            content: allowlistDomains.join('\r\n'),
            appVersion
          };
        }

      case MESSAGE_TYPES.SAVE_ALLOWLIST_DOMAINS:
        {
          const {
            value
          } = data;
          const domains = value.split(/[\r\n]+/).map(string => string.trim()).filter(string => string.length > 0);
          allowlist.updateAllowlistDomains(domains);
          break;
        }

      case MESSAGE_TYPES.GET_USER_RULES:
        {
          const content = await userrules.getUserRulesText();
          const appVersion = backgroundPage.app.getVersion();
          return {
            content,
            appVersion
          };
        }

      case MESSAGE_TYPES.SAVE_USER_RULES:
        {
          const {
            value
          } = data;
          userrules.updateUserRulesText(value); // We are waiting until request filter is updated

          return new Promise(resolve => {
            const listenerId = listeners.addListener(event => {
              if (event === listeners.USER_FILTER_UPDATED) {
                listeners.removeListener(listenerId);
                resolve();
              }
            });
          });
        }

      case MESSAGE_TYPES.FILTERING_LOG_ADD_USER_RULE:
        {
          const {
            ruleText
          } = data;
          userrules.addRules([ruleText]);
          break;
        }

      case MESSAGE_TYPES.DEVTOOLS_ADD_USER_RULE:
        {
          const {
            ruleText
          } = data;
          userrules.addRules([ruleText]);
          break;
        }

      case MESSAGE_TYPES.CONTENT_SCRIPT_ADD_USER_RULE:
        {
          const {
            ruleText,
            token
          } = data;
          const expectedToken = uiService.getAssistantToken(); // check for token to avoid possible vulnerabilities AG-12883
          // https://groups.google.com/a/chromium.org/g/chromium-extensions/c/0ei-UCHNm34/m/lDaXwQhzBAAJ?pli=1
          // https://bugs.chromium.org/p/chromium/issues/detail?id=982326

          if (token === expectedToken) {
            userrules.addRules([ruleText]);
          } else {
            log.error('Tokens for message {0} does not not match. Expected token: {1}. Received token: {2}', message, token, expectedToken);
          }

          break;
        }

      case MESSAGE_TYPES.REMOVE_USER_RULE:
        {
          const {
            ruleText
          } = data;
          userrules.removeRule(ruleText);
          break;
        }

      case MESSAGE_TYPES.CHECK_ANTIBANNER_FILTERS_UPDATE:
        {
          const filters = await uiService.checkFiltersUpdates();
          return filters;
        }

      case MESSAGE_TYPES.LOAD_CUSTOM_FILTER_INFO:
        try {
          const {
            url,
            title
          } = data;
          return application.loadCustomFilterInfo(url, {
            title
          });
        } catch (e) {
          return {};
        }

      case MESSAGE_TYPES.SUBSCRIBE_TO_CUSTOM_FILTER:
        {
          const {
            customUrl,
            name,
            trusted
          } = data.filter;

          try {
            const filter = await application.loadCustomFilter(customUrl, {
              title: name,
              trusted
            });
            await application.addAndEnableFilters([filter.filterId]);
            return filter;
          } catch (e) {// do nothing
          }

          break;
        }

      case MESSAGE_TYPES.OPEN_THANKYOU_PAGE:
        uiService.openThankYouPage();
        break;

      case MESSAGE_TYPES.OPEN_EXTENSION_STORE:
        uiService.openExtensionStore();
        break;

      case MESSAGE_TYPES.OPEN_FILTERING_LOG:
        uiService.openFilteringLog(message.tabId);
        break;

      case MESSAGE_TYPES.SET_FILTERING_LOG_WINDOW_STATE:
        filteringLogWindowState.setState(data.windowState);
        break;

      case MESSAGE_TYPES.OPEN_FULLSCREEN_USER_RULES:
        uiService.openFullscreenUserRules();
        break;

      case MESSAGE_TYPES.GET_FILTERING_LOG_DATA:
        {
          return {
            filtersMetadata: subscriptions.getFilters(),
            settings: settings.getAllSettings(),
            preserveLogEnabled: filtering_log_browsers.isPreserveLogEnabled()
          };
        }

      case MESSAGE_TYPES.OPEN_SAFEBROWSING_TRUSTED:
        {
          const {
            url
          } = data;
          safebrowsing_browsers.addToSafebrowsingTrusted(url);
          const tab = await tabsApi.getActive();

          if (tab) {
            tabsApi.reload(tab.tabId, url);
          }

          break;
        }

      case MESSAGE_TYPES.OPEN_TAB:
        {
          const {
            url,
            options
          } = data;
          return uiService.openTab(url, options);
        }

      case MESSAGE_TYPES.RESET_BLOCKED_ADS_COUNT:
        frames_frames.resetBlockedAdsCount();
        break;

      case MESSAGE_TYPES.RESET_SETTINGS:
        return settingsProvider.applyDefaultSettings();

      case MESSAGE_TYPES.GET_SELECTORS_AND_SCRIPTS:
        {
          let urlForSelectors; // https://github.com/AdguardTeam/AdguardBrowserExtension/issues/1498
          // when document url for iframe is about:blank then we use tab url

          if (!utils.url.isHttpOrWsRequest(message.documentUrl) && sender.frameId !== 0) {
            urlForSelectors = sender.tab.url;
          } else {
            urlForSelectors = message.documentUrl;
          } // force getting selectors and scripts during browser restart with already open tabs


          const response = webRequestService.processGetSelectorsAndScripts(sender.tab, urlForSelectors, filteringApi.shouldCollapseAllElements());
          return response || {};
        }

      case MESSAGE_TYPES.GET_COOKIE_RULES:
        {
          if (!utils.url.isHttpOrWsRequest(message.documentUrl) && sender.frameId !== 0) {
            return {};
          }

          return {
            rulesData: getCookieRulesDataForContentScript(sender.tab, message.documentUrl, sender.tab.url)
          };
        }

      case MESSAGE_TYPES.SAVE_COOKIE_LOG_EVENT:
        {
          filtering_log_browsers.addCookieEvent({
            tabId: sender.tab.tabId,
            cookieName: data.cookieName,
            cookieDomain: data.cookieDomain,
            cookieRule: new tsurlfilter_browser.NetworkRule(data.ruleText, data.filterId),
            isModifyingCookieRule: false,
            thirdParty: data.thirdParty,
            timestamp: Date.now()
          });
          break;
        }

      case MESSAGE_TYPES.CHECK_PAGE_SCRIPT_WRAPPER_REQUEST:
        {
          const block = webRequestService.checkPageScriptWrapperRequest(sender.tab, message.elementUrl, message.documentUrl, message.requestType);
          return {
            block,
            requestId: message.requestId
          };
        }

      case MESSAGE_TYPES.PROCESS_SHOULD_COLLAPSE:
        {
          const collapse = webRequestService.processShouldCollapse(sender.tab, message.elementUrl, message.documentUrl, message.requestType);
          return {
            collapse,
            requestId: message.requestId
          };
        }

      case MESSAGE_TYPES.PROCESS_SHOULD_COLLAPSE_MANY:
        {
          const requests = webRequestService.processShouldCollapseMany(sender.tab, message.documentUrl, message.requests);
          return {
            requests
          };
        }

      case MESSAGE_TYPES.ON_OPEN_FILTERING_LOG_PAGE:
        filtering_log_browsers.onOpenFilteringLogPage();
        break;

      case MESSAGE_TYPES.ON_CLOSE_FILTERING_LOG_PAGE:
        filtering_log_browsers.onCloseFilteringLogPage();
        break;

      case MESSAGE_TYPES.CLEAR_EVENTS_BY_TAB_ID:
        filtering_log_browsers.clearEventsByTabId(data.tabId, data.ignorePreserveLog);
        break;

      case MESSAGE_TYPES.REFRESH_PAGE:
        filtering_log_browsers.clearEventsByTabId(data.tabId);
        await tabsApi.reload(data.tabId);
        break;

      case MESSAGE_TYPES.GET_TAB_FRAME_INFO_BY_ID:
        {
          if (data.tabId) {
            const frameInfo = frames_frames.getFrameInfo({
              tabId: data.tabId
            });
            return {
              frameInfo
            };
          }

          const tab = await tabsApi.getActive();

          if (tab) {
            const frameInfo = frames_frames.getFrameInfo(tab);
            return {
              frameInfo
            };
          }

          break;
        }

      case MESSAGE_TYPES.GET_FILTERING_INFO_BY_TAB_ID:
        {
          const {
            tabId
          } = data;
          return filtering_log_browsers.getFilteringInfoByTabId(tabId);
        }

      case MESSAGE_TYPES.SYNCHRONIZE_OPEN_TABS:
        {
          return filtering_log_browsers.synchronizeOpenTabs();
        }

      case MESSAGE_TYPES.ADD_FILTERING_SUBSCRIPTION:
        {
          const {
            url,
            title
          } = message;
          await uiService.openCustomFiltersModal(url, title);
          break;
        }
      // Popup methods

      case MESSAGE_TYPES.ADD_ALLOWLIST_DOMAIN_POPUP:
        {
          const tab = await tabsApi.getActive(data.tabId);

          if (tab) {
            uiService.allowlistTab(tab);
          }

          break;
        }

      case MESSAGE_TYPES.REMOVE_ALLOWLIST_DOMAIN:
        {
          const tab = await tabsApi.getActive(data.tabId);

          if (tab) {
            uiService.unAllowlistTab(tab);
          }

          break;
        }

      case MESSAGE_TYPES.CHANGE_APPLICATION_FILTERING_DISABLED:
        {
          const {
            state
          } = data;
          uiService.changeApplicationFilteringDisabled(state);
          break;
        }

      case MESSAGE_TYPES.OPEN_SITE_REPORT_TAB:
        {
          const {
            url
          } = data;
          uiService.openSiteReportTab(url);
          break;
        }

      case MESSAGE_TYPES.OPEN_ABUSE_TAB:
        {
          const {
            url
          } = data;
          uiService.openAbuseTab(url);
          break;
        }

      case MESSAGE_TYPES.OPEN_SETTINGS_TAB:
        uiService.openSettingsTab();
        break;

      case MESSAGE_TYPES.OPEN_ASSISTANT:
        uiService.openAssistant();
        break;

      case MESSAGE_TYPES.GET_TAB_INFO_FOR_POPUP:
        {
          const tab = await tabsApi.getActive(data.tabId); // There can't be data till localstorage is initialized

          const stats = storage_localStorage.isInitialized() ? pageStats.getStatisticsData() : {};

          if (tab) {
            const frameInfo = frames_frames.getFrameInfo(tab);
            return {
              frameInfo,
              stats,
              options: {
                showStatsSupported: true,
                isFirefoxBrowser: browserUtils.isFirefoxBrowser(),
                showInfoAboutFullVersion: settings.isShowInfoAboutAdguardFullVersion(),
                isMacOs: browserUtils.isMacOs(),
                isEdgeBrowser: browserUtils.isEdgeBrowser() || browserUtils.isEdgeChromiumBrowser(),
                notification: notifications.getCurrentNotification(),
                isDisableShowAdguardPromoInfo: settings.isDisableShowAdguardPromoInfo(),
                hasCustomRulesToReset: await userrules.hasRulesForUrl(frameInfo.url)
              },
              settings: settings.getAllSettings()
            };
          }

          break;
        }

      case MESSAGE_TYPES.SET_NOTIFICATION_VIEWED:
        notifications.setNotificationViewed(data.withDelay);
        break;

      case MESSAGE_TYPES.GET_STATISTICS_DATA:
        // There can't be data till localstorage is initialized
        if (!storage_localStorage.isInitialized()) {
          return {};
        }

        return {
          stats: pageStats.getStatisticsData()
        };

      case MESSAGE_TYPES.SAVE_CSS_HITS_STATS:
        processSaveCssHitStats(sender.tab, message.stats);
        break;

      case MESSAGE_TYPES.LOAD_SETTINGS_JSON:
        {
          const appVersion = backgroundPage.app.getVersion();
          const json = await settingsProvider.loadSettingsBackup();
          return {
            content: json,
            appVersion
          };
        }

      case MESSAGE_TYPES.APPLY_SETTINGS_JSON:
        {
          const {
            json
          } = data;
          return settingsProvider.applySettingsBackup(json);
        }

      case MESSAGE_TYPES.ADD_URL_TO_TRUSTED:
        {
          const {
            url
          } = data;
          await documentFilterService.addToTrusted(url);
          break;
        }

      case MESSAGE_TYPES.RESET_CUSTOM_RULES_FOR_PAGE:
        {
          const {
            url,
            tabId
          } = data;
          await userrules.removeRulesByUrl(url); // wait until request filter is updated

          await new Promise(resolve => {
            const listenerId = listeners.addListener(event => {
              if (event === listeners.REQUEST_FILTER_UPDATED) {
                listeners.removeListener(listenerId);
                resolve();
              }
            });
          }); // reload tab

          await tabsApi.reload(tabId, url);
          break;
        }

      case MESSAGE_TYPES.SET_PRESERVE_LOG_STATE:
        {
          const {
            state
          } = data;
          filtering_log_browsers.setPreserveLogState(state);
          break;
        }

      case MESSAGE_TYPES.GET_USER_RULES_EDITOR_DATA:
        {
          return {
            userRules: await userrules.getUserRulesText(),
            settings: settings.getAllSettings()
          };
        }

      case MESSAGE_TYPES.GET_EDITOR_STORAGE_CONTENT:
        {
          return editorStorage.getContent();
        }

      case MESSAGE_TYPES.SET_EDITOR_STORAGE_CONTENT:
        {
          const {
            content
          } = data;
          editorStorage.setContent(content);
          break;
        }

      case MESSAGE_TYPES.CONVERT_RULES_TEXT:
        {
          const {
            content
          } = data;
          return tsurlfilter_browser.RuleConverter.convertRules(content);
        }

      default:
        // Unhandled message
        throw new Error(`There is no such message type ${message.type}`);
    }

    return Promise.resolve();
  };

  return handleMessage;
};
/**
 *  Initialize Content => BackgroundPage messaging
 */


const init = () => {
  // Add event listener for messages from popup page, options page and content scripts
  backgroundPage.runtime.onMessage.addListener(createMessageHandler());
  backgroundPage.runtime.onConnect.addListener(longLivedMessageHandler);
};

const messageHandler = {
  init
};
;// CONCATENATED MODULE: ./Extension/pages/background/index.js








start();
webrequest.init();
requestSanitizer.init();
localeDetect.init();
messageHandler.init();
window.adguard = {
  tabs: tabsApi,
  filtersUpdate: filtersUpdate,
  userrules: userrules
};
})();

/******/ })()
;