[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"modules\": false\n      }\n    ],\n    \"@babel/preset-flow\"\n  ],\n  \"plugins\": [\n    \"@babel/plugin-transform-flow-strip-types\",\n    \"@babel/plugin-syntax-dynamic-import\",\n    \"@babel/plugin-syntax-import-meta\",\n    \"@babel/plugin-proposal-class-properties\",\n    \"@babel/plugin-proposal-json-strings\",\n    [\n      \"@babel/plugin-proposal-decorators\",\n      {\n        \"legacy\": true\n      }\n    ],\n    \"@babel/plugin-proposal-function-sent\",\n    \"@babel/plugin-proposal-export-namespace-from\",\n    \"@babel/plugin-proposal-numeric-separator\",\n    \"@babel/plugin-proposal-throw-expressions\"\n  ]\n}\n"
  },
  {
    "path": ".browserslistrc",
    "content": "Firefox >= 22\nChrome >= 5\nSafari >= 6\nOpera >= 25\nAndroid >= 4.4\nBlackberry >= 10\nOperaMobile >= 37\nFirefoxAndroid >= 47\nSamsung >= 4\nExplorer >= 9\n"
  },
  {
    "path": ".codeclimate.yml",
    "content": "---\nengines:\n  csslint:\n    enabled: true\n  duplication:\n    enabled: true\n    config:\n      languages:\n      - ruby\n      - javascript\n      - python\n      - php\n  eslint:\n    enabled: true\n  fixme:\n    enabled: true\nratings:\n  paths:\n  - \"**.css\"\n  - \"**.inc\"\n  - \"**.js\"\n  - \"**.jsx\"\n  - \"**.module\"\n  - \"**.php\"\n  - \"**.py\"\n  - \"**.rb\"\nexclude_paths:\n- node_modules/\n- tests/\n- bin/\n"
  },
  {
    "path": ".csslintrc",
    "content": "--exclude-exts=.min.css\n--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes\n"
  },
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\ntab_width = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".eslintignore",
    "content": "**/*{.,-}min.js\n"
  },
  {
    "path": ".eslintrc.yml",
    "content": "---\nparserOptions:\n  sourceType: module\n  ecmaFeatures:\n    jsx: true\n\nenv:\n  amd: true\n  browser: true\n  es6: true\n  jquery: true\n  node: true\n\n# http://eslint.org/docs/rules/\nrules:\n  # Possible Errors\n  no-await-in-loop: off\n  no-cond-assign: error\n  no-console: off\n  no-constant-condition: error\n  no-control-regex: error\n  no-debugger: error\n  no-dupe-args: error\n  no-dupe-keys: error\n  no-duplicate-case: error\n  no-empty-character-class: error\n  no-empty: error\n  no-ex-assign: error\n  no-extra-boolean-cast: error\n  no-extra-parens: off\n  no-extra-semi: error\n  no-func-assign: error\n  no-inner-declarations:\n    - error\n    - functions\n  no-invalid-regexp: error\n  no-irregular-whitespace: error\n  no-negated-in-lhs: error\n  no-obj-calls: error\n  no-prototype-builtins: off\n  no-regex-spaces: error\n  no-sparse-arrays: error\n  no-template-curly-in-string: off\n  no-unexpected-multiline: error\n  no-unreachable: error\n  no-unsafe-finally: off\n  no-unsafe-negation: off\n  use-isnan: error\n  valid-jsdoc: off\n  valid-typeof: error\n\n  # Best Practices\n  accessor-pairs: error\n  array-callback-return: off\n  block-scoped-var: off\n  class-methods-use-this: off\n  complexity:\n    - error\n    - 6\n  consistent-return: off\n  curly: off\n  default-case: off\n  dot-location: off\n  dot-notation: off\n  eqeqeq: error\n  guard-for-in: error\n  no-alert: error\n  no-caller: error\n  no-case-declarations: error\n  no-div-regex: error\n  no-else-return: off\n  no-empty-function: off\n  no-empty-pattern: error\n  no-eq-null: error\n  no-eval: error\n  no-extend-native: error\n  no-extra-bind: error\n  no-extra-label: off\n  no-fallthrough: error\n  no-floating-decimal: off\n  no-global-assign: off\n  no-implicit-coercion: off\n  no-implied-eval: error\n  no-invalid-this: off\n  no-iterator: error\n  no-labels:\n    - error\n    - allowLoop: true\n      allowSwitch: true\n  no-lone-blocks: error\n  no-loop-func: error\n  no-magic-number: off\n  no-multi-spaces: off\n  no-multi-str: off\n  no-native-reassign: error\n  no-new-func: error\n  no-new-wrappers: error\n  no-new: error\n  no-octal-escape: error\n  no-octal: error\n  no-param-reassign: off\n  no-proto: error\n  no-redeclare: error\n  no-restricted-properties: off\n  no-return-assign: error\n  no-return-await: off\n  no-script-url: error\n  no-self-assign: off\n  no-self-compare: error\n  no-sequences: off\n  no-throw-literal: off\n  no-unmodified-loop-condition: off\n  no-unused-expressions: error\n  no-unused-labels: off\n  no-useless-call: error\n  no-useless-concat: error\n  no-useless-escape: off\n  no-useless-return: off\n  no-void: error\n  no-warning-comments: off\n  no-with: error\n  prefer-promise-reject-errors: off\n  radix: error\n  require-await: off\n  vars-on-top: off\n  wrap-iife: error\n  yoda: off\n\n  # Strict\n  strict: off\n\n  # Variables\n  init-declarations: off\n  no-catch-shadow: error\n  no-delete-var: error\n  no-label-var: error\n  no-restricted-globals: off\n  no-shadow-restricted-names: error\n  no-shadow: off\n  no-undef-init: error\n  no-undef: off\n  no-undefined: off\n  no-unused-vars: off\n  no-use-before-define: off\n\n  # Node.js and CommonJS\n  callback-return: error\n  global-require: error\n  handle-callback-err: error\n  no-mixed-requires: off\n  no-new-require: off\n  no-path-concat: error\n  no-process-env: off\n  no-process-exit: error\n  no-restricted-modules: off\n  no-sync: off\n\n  # Stylistic Issues\n  array-bracket-spacing: off\n  block-spacing: off\n  brace-style: off\n  camelcase: off\n  capitalized-comments: off\n  comma-dangle:\n    - error\n    - never\n  comma-spacing: off\n  comma-style: off\n  computed-property-spacing: off\n  consistent-this: off\n  eol-last: off\n  func-call-spacing: off\n  func-name-matching: off\n  func-names: off\n  func-style: off\n  id-length: off\n  id-match: off\n  indent: off\n  jsx-quotes: off\n  key-spacing: off\n  keyword-spacing: off\n  line-comment-position: off\n  linebreak-style: off\n  lines-around-comment: off\n  lines-around-directive: off\n  max-depth: off\n  max-len: off\n  max-nested-callbacks: off\n  max-params: off\n  max-statements-per-line: off\n  max-statements:\n    - error\n    - 30\n  multiline-ternary: off\n  new-cap: off\n  new-parens: off\n  newline-after-var: off\n  newline-before-return: off\n  newline-per-chained-call: off\n  no-array-constructor: off\n  no-bitwise: off\n  no-continue: off\n  no-inline-comments: off\n  no-lonely-if: off\n  no-mixed-operators: off\n  no-mixed-spaces-and-tabs: off\n  no-multi-assign: off\n  no-multiple-empty-lines: off\n  no-negated-condition: off\n  no-nested-ternary: off\n  no-new-object: off\n  no-plusplus: off\n  no-restricted-syntax: off\n  no-spaced-func: off\n  no-tabs: off\n  no-ternary: off\n  no-trailing-spaces: off\n  no-underscore-dangle: off\n  no-unneeded-ternary: off\n  object-curly-newline: off\n  object-curly-spacing: off\n  object-property-newline: off\n  one-var-declaration-per-line: off\n  one-var: off\n  operator-assignment: off\n  operator-linebreak: off\n  padded-blocks: off\n  quote-props: off\n  quotes: off\n  require-jsdoc: off\n  semi-spacing: off\n  semi: off\n  sort-keys: off\n  sort-vars: off\n  space-before-blocks: off\n  space-before-function-paren: off\n  space-in-parens: off\n  space-infix-ops: off\n  space-unary-ops: off\n  spaced-comment: off\n  template-tag-spacing: off\n  unicode-bom: off\n  wrap-regex: off\n\n  # ECMAScript 6\n  arrow-body-style: off\n  arrow-parens: off\n  arrow-spacing: off\n  constructor-super: off\n  generator-star-spacing: off\n  no-class-assign: off\n  no-confusing-arrow: off\n  no-const-assign: off\n  no-dupe-class-members: off\n  no-duplicate-imports: off\n  no-new-symbol: off\n  no-restricted-imports: off\n  no-this-before-super: off\n  no-useless-computed-key: off\n  no-useless-constructor: off\n  no-useless-rename: off\n  no-var: off\n  object-shorthand: off\n  prefer-arrow-callback: off\n  prefer-const: off\n  prefer-destructuring: off\n  prefer-numeric-literals: off\n  prefer-rest-params: off\n  prefer-reflect: off\n  prefer-spread: off\n  prefer-template: off\n  require-yield: off\n  rest-spread-spacing: off\n  sort-imports: off\n  symbol-description: off\n  template-curly-spacing: off\n  yield-star-spacing: off\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\n.*/node_modules/.*\n\n[include]\n.*/src/.*\n\n[options]\n# Add emojis to status messages because emojis are cool 😎\nemoji=true\n\n# Enabled strict argument types\nexperimental.strict_type_args=true\n\n# Only run flow on the following file extensions\nmodule.file_ext=.js\n\nmodule.name_mapper='^push$' -> '<PROJECT_ROOT>/src/push/'\nmodule.name_mapper='^types$' -> '<PROJECT_ROOT>/src/types.js'\nmodule.name_mapper='^agents$' -> '<PROJECT_ROOT>/src/agents'\n\n[version]\n^0.57.3\n"
  },
  {
    "path": ".gitignore",
    "content": "# Created by https://www.gitignore.io\n\n### OSX ###\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n\n### Node ###\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\ndist\n\n# Dependency directory\n# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git\nnode_modules\n\n.idea\n\n# User-specific stuff:\n.idea/workspace.xml\n.idea/tasks.xml\n\n# Sensitive or high-churn files:\n.idea/dataSources/\n.idea/dataSources.ids\n.idea/dataSources.xml\n.idea/dataSources.local.xml\n.idea/sqlDataSources.xml\n.idea/dynamic.xml\n.idea/uiDesigner.xml\n\n# Gradle:\n.idea/gradle.xml\n.idea/libraries\n\n# Mongo Explorer plugin:\n.idea/mongoSettings.xml\n\n## File-based project format:\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n"
  },
  {
    "path": ".npmignore",
    "content": ".*\n"
  },
  {
    "path": ".nvmrc",
    "content": "v8.12"
  },
  {
    "path": ".prettierrc",
    "content": "singleQuote: true\nsemi: true\nuseTabs: false\ntabWidth: 4\nprintWidth: 80"
  },
  {
    "path": ".travis.yml",
    "content": "env:\n  global:\n  - CC_TEST_REPORTER_ID=71e04b5c32896d7201c79e2db2af1a89fc375f668392802961019875e71b179f\n  - GIT_COMMITTED_AT=$(if [ \"$TRAVIS_PULL_REQUEST\" == \"false\" ]; then git log -1 --pretty=format:%ct;\n    else git log -1 --skip 1 --pretty=format:%ct; fi)\n  - secure: AwJJp7im+vXzxa/UsYu/EJNppu+ss9l0GW8ftaXLNnMRkLJyo6m24DCJuhfH/ynxrSq5b2Zc7gEqDfxVWUgpNR+rrHZoHe+R/QnL60sqQXE2KvblDvG4o4e9F7vFp1xsohJ3/TTm6footWEiVlP25oVkQgi/oWhFsygJD6VGerDa2CodtU2r4p6UV5KuI8mUZuQg+rndkosMZa1BkZcz6v8e1AmJkGiIl/Agw0ye6C9iav4KoU+EXRyoxEq+dTAuhnVKA3CntOngoPDrUTQy5303x6Gzaz7uByWIyIR+uEud65RvCBduxCgREazkXdCqd/vCS65gYYktxl3fNG2so5VpKAbF/pTOylWexB10xhB+k+alIxhl3QytUx1pqDR4WI6c8d6ot+sZd7AjwvlyWdwDPuLoDB2eA18K3HbFMgjONmJFFI3gyKfyg1z5FfZm6dogfuQGZeSyxuedDAo+FygKGbgvBa+JHerR1WjU+TnFcVpwgaX/sma8Q4ff9WYLw2YOIiSi0H5V5tDi8lrtOqZmIYH4Vv2Cbl1gaAsVOOo+IBfTWor4oJzAb/jRKuNbqvhUJIqW6RYS7f8c/LMrcdn+LWHGj3zcFQ+LNFxID4OCghf7A3FvmE8A5XD07w04ofnWzrgqzgWy5+38Qj23l5IpFNgD2XGNohk7JpeGm3E=\nlanguage: node_js\nnode_js:\n- lts/*\nbefore_install: yarn global add greenkeeper-lockfile@1\nbefore_script:\n- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64\n  > ./cc-test-reporter\n- chmod +x ./cc-test-reporter\n- ./cc-test-reporter before-build\n- greenkeeper-lockfile-update\nscript:\n- npm run test\nafter_script:\n- if [ \"$TRAVIS_PULL_REQUEST\" == \"false\" ]; then ./cc-test-reporter after-build --exit-code\n  $TRAVIS_TEST_RESULT; fi\n- greenkeeper-lockfile-upload\n- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing Guidelines\n\nSo you want to contribute to Push, huh? Well lucky for you, it's really easy to do so, because you're just dealing with like, a few hundred lines of JavaScript. It's not hard.\n\nAlright. Now calm down and take a few deep breaths. Here we go. All you have to remember is two commands... think you can do that?\n\nTo BUILD Push, just run:\n\n```bash\n$ npm run build\n```\n\nTo TEST Push on BrowserStack, run:\n\n```bash\n$ npm run test\n```\n\nSee? Not hard at all. Unfortunately the Notifications API doesn't always play nicely with local sites, so don't get discouraged if you try running Push in a local HTML file and it doesn't work.\n\nTo TEST Push on a specific, locally-installed browser, you can run one of the following:\n\n```bash\n$ npm run test:opera\n$ npm run test:firefox\n$ npm run test:chrome\n$ npm run test:safari\n```\n\n### Testing & Travis\n\nPush uses the [Karma](https://karma-runner.github.io/1.0/index.html) JavaScript test runner, so read up on that if you want to make changes to any of the tests that are run. These tests are run post-push by [Travis CI](https://travis-ci.org), so look into that if you want to make any Travis configuration changes. Although, at this point I'd say Travis is all set. The tests might want to be expanded though.\n\n### REAL IMPORTANT STUFF\n\n**THERE IS ONLY ONE RULE TO PUSH CLUB** (and no, it's not that you can't talk about it). **WHENEVER** you make changes to `Push.js`, **RECOMPILE** and commit `push.min.js` as well. Until this build process can be wrapped into a sexy git hook of some sort, this is how changes to the library need to occur. **YOUR PR WILL NOT BE APPROVED UNLESS THIS HAPPENS**. That said, I did let it slide once because I wasn't thinking, but that's why I wrote this file to make sure it will never happen again.\n\nOutside of that, contributing should not be at all scary and should be a fun and positive process. Now go out and write some killer JS! Wait... is there even such a thing?\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# The MIT License (MIT)\n\nCopyright (c) 2016 Tyler Nickerson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n    \n[<img src=\"https://raw.githubusercontent.com/Nickersoft/push.js/master/logo.png\" width=\"250\">](http://pushjs.org)\n<br/><br/>\n\n[![Build Status](https://img.shields.io/travis/Nickersoft/push.js.svg)](https://travis-ci.org/Nickersoft/push.js) \n[![Coverage Status](https://img.shields.io/coveralls/Nickersoft/push.js.svg)](https://coveralls.io/github/Nickersoft/push.js?branch=master) \n[![Known Vulnerabilities](https://snyk.io/test/github/nickersoft/push.js/badge.svg)](https://snyk.io/test/github/nickersoft/push.js) \n[![Maintainability](https://api.codeclimate.com/v1/badges/52747084d9786c1570df/maintainability)](https://codeclimate.com/github/Nickersoft/push.js/maintainability)\n\n[![npm version](https://img.shields.io/npm/v/push.js.svg)](https://npmjs.com/package/push.js) \n[![npm](https://img.shields.io/npm/dm/push.js.svg)](https://npmjs.com/package/push.js)\n[![Greenkeeper badge](https://badges.greenkeeper.io/Nickersoft/push.js.svg)](https://greenkeeper.io/) \n\n*Now a proud user of*\n\n[<img src=\"https://raw.githubusercontent.com/Nickersoft/push.js/master/browserstack.png\" width=\"200px\" />](https://browserstack.com)\n\n</div>\n\n> ## Important Notice\n> Push is currently looking for co-maintainers of the repo. The guy who originally made this library, [Tyler Nickerson](https://tylernickerson.com), while still visiting this repo from time to time, is busy trying to work on his company [Linguistic](https://github.com/linguistic) right now. As a result, he may not have time to answer everyone or fix bugs as quickly as they would like him too. If you find it pretty easy to find your way around this code and think you could help some people out, shoot me a message at [nickersoft@gmail.com](mailto:nickersoft@gmail.com) and let's talk.\n\n### What is Push? ###\n\nPush is the fastest way to get up and running with Javascript desktop notifications. A fairly new addition to the\nofficial specification, the Notification API allows modern browsers such as Chrome, Safari, Firefox, and IE 9+ to push\nnotifications to a user's desktop. Push acts as a cross-browser solution to this API, falling back to use  older\nimplementations if the user's browser does not support the new API.\n\nYou can quickly install Push via [npm](http://npmjs.com):\n\n```\nnpm install push.js --save\n```\n\nOr, if you want something a little more lightweight, you can give [Bower](http://bower.io) a try:\n\n```\nbower install push.js --save\n```\n\n### Full Documentation ###\nFull documentation for Push can be found at the project's new homepage [https://pushjs.org](https://pushjs.org).\nSee you there!\n\n### Development ###\n\nIf you feel like this library is your jam and you want to contribute (or you think I'm an idiot who missed something),\ncheck out Push's neat [contributing guidelines](CONTRIBUTING.md) on how you can make your mark.\n\n### Credits ###\nPush is based off the following work:\n\n1. [HTML5-Desktop-Notifications](https://github.com/ttsvetko/HTML5-Desktop-Notifications) by [Tsvetan Tsvetkov](https://github.com/ttsvetko)\n2. [notify.js](https://github.com/alexgibson/notify.js) by [Alex Gibson](https://github.com/alexgibson)\n"
  },
  {
    "path": "bin/push.js",
    "content": "/**\n * @license\n *\n * Push v1.0.9\n * =========\n * A compact, cross-browser solution for the JavaScript Notifications API\n *\n * Credits\n * -------\n * Tsvetan Tsvetkov (ttsvetko)\n * Alex Gibson (alexgibson)\n *\n * License\n * -------\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015-2017 Tyler Nickerson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n!function(i,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):(i=i||self).Push=t()}(this,function(){\"use strict\";var i={errors:{incompatible:\"\".concat(\"PushError:\",\" Push.js is incompatible with browser.\"),invalid_plugin:\"\".concat(\"PushError:\",\" plugin class missing from plugin manifest (invalid plugin). Please check the documentation.\"),invalid_title:\"\".concat(\"PushError:\",\" title of notification must be a string\"),permission_denied:\"\".concat(\"PushError:\",\" permission request declined\"),sw_notification_error:\"\".concat(\"PushError:\",\" could not show a ServiceWorker notification due to the following reason: \"),sw_registration_error:\"\".concat(\"PushError:\",\" could not register the ServiceWorker due to the following reason: \"),unknown_interface:\"\".concat(\"PushError:\",\" unable to create notification: unknown interface\")}};function t(i){return(t=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(i){return typeof i}:function(i){return i&&\"function\"==typeof Symbol&&i.constructor===Symbol&&i!==Symbol.prototype?\"symbol\":typeof i})(i)}function n(i,t){if(!(i instanceof t))throw new TypeError(\"Cannot call a class as a function\")}function e(i,t){for(var n=0;n<t.length;n++){var e=t[n];e.enumerable=e.enumerable||!1,e.configurable=!0,\"value\"in e&&(e.writable=!0),Object.defineProperty(i,e.key,e)}}function o(i,t,n){return t&&e(i.prototype,t),n&&e(i,n),i}function r(i,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function\");i.prototype=Object.create(t&&t.prototype,{constructor:{value:i,writable:!0,configurable:!0}}),t&&c(i,t)}function s(i){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(i){return i.__proto__||Object.getPrototypeOf(i)})(i)}function c(i,t){return(c=Object.setPrototypeOf||function(i,t){return i.__proto__=t,i})(i,t)}function a(i,t){return!t||\"object\"!=typeof t&&\"function\"!=typeof t?function(i){if(void 0===i)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return i}(i):t}var u=function(){function i(t){n(this,i),this._win=t,this.GRANTED=\"granted\",this.DEFAULT=\"default\",this.DENIED=\"denied\",this._permissions=[this.GRANTED,this.DEFAULT,this.DENIED]}return o(i,[{key:\"request\",value:function(i,t){return arguments.length>0?this._requestWithCallback.apply(this,arguments):this._requestAsPromise()}},{key:\"_requestWithCallback\",value:function(i,t){var n,e=this,o=this.get(),r=!1,s=function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:e._win.Notification.permission;r||(r=!0,void 0===n&&e._win.webkitNotifications&&(n=e._win.webkitNotifications.checkPermission()),n===e.GRANTED||0===n?i&&i():t&&t())};o!==this.DEFAULT?s(o):this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission?this._win.webkitNotifications.requestPermission(s):this._win.Notification&&this._win.Notification.requestPermission?(n=this._win.Notification.requestPermission(s))&&n.then&&n.then(s).catch(function(){t&&t()}):i&&i()}},{key:\"_requestAsPromise\",value:function(){var i=this,t=this.get(),n=t!==this.DEFAULT,e=this._win.Notification&&this._win.Notification.requestPermission,o=this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission;return new Promise(function(r,s){var c,a=!1,u=function(t){a||(a=!0,!function(t){return t===i.GRANTED||0===t}(t)?s():r())};n?u(t):o?i._win.webkitNotifications.requestPermission(function(i){u(i)}):e?(c=i._win.Notification.requestPermission(u))&&c.then&&c.then(u).catch(s):r()})}},{key:\"has\",value:function(){return this.get()===this.GRANTED}},{key:\"get\",value:function(){return this._win.Notification&&this._win.Notification.permission?this._win.Notification.permission:this._win.webkitNotifications&&this._win.webkitNotifications.checkPermission?this._permissions[this._win.webkitNotifications.checkPermission()]:navigator.mozNotification?this.GRANTED:this._win.external&&this._win.external.msIsSiteMode?this._win.external.msIsSiteMode()?this.GRANTED:this.DEFAULT:this.GRANTED}}]),i}(),f=function(){function i(){n(this,i)}return o(i,null,[{key:\"isUndefined\",value:function(i){return void 0===i}},{key:\"isNull\",value:function(i){return null===obj}},{key:\"isString\",value:function(i){return\"string\"==typeof i}},{key:\"isFunction\",value:function(i){return i&&\"[object Function]\"==={}.toString.call(i)}},{key:\"isObject\",value:function(i){return\"object\"===t(i)}},{key:\"objectMerge\",value:function(i,t){for(var n in t)i.hasOwnProperty(n)&&this.isObject(i[n])&&this.isObject(t[n])?this.objectMerge(i[n],t[n]):i[n]=t[n]}}]),i}(),l=function i(t){n(this,i),this._win=t},h=function(i){function t(){return n(this,t),a(this,s(t).apply(this,arguments))}return r(t,l),o(t,[{key:\"isSupported\",value:function(){return void 0!==this._win.Notification}},{key:\"create\",value:function(i,t){return new this._win.Notification(i,{icon:f.isString(t.icon)||f.isUndefined(t.icon)||f.isNull(t.icon)?t.icon:t.icon.x32,body:t.body,tag:t.tag,requireInteraction:t.requireInteraction})}},{key:\"close\",value:function(i){i.close()}}]),t}(),_=function(t){function e(){return n(this,e),a(this,s(e).apply(this,arguments))}return r(e,l),o(e,[{key:\"isSupported\",value:function(){return void 0!==this._win.navigator&&void 0!==this._win.navigator.serviceWorker}},{key:\"getFunctionBody\",value:function(i){var t=i.toString().match(/function[^{]+{([\\s\\S]*)}$/);return null!=t&&t.length>1?t[1]:null}},{key:\"create\",value:function(t,n,e,o,r){var s=this;this._win.navigator.serviceWorker.register(o),this._win.navigator.serviceWorker.ready.then(function(o){var c={id:t,link:e.link,origin:document.location.href,onClick:f.isFunction(e.onClick)?s.getFunctionBody(e.onClick):\"\",onClose:f.isFunction(e.onClose)?s.getFunctionBody(e.onClose):\"\"};void 0!==e.data&&null!==e.data&&(c=Object.assign(c,e.data)),o.showNotification(n,{icon:e.icon,body:e.body,vibrate:e.vibrate,tag:e.tag,data:c,requireInteraction:e.requireInteraction,silent:e.silent}).then(function(){o.getNotifications().then(function(i){o.active.postMessage(\"\"),r(i)})}).catch(function(t){throw new Error(i.errors.sw_notification_error+t.message)})}).catch(function(t){throw new Error(i.errors.sw_registration_error+t.message)})}},{key:\"close\",value:function(){}}]),e}(),v=function(i){function t(){return n(this,t),a(this,s(t).apply(this,arguments))}return r(t,l),o(t,[{key:\"isSupported\",value:function(){return void 0!==this._win.navigator.mozNotification}},{key:\"create\",value:function(i,t){var n=this._win.navigator.mozNotification.createNotification(i,t.body,t.icon);return n.show(),n}}]),t}(),d=function(i){function t(){return n(this,t),a(this,s(t).apply(this,arguments))}return r(t,l),o(t,[{key:\"isSupported\",value:function(){return void 0!==this._win.external&&void 0!==this._win.external.msIsSiteMode}},{key:\"create\",value:function(i,t){return this._win.external.msSiteModeClearIconOverlay(),this._win.external.msSiteModeSetIconOverlay(f.isString(t.icon)||f.isUndefined(t.icon)?t.icon:t.icon.x16,i),this._win.external.msSiteModeActivate(),null}},{key:\"close\",value:function(){this._win.external.msSiteModeClearIconOverlay()}}]),t}(),w=function(i){function t(){return n(this,t),a(this,s(t).apply(this,arguments))}return r(t,l),o(t,[{key:\"isSupported\",value:function(){return void 0!==this._win.webkitNotifications}},{key:\"create\",value:function(i,t){var n=this._win.webkitNotifications.createNotification(t.icon,i,t.body);return n.show(),n}},{key:\"close\",value:function(i){i.cancel()}}]),t}();return new(function(){function t(i){n(this,t),this._currentId=0,this._notifications={},this._win=i,this.Permission=new u(i),this._agents={desktop:new h(i),chrome:new _(i),firefox:new v(i),ms:new d(i),webkit:new w(i)},this._configuration={serviceWorker:\"/serviceWorker.min.js\",fallback:function(i){}}}return o(t,[{key:\"_closeNotification\",value:function(t){var n=!0,e=this._notifications[t];if(void 0!==e){if(n=this._removeNotification(t),this._agents.desktop.isSupported())this._agents.desktop.close(e);else if(this._agents.webkit.isSupported())this._agents.webkit.close(e);else{if(!this._agents.ms.isSupported())throw n=!1,new Error(i.errors.unknown_interface);this._agents.ms.close()}return n}return!1}},{key:\"_addNotification\",value:function(i){var t=this._currentId;return this._notifications[t]=i,this._currentId++,t}},{key:\"_removeNotification\",value:function(i){var t=!1;return this._notifications.hasOwnProperty(i)&&(delete this._notifications[i],t=!0),t}},{key:\"_prepareNotification\",value:function(i,t){var n,e=this;return n={get:function(){return e._notifications[i]},close:function(){e._closeNotification(i)}},t.timeout&&setTimeout(function(){n.close()},t.timeout),n}},{key:\"_serviceWorkerCallback\",value:function(i,t,n){var e=this,o=this._addNotification(i[i.length-1]);navigator&&navigator.serviceWorker&&(navigator.serviceWorker.addEventListener(\"message\",function(i){var t=JSON.parse(i.data);\"close\"===t.action&&Number.isInteger(t.id)&&e._removeNotification(t.id)}),n(this._prepareNotification(o,t))),n(null)}},{key:\"_createCallback\",value:function(i,t,n){var e,o=this,r=null;if(t=t||{},e=function(i){o._removeNotification(i),f.isFunction(t.onClose)&&t.onClose.call(o,r)},this._agents.desktop.isSupported())try{r=this._agents.desktop.create(i,t)}catch(e){var s=this._currentId,c=this.config().serviceWorker;this._agents.chrome.isSupported()&&this._agents.chrome.create(s,i,t,c,function(i){return o._serviceWorkerCallback(i,t,n)})}else this._agents.webkit.isSupported()?r=this._agents.webkit.create(i,t):this._agents.firefox.isSupported()?this._agents.firefox.create(i,t):this._agents.ms.isSupported()?r=this._agents.ms.create(i,t):(t.title=i,this.config().fallback(t));if(null!==r){var a=this._addNotification(r),u=this._prepareNotification(a,t);f.isFunction(r.addEventListener)&&(f.isFunction(t.onShow)&&r.addEventListener(\"show\",t.onShow),f.isFunction(t.onError)&&r.addEventListener(\"error\",t.onError),f.isFunction(t.onClick)&&r.addEventListener(\"click\",t.onClick),r.addEventListener(\"close\",function(){e(a)}),r.addEventListener(\"cancel\",function(){e(a)})),n(u)}n(null)}},{key:\"create\",value:function(t,n){var e,o=this;if(!f.isString(t))throw new Error(i.errors.invalid_title);return e=this.Permission.has()?function(i,e){try{o._createCallback(t,n,i)}catch(i){e(i)}}:function(e,r){o.Permission.request().then(function(){o._createCallback(t,n,e)}).catch(function(){r(i.errors.permission_denied)})},new Promise(e)}},{key:\"count\",value:function(){var i,t=0;for(i in this._notifications)this._notifications.hasOwnProperty(i)&&t++;return t}},{key:\"close\",value:function(i){var t;for(t in this._notifications)if(this._notifications.hasOwnProperty(t)&&this._notifications[t].tag===i)return this._closeNotification(t)}},{key:\"clear\",value:function(){var i,t=!0;for(i in this._notifications)this._notifications.hasOwnProperty(i)&&(t=t&&this._closeNotification(i));return t}},{key:\"supported\",value:function(){var i=!1;for(var t in this._agents)this._agents.hasOwnProperty(t)&&(i=i||this._agents[t].isSupported());return i}},{key:\"config\",value:function(i){return(void 0!==i||null!==i&&f.isObject(i))&&f.objectMerge(this._configuration,i),this._configuration}},{key:\"extend\",value:function(t){var n,e={}.hasOwnProperty;if(!e.call(t,\"plugin\"))throw new Error(i.errors.invalid_plugin);for(var o in e.call(t,\"config\")&&f.isObject(t.config)&&null!==t.config&&this.config(t.config),n=new(0,t.plugin)(this.config()))e.call(n,o)&&f.isFunction(n[o])&&(this[o]=n[o])}}]),t}())(\"undefined\"!=typeof window?window:global)});\n//# sourceMappingURL=push.js.map\n"
  },
  {
    "path": "bower.json",
    "content": "{\n  \"name\": \"push.js\",\n  \"description\": \"A compact, cross-browser solution for the Javascript Notifications API\",\n  \"main\": \"bin/push.js\",\n  \"authors\": [\n    \"Tyler Nickerson\"\n  ],\n  \"license\": \"MIT\",\n  \"homepage\": \"https://pushjs.org\",\n  \"ignore\": [\n    \"**/.*\",\n    \"coverage\",\n    \"node_modules\",\n    \"bower_components\",\n    \"tests\",\n    \"src\",\n    \"build\",\n    \"*.lock\",\n    \"*.json\"\n  ]\n}\n"
  },
  {
    "path": "index.d.ts",
    "content": "declare module 'push.js' {\n\n    const defaultPush: Push;\n    export default defaultPush;\n\n    class Push {\n        Permission: PushPermission;\n\n        create(title: string, params?: PushNotificationParams): Promise<PushNotification>\n\n        close(tag: string): void;\n\n        clear(): void;\n\n        config(params: PushParams): void;\n    }\n\n    export interface PushNotificationParams {\n        body?: string;\n        icon?: string;\n        link?: string;\n        timeout?: number;\n        tag?: string;\n        requireInteraction?: boolean;\n        vibrate?: boolean;\n        silent?: boolean;\n        onClick?: Function;\n        onError?: Function;\n    }\n\n    export interface PushParams {\n        serviceWorker?: string;\n        fallback?: Function;\n    }\n\n    export interface PushPermission {\n        DEFAULT: string;\n        GRANTED: string;\n        DENIED: string;\n\n        request(onGranted?: Function, onDenied?: Function): void;\n\n        has(): boolean;\n\n        get(): string;\n    }\n\n    export interface PushNotification {\n        close(): void;\n    }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"push.js\",\n    \"version\": \"1.0.12\",\n    \"description\": \"A compact, cross-browser solution for the Javascript Notifications API\",\n    \"main\": \"bin/push.min.js\",\n    \"scripts\": {\n        \"clean\": \"rimraf bin/\",\n        \"build\": \"rollup -c && uglifyjs --source-map -o bin/serviceWorker.min.js src/serviceWorker.js\",\n        \"test\": \"npm run build && karma start tests/karma.conf.js\",\n        \"test:chrome\": \"PUSHJS_TEST_BROWSER=Chrome npm run test\",\n        \"test:opera\": \"PUSHJS_TEST_BROWSER=Opera npm run test\",\n        \"test:firefox\": \"PUSHJS_TEST_BROWSER=Firefox npm run test\",\n        \"test:safari\": \"PUSHJS_TEST_BROWSER=Safari npm run test\",\n        \"prepublish\": \"npm run build\",\n        \"precommit\": \"lint-staged && npm run build && git add ./bin\"\n    },\n    \"files\": [\n        \"bin\",\n        \"*.md\",\n        \"*.png\",\n        \"*.d.ts\"\n    ],\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/Nickersoft/push.js\"\n    },\n    \"author\": \"Tyler Nickerson\",\n    \"license\": \"MIT\",\n    \"bugs\": {\n        \"url\": \"https://github.com/Nickersoft/push.js/issues\"\n    },\n    \"homepage\": \"https://github.com/Nickersoft/push.js\",\n    \"devDependencies\": {\n        \"@babel/core\": \"^7.5.5\",\n        \"@babel/plugin-proposal-class-properties\": \"^7.5.5\",\n        \"@babel/plugin-proposal-decorators\": \"^7.4.4\",\n        \"@babel/plugin-proposal-export-namespace-from\": \"^7.5.2\",\n        \"@babel/plugin-proposal-function-sent\": \"^7.5.0\",\n        \"@babel/plugin-proposal-json-strings\": \"^7.2.0\",\n        \"@babel/plugin-proposal-numeric-separator\": \"^7.2.0\",\n        \"@babel/plugin-proposal-throw-expressions\": \"^7.2.0\",\n        \"@babel/plugin-syntax-dynamic-import\": \"^7.2.0\",\n        \"@babel/plugin-syntax-import-meta\": \"^7.2.0\",\n        \"@babel/plugin-transform-flow-strip-types\": \"^7.4.4\",\n        \"@babel/plugin-transform-strict-mode\": \"^7.2.0\",\n        \"@babel/polyfill\": \"^7.4.4\",\n        \"@babel/preset-env\": \"^7.5.5\",\n        \"@babel/preset-flow\": \"^7.0.0\",\n        \"browserify\": \"^16.3.0\",\n        \"coveralls\": \"^3.0.5\",\n        \"flow-bin\": \"^0.103.0\",\n        \"husky\": \"^3.0.1\",\n        \"jasmine-core\": \"^3.4.0\",\n        \"js-yaml\": \"^3.13.1\",\n        \"karma\": \"^4.2.0\",\n        \"karma-browserstack-launcher\": \"~1.4.0\",\n        \"karma-chrome-launcher\": \"^3.0.0\",\n        \"karma-coverage\": \"^1.1.2\",\n        \"karma-firefox-launcher\": \"^1.1.0\",\n        \"karma-jasmine\": \"^2.0.1\",\n        \"karma-mocha-reporter\": \"^2.2.5\",\n        \"karma-opera-launcher\": \"^1.0.0\",\n        \"karma-safari-launcher\": \"^1.0.0\",\n        \"karma-sourcemap-loader\": \"^0.3.7\",\n        \"lint-staged\": \"^9.2.0\",\n        \"natives\": \"^1.1.6\",\n        \"platform\": \"^1.3.5\",\n        \"prettier\": \"^1.18.2\",\n        \"rimraf\": \"^2.6.3\",\n        \"rollup\": \"^1.17.0\",\n        \"rollup-plugin-alias\": \"^1.5.2\",\n        \"rollup-plugin-babel\": \"^4.3.3\",\n        \"rollup-plugin-commonjs\": \"^10.0.1\",\n        \"rollup-plugin-node-resolve\": \"^5.2.0\",\n        \"rollup-plugin-terser\": \"^5.1.1\"\n    },\n    \"lint-staged\": {\n        \"*.{js,json,css}\": [\n            \"prettier --write\",\n            \"git add\"\n        ]\n    },\n    \"dependencies\": {},\n    \"resolutions\": {\n        \"natives\": \"1.1.6\"\n    }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import path from \"path\";\nimport resolve from \"rollup-plugin-node-resolve\";\nimport babel from \"rollup-plugin-babel\";\nimport commonjs from \"rollup-plugin-commonjs\";\nimport alias from \"rollup-plugin-alias\";\nimport { terser } from \"rollup-plugin-terser\";\n\nconst license = `/**\n * @license\n *\n * Push v1.0.9\n * =========\n * A compact, cross-browser solution for the JavaScript Notifications API\n *\n * Credits\n * -------\n * Tsvetan Tsvetkov (ttsvetko)\n * Alex Gibson (alexgibson)\n *\n * License\n * -------\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2015-2017 Tyler Nickerson\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */`;\n\nconst common = {\n  input: \"src/index.js\",\n  output: {\n    banner: license,\n    file: \"bin/push.min.js\",\n    format: \"umd\",\n    name: \"Push\",\n    sourcemap: true\n  },\n  plugins: [\n    babel({\n      exclude: \"node_modules/**\"\n    }),\n    alias({\n      types: path.resolve(__dirname, \"src/types\"),\n      push: path.resolve(__dirname, \"src/push/index\"),\n      agents: path.resolve(__dirname, \"src/agents/index\")\n    }),\n    commonjs(),\n    resolve(),\n    terser({\n      output: {\n        beautify: false,\n        preamble: license\n      }\n    })\n  ]\n};\n\nexport default [\n  {\n    ...common,\n    output: {\n      ...common.output,\n      file: \"bin/push.js\"\n    }\n  },\n  {\n    ...common,\n    output: {\n      ...common.output,\n      file: \"bin/push.min.js\"\n    }\n  }\n];\n"
  },
  {
    "path": "src/agents/AbstractAgent.js",
    "content": "// @flow\nimport type { Global } from 'types';\n\nexport default class AbstractAgent {\n    _win: Global;\n\n    constructor(win: Global) {\n        this._win = win;\n    }\n}\n"
  },
  {
    "path": "src/agents/DesktopAgent.js",
    "content": "// @flow\nimport { AbstractAgent } from 'agents';\nimport { Util } from 'push';\nimport type { PushOptions, GenericNotification, Global } from 'types';\n\n/**\n * Notification agent for modern desktop browsers:\n * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+\n */\nexport default class DesktopAgent extends AbstractAgent {\n    _win: Global;\n\n    /**\n     * Returns a boolean denoting support\n     * @returns {Boolean} boolean denoting whether webkit notifications are supported\n     */\n    isSupported() {\n        return this._win.Notification !== undefined;\n    }\n\n    /**\n     * Creates a new notification\n     * @param title - notification title\n     * @param options - notification options array\n     * @returns {Notification}\n     */\n    create(title: string, options: PushOptions) {\n        return new this._win.Notification(title, {\n            icon:\n                Util.isString(options.icon) ||\n                Util.isUndefined(options.icon) ||\n                Util.isNull(options.icon)\n                    ? options.icon\n                    : options.icon.x32,\n            body: options.body,\n            tag: options.tag,\n            requireInteraction: options.requireInteraction\n        });\n    }\n\n    /**\n     * Close a given notification\n     * @param notification - notification to close\n     */\n    close(notification: GenericNotification) {\n        notification.close();\n    }\n}\n"
  },
  {
    "path": "src/agents/MSAgent.js",
    "content": "// @flow\nimport { AbstractAgent } from 'agents';\nimport { Util } from 'push';\nimport type { PushOptions, Global } from 'types';\n\n/**\n * Notification agent for IE9\n */\nexport default class MSAgent extends AbstractAgent {\n    _win: Global;\n\n    /**\n     * Returns a boolean denoting support\n     * @returns {Boolean} boolean denoting whether webkit notifications are supported\n     */\n    isSupported() {\n        return (\n            this._win.external !== undefined &&\n            this._win.external.msIsSiteMode !== undefined\n        );\n    }\n\n    /**\n     * Creates a new notification\n     * @param title - notification title\n     * @param options - notification options array\n     * @returns {Notification}\n     */\n    create(title: string, options: PushOptions) {\n        /* Clear any previous notifications */\n        this._win.external.msSiteModeClearIconOverlay();\n\n        this._win.external.msSiteModeSetIconOverlay(\n            Util.isString(options.icon) || Util.isUndefined(options.icon)\n                ? options.icon\n                : options.icon.x16,\n            title\n        );\n\n        this._win.external.msSiteModeActivate();\n\n        return null;\n    }\n\n    /**\n     * Close a given notification\n     * @param notification - notification to close\n     */\n    close() {\n        this._win.external.msSiteModeClearIconOverlay();\n    }\n}\n"
  },
  {
    "path": "src/agents/MobileChromeAgent.js",
    "content": "// @flow\nimport { Util, Messages } from 'push';\nimport { AbstractAgent } from 'agents';\nimport type { Global, GenericNotification, PushOptions } from 'types';\n\n/**\n * Notification agent for modern desktop browsers:\n * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+\n */\nexport default class MobileChromeAgent extends AbstractAgent {\n    _win: Global;\n\n    /**\n     * Returns a boolean denoting support\n     * @returns {Boolean} boolean denoting whether webkit notifications are supported\n     */\n    isSupported() {\n        return (\n            this._win.navigator !== undefined &&\n            this._win.navigator.serviceWorker !== undefined\n        );\n    }\n\n    /**\n     * Returns the function body as a string\n     * @param func\n     */\n    getFunctionBody(func: () => void) {\n        const str = func.toString().match(/function[^{]+{([\\s\\S]*)}$/);\n        return typeof str !== 'undefined' && str !== null && str.length > 1\n            ? str[1]\n            : null;\n    }\n\n    /**\n     * Creates a new notification\n     * @param id                ID of notification\n     * @param title             Title of notification\n     * @param options           Options object\n     * @param serviceWorker     ServiceWorker path\n     * @param callback          Callback function\n     */\n    create(\n        id: number,\n        title: string,\n        options: PushOptions,\n        serviceWorker: string,\n        callback: (GenericNotification[]) => void\n    ) {\n        /* Register ServiceWorker */\n        this._win.navigator.serviceWorker.register(serviceWorker);\n\n        this._win.navigator.serviceWorker.ready\n            .then(registration => {\n                /* Local data the service worker will use */\n                let localData = {\n                    id: id,\n                    link: options.link,\n                    origin: document.location.href,\n                    onClick: Util.isFunction(options.onClick)\n                        ? this.getFunctionBody(options.onClick)\n                        : '',\n                    onClose: Util.isFunction(options.onClose)\n                        ? this.getFunctionBody(options.onClose)\n                        : ''\n                };\n\n                /* Merge the local data with user-provided data */\n                if (options.data !== undefined && options.data !== null)\n                    localData = Object.assign(localData, options.data);\n\n                /* Show the notification */\n                registration\n                    .showNotification(title, {\n                        icon: options.icon,\n                        body: options.body,\n                        vibrate: options.vibrate,\n                        tag: options.tag,\n                        data: localData,\n                        requireInteraction: options.requireInteraction,\n                        silent: options.silent\n                    })\n                    .then(() => {\n                        registration.getNotifications().then(notifications => {\n                            /* Send an empty message so the ServiceWorker knows who the client is */\n                            registration.active.postMessage('');\n\n                            /* Trigger callback */\n                            callback(notifications);\n                        });\n                    })\n                    .catch(function(error) {\n                        throw new Error(\n                            Messages.errors.sw_notification_error +\n                                error.message\n                        );\n                    });\n            })\n            .catch(function(error) {\n                throw new Error(\n                    Messages.errors.sw_registration_error + error.message\n                );\n            });\n    }\n\n    /**\n     * Close all notification\n     */\n    close() {\n        // Can't do this with service workers\n    }\n}\n"
  },
  {
    "path": "src/agents/MobileFirefoxAgent.js",
    "content": "// @flow\nimport { AbstractAgent } from 'agents';\nimport type { Global, PushOptions } from 'types';\n\n/**\n * Notification agent for modern desktop browsers:\n * Safari 6+, Firefox 22+, Chrome 22+, Opera 25+\n */\nexport default class MobileFirefoxAgent extends AbstractAgent {\n    _win: Global;\n\n    /**\n     * Returns a boolean denoting support\n     * @returns {Boolean} boolean denoting whether webkit notifications are supported\n     */\n    isSupported() {\n        return this._win.navigator.mozNotification !== undefined;\n    }\n\n    /**\n     * Creates a new notification\n     * @param title - notification title\n     * @param options - notification options array\n     * @returns {Notification}\n     */\n    create(title: string, options: PushOptions) {\n        let notification = this._win.navigator.mozNotification.createNotification(\n            title,\n            options.body,\n            options.icon\n        );\n\n        notification.show();\n\n        return notification;\n    }\n}\n"
  },
  {
    "path": "src/agents/WebKitAgent.js",
    "content": "// @flow\nimport { AbstractAgent } from 'agents';\nimport type { Global, GenericNotification, PushOptions } from 'types';\n\n/**\n * Notification agent for old Chrome versions (and some) Firefox\n */\nexport default class WebKitAgent extends AbstractAgent {\n    _win: Global;\n\n    /**\n     * Returns a boolean denoting support\n     * @returns {Boolean} boolean denoting whether webkit notifications are supported\n     */\n    isSupported() {\n        return this._win.webkitNotifications !== undefined;\n    }\n\n    /**\n     * Creates a new notification\n     * @param title - notification title\n     * @param options - notification options array\n     * @returns {Notification}\n     */\n    create(title: string, options: PushOptions) {\n        let notification = this._win.webkitNotifications.createNotification(\n            options.icon,\n            title,\n            options.body\n        );\n\n        notification.show();\n\n        return notification;\n    }\n\n    /**\n     * Close a given notification\n     * @param notification - notification to close\n     */\n    close(notification: GenericNotification) {\n        notification.cancel();\n    }\n}\n"
  },
  {
    "path": "src/agents/index.js",
    "content": "import AbstractAgent from './AbstractAgent';\nimport DesktopAgent from './DesktopAgent';\nimport MobileChromeAgent from './MobileChromeAgent';\nimport MobileFirefoxAgent from './MobileFirefoxAgent';\nimport MSAgent from './MSAgent';\nimport WebKitAgent from './WebKitAgent';\n\nexport {\n    AbstractAgent,\n    DesktopAgent,\n    MobileChromeAgent,\n    MobileFirefoxAgent,\n    MSAgent,\n    WebKitAgent\n};\n"
  },
  {
    "path": "src/index.js",
    "content": "// @flow\nimport { Push } from 'push';\n\nexport default new Push(typeof window !== 'undefined' ? window : global);\n"
  },
  {
    "path": "src/push/Messages.js",
    "content": "// @flow\nconst errorPrefix = 'PushError:';\n\nexport default {\n    errors: {\n        incompatible: `${errorPrefix} Push.js is incompatible with browser.`,\n        invalid_plugin: `${errorPrefix} plugin class missing from plugin manifest (invalid plugin). Please check the documentation.`,\n        invalid_title: `${errorPrefix} title of notification must be a string`,\n        permission_denied: `${errorPrefix} permission request declined`,\n        sw_notification_error: `${errorPrefix} could not show a ServiceWorker notification due to the following reason: `,\n        sw_registration_error: `${errorPrefix} could not register the ServiceWorker due to the following reason: `,\n        unknown_interface: `${errorPrefix} unable to create notification: unknown interface`\n    }\n};\n"
  },
  {
    "path": "src/push/Permission.js",
    "content": "// @flow\nimport type { Global } from 'types';\n\nexport default class Permission {\n    // Private members\n    _permissions: string[];\n    _win: Global;\n\n    // Public members\n    GRANTED: string;\n    DEFAULT: string;\n    DENIED: string;\n\n    constructor(win: Global) {\n        this._win = win;\n        this.GRANTED = 'granted';\n        this.DEFAULT = 'default';\n        this.DENIED = 'denied';\n        this._permissions = [this.GRANTED, this.DEFAULT, this.DENIED];\n    }\n\n    /**\n   * Requests permission for desktop notifications\n   * @param {Function} onGranted - Function to execute once permission is granted\n   * @param {Function} onDenied - Function to execute once permission is denied\n   * @return {void, Promise}\n   */\n    request(onGranted: () => void, onDenied: () => void) {\n        return arguments.length > 0\n            ? this._requestWithCallback(...arguments)\n            : this._requestAsPromise();\n    }\n\n    /**\n   * Old permissions implementation deprecated in favor of a promise based one\n   * @deprecated Since V1.0.4\n   * @param {Function} onGranted - Function to execute once permission is granted\n   * @param {Function} onDenied - Function to execute once permission is denied\n   * @return {void}\n   */\n    _requestWithCallback(onGranted: () => void, onDenied: () => void) {\n        const existing = this.get();\n\n        var resolved = false;\n        var resolve = (result = this._win.Notification.permission) => {\n            if (resolved) return;\n            resolved = true;\n            if (typeof result === 'undefined' && this._win.webkitNotifications)\n                result = this._win.webkitNotifications.checkPermission();\n            if (result === this.GRANTED || result === 0) {\n                if (onGranted) onGranted();\n            } else if (onDenied) onDenied();\n        };\n        var request;\n\n        /* Permissions already set */\n        if (existing !== this.DEFAULT) {\n            resolve(existing);\n        } else if (\n            this._win.webkitNotifications &&\n            this._win.webkitNotifications.checkPermission\n        ) {\n            /* Safari 6+, Legacy webkit browsers */\n            this._win.webkitNotifications.requestPermission(resolve);\n        } else if (\n            this._win.Notification &&\n            this._win.Notification.requestPermission\n        ) {\n            /* Safari 12+ */\n            /* This resolve argument will only be used in Safari */\n            /* CHrome, instead, returns a Promise */\n            request = this._win.Notification.requestPermission(resolve);\n            if (request && request.then) {\n                /* Chrome 23+ */\n                request.then(resolve).catch(function() {\n                    if (onDenied) onDenied();\n                });\n            }\n        } else if (onGranted) {\n            /* Let the user continue by default */\n            onGranted();\n        }\n    }\n\n    /**\n   * Requests permission for desktop notifications in a promise based way\n   * @return {Promise}\n   */\n    _requestAsPromise(): Promise<void> {\n        const existing = this.get();\n\n        let isGranted = result => result === this.GRANTED || result === 0;\n\n        /* Permissions already set */\n        var hasPermissions = existing !== this.DEFAULT;\n\n        /* Safari 6+, Chrome 23+ */\n        var isModernAPI =\n            this._win.Notification && this._win.Notification.requestPermission;\n\n        /* Legacy webkit browsers */\n        var isWebkitAPI =\n            this._win.webkitNotifications &&\n            this._win.webkitNotifications.checkPermission;\n\n        return new Promise((resolvePromise, rejectPromise) => {\n            var resolved = false;\n            var resolver = result => {\n                if (resolved) return;\n                resolved = true;\n                isGranted(result) ? resolvePromise() : rejectPromise();\n            };\n            var request;\n\n            if (hasPermissions) {\n                resolver(existing);\n            } else if (isWebkitAPI) {\n                this._win.webkitNotifications.requestPermission(result => {\n                    resolver(result);\n                });\n            } else if (isModernAPI) {\n                /* Safari 12+ */\n                /* This resolver argument will only be used in Safari */\n                /* CHrome, instead, returns a Promise */\n                request = this._win.Notification.requestPermission(resolver);\n                if (request && request.then) {\n                    /* Chrome 23+ */\n                    request.then(resolver).catch(rejectPromise);\n                }\n            } else resolvePromise();\n        });\n    }\n\n    /**\n   * Returns whether Push has been granted permission to run\n   * @return {Boolean}\n   */\n    has() {\n        return this.get() === this.GRANTED;\n    }\n\n    /**\n   * Gets the permission level\n   * @return {Permission} The permission level\n   */\n    get() {\n        let permission;\n\n        /* Safari 6+, Chrome 23+ */\n        if (this._win.Notification && this._win.Notification.permission)\n            permission = this._win.Notification.permission;\n        else if (\n            this._win.webkitNotifications &&\n            this._win.webkitNotifications.checkPermission\n        )\n            /* Legacy webkit browsers */\n            permission = this._permissions[\n                this._win.webkitNotifications.checkPermission()\n            ];\n        else if (navigator.mozNotification)\n            /* Firefox Mobile */\n            permission = this.GRANTED;\n        else if (this._win.external && this._win.external.msIsSiteMode)\n            /* IE9+ */\n            permission = this._win.external.msIsSiteMode()\n                ? this.GRANTED\n                : this.DEFAULT;\n        else permission = this.GRANTED;\n\n        return permission;\n    }\n}\n"
  },
  {
    "path": "src/push/Push.js",
    "content": "// @flow\nimport { Messages, Permission, Util } from 'push';\nimport type { PluginManifest, GenericNotification, PushOptions } from 'types';\n\n/* Import notification agents */\nimport {\n    DesktopAgent,\n    MobileChromeAgent,\n    MobileFirefoxAgent,\n    MSAgent,\n    WebKitAgent\n} from 'agents';\n\nexport default class Push {\n    // Private members\n    _agents: {\n        desktop: DesktopAgent,\n        chrome: MobileChromeAgent,\n        firefox: MobileFirefoxAgent,\n        ms: MSAgent,\n        webkit: WebKitAgent\n    };\n    _configuration: {\n        serviceWorker: string,\n        fallback: ({}) => void\n    };\n    _currentId: number;\n    _notifications: {};\n    _win: {};\n\n    // Public members\n    Permission: Permission;\n\n    constructor(win: {}) {\n        /* Private variables */\n\n        /* ID to use for new notifications */\n        this._currentId = 0;\n\n        /* Map of open notifications */\n        this._notifications = {};\n\n        /* Window object */\n        this._win = win;\n\n        /* Public variables */\n        this.Permission = new Permission(win);\n\n        /* Agents */\n        this._agents = {\n            desktop: new DesktopAgent(win),\n            chrome: new MobileChromeAgent(win),\n            firefox: new MobileFirefoxAgent(win),\n            ms: new MSAgent(win),\n            webkit: new WebKitAgent(win)\n        };\n\n        this._configuration = {\n            serviceWorker: '/serviceWorker.min.js',\n            fallback: function(payload) {}\n        };\n    }\n\n    /**\n     * Closes a notification\n     * @param id            ID of notification\n     * @returns {boolean}   denotes whether the operation was successful\n     * @private\n     */\n    _closeNotification(id: number | string) {\n        let success = true;\n        const notification = this._notifications[id];\n\n        if (notification !== undefined) {\n            success = this._removeNotification(id);\n\n            /* Safari 6+, Firefox 22+, Chrome 22+, Opera 25+ */\n            if (this._agents.desktop.isSupported())\n                this._agents.desktop.close(notification);\n            else if (this._agents.webkit.isSupported())\n                /* Legacy WebKit browsers */\n                this._agents.webkit.close(notification);\n            else if (this._agents.ms.isSupported())\n                /* IE9 */\n                this._agents.ms.close();\n            else {\n                success = false;\n                throw new Error(Messages.errors.unknown_interface);\n            }\n\n            return success;\n        }\n\n        return false;\n    }\n\n    /**\n   * Adds a notification to the global dictionary of notifications\n   * @param {Notification} notification\n   * @return {Integer} Dictionary key of the notification\n   * @private\n   */\n    _addNotification(notification: GenericNotification) {\n        const id = this._currentId;\n        this._notifications[id] = notification;\n        this._currentId++;\n        return id;\n    }\n\n    /**\n   * Removes a notification with the given ID\n   * @param  {Integer} id - Dictionary key/ID of the notification to remove\n   * @return {Boolean} boolean denoting success\n   * @private\n   */\n    _removeNotification(id: number | string) {\n        let success = false;\n\n        if (this._notifications.hasOwnProperty(id)) {\n            /* We're successful if we omit the given ID from the new array */\n            delete this._notifications[id];\n            success = true;\n        }\n\n        return success;\n    }\n\n    /**\n   * Creates the wrapper for a given notification\n   *\n   * @param {Integer} id - Dictionary key/ID of the notification\n   * @param {Map} options - Options used to create the notification\n   * @returns {Map} wrapper hashmap object\n   * @private\n   */\n    _prepareNotification(id: number, options: PushOptions) {\n        let wrapper;\n\n        /* Wrapper used to get/close notification later on */\n        wrapper = {\n            get: () => {\n                return this._notifications[id];\n            },\n\n            close: () => {\n                this._closeNotification(id);\n            }\n        };\n\n        /* Autoclose timeout */\n        if (options.timeout) {\n            setTimeout(() => {\n                wrapper.close();\n            }, options.timeout);\n        }\n\n        return wrapper;\n    }\n\n    /**\n   * Find the most recent notification from a ServiceWorker and add it to the global array\n   * @param notifications\n   * @private\n   */\n    _serviceWorkerCallback(\n        notifications: GenericNotification[],\n        options: PushOptions,\n        resolve: ({} | null) => void\n    ) {\n        let id = this._addNotification(notifications[notifications.length - 1]);\n\n        /* Listen for close requests from the ServiceWorker */\n        if (navigator && navigator.serviceWorker) {\n            navigator.serviceWorker.addEventListener('message', event => {\n                const data = JSON.parse(event.data);\n\n                if (data.action === 'close' && Number.isInteger(data.id))\n                    this._removeNotification(data.id);\n            });\n\n            resolve(this._prepareNotification(id, options));\n        }\n\n        resolve(null);\n    }\n\n    /**\n   * Callback function for the 'create' method\n   * @return {void}\n   * @private\n   */\n    _createCallback(\n        title: string,\n        options: PushOptions,\n        resolve: ({} | null) => void\n    ) {\n        let notification = null;\n        let onClose;\n\n        /* Set empty settings if none are specified */\n        options = options || {};\n\n        /* onClose event handler */\n        onClose = id => {\n            /* A bit redundant, but covers the cases when close() isn't explicitly called */\n            this._removeNotification(id);\n            if (Util.isFunction(options.onClose)) {\n                options.onClose.call(this, notification);\n            }\n        };\n\n        /* Safari 6+, Firefox 22+, Chrome 22+, Opera 25+ */\n        if (this._agents.desktop.isSupported()) {\n            try {\n                /* Create a notification using the API if possible */\n                notification = this._agents.desktop.create(title, options);\n            } catch (e) {\n                const id = this._currentId;\n                const sw = this.config().serviceWorker;\n                const cb = notifications =>\n                    this._serviceWorkerCallback(\n                        notifications,\n                        options,\n                        resolve\n                    );\n                /* Create a Chrome ServiceWorker notification if it isn't supported */\n                if (this._agents.chrome.isSupported()) {\n                    this._agents.chrome.create(id, title, options, sw, cb);\n                }\n            }\n            /* Legacy WebKit browsers */\n        } else if (this._agents.webkit.isSupported())\n            notification = this._agents.webkit.create(title, options);\n        else if (this._agents.firefox.isSupported())\n            /* Firefox Mobile */\n            this._agents.firefox.create(title, options);\n        else if (this._agents.ms.isSupported())\n            /* IE9 */\n            notification = this._agents.ms.create(title, options);\n        else {\n            /* Default fallback */\n            options.title = title;\n            this.config().fallback(options);\n        }\n\n        if (notification !== null) {\n            const id = this._addNotification(notification);\n            const wrapper = this._prepareNotification(id, options);\n\n            /* Notification callbacks */\n            if (Util.isFunction(notification.addEventListener)) {\n              if (Util.isFunction(options.onShow))\n                  notification.addEventListener('show', options.onShow);\n\n              if (Util.isFunction(options.onError))\n                  notification.addEventListener('error', options.onError);\n\n              if (Util.isFunction(options.onClick))\n                  notification.addEventListener('click', options.onClick);\n\n              notification.addEventListener('close', () => {\n                  onClose(id);\n              });\n\n              notification.addEventListener('cancel', () => {\n                  onClose(id);\n              });\n            }\n\n            /* Return the wrapper so the user can call close() */\n            resolve(wrapper);\n        }\n\n        /* By default, pass an empty wrapper */\n        resolve(null);\n    }\n\n    /**\n   * Creates and displays a new notification\n   * @param {Array} options\n   * @return {Promise}\n   */\n    create(title: string, options: {}): Promise<void> {\n        let promiseCallback;\n\n        /* Fail if no or an invalid title is provided */\n        if (!Util.isString(title)) {\n            throw new Error(Messages.errors.invalid_title);\n        }\n\n        /* Request permission if it isn't granted */\n        if (!this.Permission.has()) {\n            promiseCallback = (resolve: () => void, reject: string => void) => {\n                this.Permission\n                    .request()\n                    .then(() => {\n                        this._createCallback(title, options, resolve);\n                    })\n                    .catch(() => {\n                        reject(Messages.errors.permission_denied);\n                    });\n            };\n        } else {\n            promiseCallback = (resolve: () => void, reject: string => void) => {\n                try {\n                    this._createCallback(title, options, resolve);\n                } catch (e) {\n                    reject(e);\n                }\n            };\n        }\n\n        return new Promise(promiseCallback);\n    }\n\n    /**\n   * Returns the notification count\n   * @return {Integer} The notification count\n   */\n    count() {\n        let count = 0;\n        let key;\n\n        for (key in this._notifications)\n            if (this._notifications.hasOwnProperty(key)) count++;\n\n        return count;\n    }\n\n    /**\n   * Closes a notification with the given tag\n   * @param {String} tag - Tag of the notification to close\n   * @return {Boolean} boolean denoting success\n   */\n    close(tag: string) {\n        let key, notification;\n\n        for (key in this._notifications) {\n            if (this._notifications.hasOwnProperty(key)) {\n                notification = this._notifications[key];\n\n                /* Run only if the tags match */\n                if (notification.tag === tag) {\n                    /* Call the notification's close() method */\n                    return this._closeNotification(key);\n                }\n            }\n        }\n    }\n\n    /**\n   * Clears all notifications\n   * @return {Boolean} boolean denoting whether the clear was successful in closing all notifications\n   */\n    clear() {\n        let key,\n            success = true;\n\n        for (key in this._notifications)\n            if (this._notifications.hasOwnProperty(key))\n                success = success && this._closeNotification(key);\n\n        return success;\n    }\n\n    /**\n   * Denotes whether Push is supported in the current browser\n   * @returns {boolean}\n   */\n    supported() {\n        let supported = false;\n\n        for (var agent in this._agents)\n            if (this._agents.hasOwnProperty(agent))\n                supported = supported || this._agents[agent].isSupported();\n\n        return supported;\n    }\n\n    /**\n   * Modifies settings or returns all settings if no parameter passed\n   * @param settings\n   */\n    config(settings?: {}) {\n        if (\n            typeof settings !== 'undefined' ||\n            (settings !== null && Util.isObject(settings))\n        )\n            Util.objectMerge(this._configuration, settings);\n\n        return this._configuration;\n    }\n\n    /**\n   * Copies the functions from a plugin to the main library\n   * @param plugin\n   */\n    extend(manifest: PluginManifest) {\n        var plugin,\n            Plugin,\n            hasProp = {}.hasOwnProperty;\n\n        if (!hasProp.call(manifest, 'plugin')) {\n            throw new Error(Messages.errors.invalid_plugin);\n        } else {\n            if (\n                hasProp.call(manifest, 'config') &&\n                Util.isObject(manifest.config) &&\n                manifest.config !== null\n            ) {\n                this.config(manifest.config);\n            }\n\n            Plugin = manifest.plugin;\n            plugin = new Plugin(this.config());\n\n            for (var member in plugin) {\n                if (\n                    hasProp.call(plugin, member) &&\n                    Util.isFunction(plugin[member])\n                )\n                    // $FlowFixMe\n                    this[member] = plugin[member];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/push/Util.js",
    "content": "// @flow\nexport default class Util {\n    static isUndefined(obj) {\n        return obj === undefined;\n    }\n\n    static isNull(obs) {\n        return obj === null;\n    }\n\n    static isString(obj) {\n        return typeof obj === 'string';\n    }\n\n    static isFunction(obj) {\n        return obj && {}.toString.call(obj) === '[object Function]';\n    }\n\n    static isObject(obj) {\n        return typeof obj === 'object';\n    }\n\n    static objectMerge(target, source) {\n        for (var key in source) {\n            if (\n                target.hasOwnProperty(key) &&\n                this.isObject(target[key]) &&\n                this.isObject(source[key])\n            ) {\n                this.objectMerge(target[key], source[key]);\n            } else {\n                target[key] = source[key];\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/push/index.js",
    "content": "import Messages from './Messages';\nimport Permission from './Permission';\nimport Util from './Util';\nimport Push from './Push';\n\nexport { Messages, Permission, Util, Push };\n"
  },
  {
    "path": "src/serviceWorker.js",
    "content": "'use strict';\n\nfunction isFunction(obj) {\n    return obj && {}.toString.call(obj) === '[object Function]';\n}\n\nfunction runFunctionString(funcStr) {\n    if (funcStr.trim().length > 0) {\n        var func = new Function(funcStr);\n        if (isFunction(func)) {\n            func();\n        }\n    }\n}\n\nself.addEventListener('message', function(event) {\n    self.client = event.source;\n});\n\nself.onnotificationclose = function(event) {\n    runFunctionString(event.notification.data.onClose);\n\n    /* Tell Push to execute close callback */\n    self.client.postMessage(\n        JSON.stringify({\n            id: event.notification.data.id,\n            action: 'close'\n        })\n    );\n};\n\nself.onnotificationclick = function(event) {\n    var link, origin, href;\n\n    if (\n        typeof event.notification.data.link !== 'undefined' &&\n        event.notification.data.link !== null\n    ) {\n        origin = event.notification.data.origin;\n        link = event.notification.data.link;\n        href = origin.substring(0, origin.indexOf('/', 8)) + '/';\n\n        /* Removes prepending slash, as we don't need it */\n        if (link[0] === '/') {\n            link = link.length > 1 ? link.substring(1, link.length) : '';\n        }\n\n        event.notification.close();\n\n        /* This looks to see if the current is already open and focuses if it is */\n        event.waitUntil(\n            clients\n                .matchAll({\n                    type: 'window'\n                })\n                .then(function(clientList) {\n                    var client, full_url;\n\n                    for (var i = 0; i < clientList.length; i++) {\n                        client = clientList[i];\n                        full_url = href + link;\n\n                        /* Covers case where full_url might be http://example.com/john and the client URL is http://example.com/john/ */\n                        if (\n                            full_url[full_url.length - 1] !== '/' &&\n                            client.url[client.url.length - 1] === '/'\n                        ) {\n                            full_url += '/';\n                        }\n\n                        if (client.url === full_url && 'focus' in client) {\n                            return client.focus();\n                        }\n                    }\n\n                    if (clients.openWindow) {\n                        return clients.openWindow('/' + link);\n                    }\n                })\n                .catch(function(error) {\n                    throw new Error(\n                        'A ServiceWorker error occurred: ' + error.message\n                    );\n                })\n        );\n    }\n\n    runFunctionString(event.notification.data.onClick);\n};\n"
  },
  {
    "path": "src/types.js",
    "content": "export type GenericNotification = Notification | webkitNotifications;\n\nexport type Global = {\n    Notification?: Notification,\n    webkitNotifications?: webkitNotifications\n};\n\nexport type PushOptions = {\n    body?: string,\n    icon?: string,\n    link?: string,\n    timeout?: number,\n    tag?: string,\n    requireInteraction?: boolean,\n    vibrate?: boolean,\n    silent?: boolean,\n    onClick?: Function,\n    onError?: Function\n};\n\nexport type PluginManifest = {\n    plugin: {},\n    config?: {}\n};\n"
  },
  {
    "path": "tests/browsers.conf.js",
    "content": "var BROWSER_FIREFOX = 'Firefox',\n    BROWSER_CHROME = 'Chrome',\n    BROWSER_EDGE = 'Edge',\n    BROWSER_IE = 'ie',\n    BROWSER_OPERA = 'Opera',\n    BROWSER_SAFARI = 'Safari';\n\nfunction getWindowsDesktop(browser, version) {\n    return {\n        base: 'BrowserStack',\n        browser: browser,\n        browser_version: version.toString() + '.0',\n        os: 'Windows',\n        os_version: '10'\n    };\n}\n\nfunction getOSXDesktop(browser, version, os) {\n    var rounded;\n\n    if (!os) os = version < 25 ? 'Snow Leopard' : 'Sierra';\n\n    rounded = Math.floor(version);\n\n    if (version == rounded) version = version.toString() + '.0';\n\n    return {\n        base: 'BrowserStack',\n        browser: browser,\n        browser_version: version,\n        os: 'OS X',\n        os_version: os\n    };\n}\n\nfunction getMobile(browser) {\n    return {\n        base: 'BrowserStack',\n        real_mobile: true,\n        device: 'Google Pixel',\n        browser: 'Mobile ' + browser,\n        os: 'android',\n        os_version: '7.1'\n    };\n}\n\nmodule.exports = {\n    bs_firefox_mac: getOSXDesktop(BROWSER_FIREFOX, 54),\n    bs_firefox_mac_old: getOSXDesktop(BROWSER_FIREFOX, 21),\n    bs_chrome_mac: getOSXDesktop(BROWSER_CHROME, 59),\n    bs_edge_win: getWindowsDesktop(BROWSER_EDGE, 15),\n    bs_safari_mac: getOSXDesktop(BROWSER_SAFARI, 10.1, 'Sierra'),\n    bs_opera_mac: getOSXDesktop(BROWSER_OPERA, 46)\n    // bs_chrome_mac_old: getOSXDesktop(BROWSER_CHROME, 16), <-- issues testing Push on old Chrome versions in BrowserStack\n    // bs_firefox_mobile: getMobile(BROWSER_CHROME) <-- can't work because of HTTPS requirement (wth dude)\n};\n"
  },
  {
    "path": "tests/karma.conf.js",
    "content": "// Karma configuration\n// Generated on Tue Jul 21 2015 22:34:30 GMT-0400 (EDT)\nlet browsers, selected_browsers;\n\nbrowsers = require('./browsers.conf');\nselected_browsers = Object.keys(browsers);\n\nconst browser = process.env.PUSHJS_TEST_BROWSER;\n\nmodule.exports = function(config) {\n    config.set({\n        // base path that will be used to resolve all patterns (eg. files, exclude)\n        basePath: '../',\n\n        ...(!browser && {\n            browserStack: {\n                username: 'Nickersoft',\n                accessKey: 'peTScQRRBpSkOGjybGpd'\n            }\n        }),\n\n        coverageReporter: {\n            // specify a common output directory\n            dir: 'coverage',\n            reporters: [\n                {\n                    type: 'lcov',\n                    subdir: '.'\n                }\n            ]\n        },\n\n        // frameworks to use\n        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter\n        frameworks: ['jasmine'],\n\n        plugins: [\n            'karma-jasmine',\n            'karma-mocha-reporter',\n            'karma-coverage',\n            'karma-sourcemap-loader',\n            ...(browser\n                ? [`karma-${browser.toLowerCase()}-launcher`]\n                : ['karma-browserstack-launcher'])\n        ],\n\n        // list of files / patterns to load in the browser\n        files: [\n            './node_modules/platform/platform.js',\n            './node_modules/@babel/polyfill/dist/polyfill.min.js',\n            './bin/push.min.js',\n            './tests/push.tests.js',\n            './src/serviceWorker.min.js'\n        ],\n\n        // preprocess matching files before serving them to the browser\n        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor\n        preprocessors: {\n            './bin/push.js': ['sourcemap', 'coverage']\n        },\n\n        // src results reporter to use\n        // possible values: 'dots', 'progress'\n        // available reporters: https://npmjs.org/browse/keyword/karma-reporter\n        reporters: ['mocha', 'coverage', ...(!browser ? ['BrowserStack'] : [])],\n\n        // web server port\n        port: 9876,\n\n        // enable / disable colors in the output (reporters and logs)\n        colors: true,\n\n        // level of logging\n        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG\n        logLevel: config.LOG_INFO,\n\n        // enable / disable watching file and executing src whenever any file changes\n        autoWatch: false,\n\n        // start these browsers\n        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher\n        browsers: browser ? [browser] : selected_browsers,\n\n        // Continuous Integration mode\n        // if true, Karma captures browsers, runs the src and exits\n        singleRun: true,\n\n        // custom browser launchers for BrowserStack\n        ...(!browser && { customLaunchers: browsers })\n    });\n};\n"
  },
  {
    "path": "tests/push.tests.js",
    "content": "var BROWSER_CHROME = 'Chrome',\n    BROWSER_FIREFOX = 'Firefox',\n    BROWSER_EDGE = 'Edge',\n    BROWSER_OPERA = 'Opera',\n    TEST_TITLE = 'title',\n    TEST_BODY = 'body',\n    TEST_TIMEOUT = 1000,\n    TEST_TAG = 'foo',\n    TEST_TAG_2 = 'bar',\n    TEST_ICON = 'icon',\n    TEST_SW_DEFAULT = '/serviceWorker.min.js',\n    NOOP = function() {\n        return null;\n    };\n\ndescribe('proper support detection', function() {\n    function isBrowser(browser) {\n        return platform.name.toLowerCase() === browser.toLowerCase();\n    }\n\n    function getVersion() {\n        return parseFloat(platform.version);\n    }\n\n    function isSupported() {\n        return Push.supported();\n    }\n\n    it('should detect Firefox support correctly', function() {\n        if (isBrowser(BROWSER_FIREFOX)) {\n            if (getVersion() > 21) expect(isSupported()).toBeTruthy();\n            else expect(isSupported()).toBeFalsy();\n        } else {\n            pending();\n        }\n    });\n\n    it('should detect Chrome support correctly', function() {\n        if (isBrowser(BROWSER_CHROME)) {\n            if (getVersion() > 4) expect(isSupported()).toBeTruthy();\n            else expect(isSupported()).toBeFalsy();\n        } else {\n            pending();\n        }\n    });\n\n    it('should detect Opera support correctly', function() {\n        if (isBrowser(BROWSER_OPERA)) {\n            if (getVersion() > 23) expect(isSupported()).toBeTruthy();\n            else expect(isSupported()).toBeFalsy();\n        } else {\n            pending();\n        }\n    });\n\n    it('should detect Edge support correctly', function() {\n        if (isBrowser(BROWSER_EDGE)) {\n            if (getVersion() > 14) expect(isSupported()).toBeTruthy();\n            else expect(isSupported()).toBeFalsy();\n        } else {\n            pending();\n        }\n    });\n});\n\ndescribe('adding plugins', function() {\n    it('reject invalid plugin manifests', function() {\n        var testPlugin = function() {\n            this.testFunc = function() {};\n        };\n\n        expect(Push.extend.bind(Push, testPlugin)).toThrow();\n    });\n\n    it('accept valid plugin manifests', function() {\n        var testPlugin = {\n            plugin: function() {\n                this.testFunc = function() {};\n            }\n        };\n\n        Push.extend(testPlugin);\n\n        expect(Push.testFunc).toBeDefined();\n    });\n\n    it('only allow object-based configs', function() {\n        spyOn(window.Push, 'config');\n\n        var testPlugin = {\n            config: null,\n            plugin: function() {\n                this.testFunc = function() {};\n            }\n        };\n\n        Push.extend(testPlugin);\n\n        expect(Push.config.calls.count()).toEqual(1); // config() is called one by default in extend()\n\n        var testPlugin2 = {\n            config: {},\n            plugin: function() {\n                this.testFunc = function() {};\n            }\n        };\n\n        Push.extend(testPlugin2);\n\n        expect(Push.config.calls.count()).toBeGreaterThan(1);\n    });\n});\n\ndescribe('changing configuration', function() {\n    it('returns the current configuration if no parameters passed', function() {\n        var output = {\n            serviceWorker: TEST_SW_DEFAULT,\n            fallback: function(payload) {}\n        };\n\n        var configKeys = Object.keys(Push.config());\n\n        Object.keys(output).forEach(function(k) {\n            expect(configKeys.includes(k)).toBeTruthy();\n        });\n    });\n\n    it('adds a configuration if one is specified', function() {\n        Push.config({\n            a: 1\n        });\n\n        expect(Push.config().a).toBeDefined();\n        expect(Push.config().a).toBe(1);\n    });\n\n    it('should be capable of performing a deep merge', function() {\n        var input1 = {\n            b: {\n                c: 1,\n                d: {\n                    e: 2,\n                    f: 3\n                }\n            }\n        };\n        var input2 = {\n            b: {\n                d: {\n                    e: 2,\n                    f: 4\n                },\n                g: 5\n            }\n        };\n        var output = {\n            c: 1,\n            d: {\n                e: 2,\n                f: 4\n            },\n            g: 5\n        };\n\n        Push.config(input1);\n        Push.config(input2);\n\n        expect(Push.config().b).toBeDefined();\n        expect(JSON.stringify(Push.config().b)).toBe(JSON.stringify(output));\n    });\n});\n\nif (Push.supported()) {\n    Push.config({\n        serviceWorker: TEST_SW_DEFAULT\n    });\n\n    function initRequestSpy(granted) {\n        var param_str, param_int;\n\n        param_str = granted ? Push.Permission.GRANTED : Push.Permission.DEFAULT;\n        param_int = granted ? 0 : 1;\n\n        /* Safari 6+, Legacy webkit browsers */\n        if (\n            window.webkitNotifications &&\n            window.webkitNotifications.checkPermission\n        ) {\n            spyOn(window.webkitNotifications, 'requestPermission').and.callFake(\n                function(cb) {\n                    cb(param_int);\n                }\n            );\n        } else if (\n            /* Chrome 23+ */\n            window.Notification &&\n            window.Notification.requestPermission\n        ) {\n            spyOn(window.Notification, 'requestPermission').and.callFake(\n                function() {\n                    return new Promise(function(resolve) {\n                        resolve(param_str);\n                    });\n                }\n            );\n        }\n    }\n\n    function getRequestObject() {\n        var obj = {};\n\n        /* Safari 6+, Legacy webkit browsers */\n        if (\n            window.webkitNotifications &&\n            window.webkitNotifications.checkPermission\n        )\n            return window.webkitNotifications.requestPermission;\n        /* Chrome 23+ */ else if (\n            window.Notification &&\n            window.Notification.requestPermission\n        )\n            return window.Notification.requestPermission;\n        return null;\n    }\n\n    describe('initialization', function() {\n        it('should create a new instance', function() {\n            expect(window.Push !== undefined).toBeTruthy();\n        });\n\n        it('isSupported should return a boolean', function() {\n            expect(typeof Push.supported()).toBe('boolean');\n        });\n    });\n\n    describe('permission', function() {\n        var callback; // Callback spy\n\n        beforeAll(function() {\n            jasmine.clock().uninstall();\n            jasmine.clock().install();\n        });\n\n        beforeEach(function() {\n            callback = jasmine.createSpy('callback');\n        });\n\n        it('should have permission stored as a string varant', function() {\n            expect(typeof Push.Permission.get()).toBe('string');\n        });\n\n        it('should update permission value if permission is denied and execute callback (deprecated)', function(done) {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n\n            initRequestSpy(false);\n\n            Push.Permission.request(NOOP, function() {\n                callback();\n                expect(Push.Permission.has()).toBe(false);\n                expect(callback).toHaveBeenCalled();\n                done();\n            });\n        });\n\n        it('should update permission value if permission is denied and execute callback (with promise)', function(done) {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n\n            initRequestSpy(false);\n\n            Push.Permission.request()\n                .then(NOOP)\n                .catch(function() {\n                    callback();\n                    expect(callback).toHaveBeenCalled();\n                    expect(Push.Permission.has()).toBe(false);\n                    done();\n                });\n        });\n\n        it('should request permission if permission is not granted', function() {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n            initRequestSpy(false);\n\n            Push.create(TEST_TITLE).then(function() {\n                expect(getRequestObject()).toHaveBeenCalled();\n            });\n        });\n\n        it('should update permission value if permission is granted and execute callback (deprecated)', function() {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.GRANTED\n            );\n            initRequestSpy(true);\n\n            Push.Permission.request(callback, NOOP);\n\n            jasmine.clock().tick(TEST_TIMEOUT);\n\n            expect(Push.Permission.has()).toBe(true);\n            expect(callback).toHaveBeenCalled();\n        });\n\n        it('should update permission value if permission is granted and execute callback (with promise)', function() {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.GRANTED\n            );\n\n            initRequestSpy(true);\n\n            Push.Permission.request();\n\n            jasmine.clock().tick(TEST_TIMEOUT);\n\n            expect(Push.Permission.has()).toBe(true);\n        });\n\n        it('should not request permission if permission is already granted', function() {\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.GRANTED\n            );\n            initRequestSpy(true);\n\n            Push.Permission.request();\n            Push.create(TEST_TITLE)\n                .then(function() {\n                    expect(getRequestObject()).not.toHaveBeenCalled();\n                })\n                .catch(function() {});\n        });\n    });\n\n    describe('creating notifications', function() {\n        beforeAll(function() {\n            jasmine.clock().uninstall();\n            jasmine.clock().install();\n\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n            initRequestSpy(true);\n        });\n\n        beforeEach(function() {\n            Push.clear();\n        });\n\n        it('should throw exception if no title is provided', function() {\n            expect(function() {\n                Push.create();\n            }).toThrow();\n        });\n\n        it('should return a valid notification wrapper', function(done) {\n            Push.create(TEST_TITLE).then(function(wrapper) {\n                expect(wrapper).not.toBe(undefined);\n                expect(wrapper.get).not.toBe(undefined);\n                expect(wrapper.close).not.toBe(undefined);\n                done();\n            });\n        });\n\n        it('should return promise successfully', function() {\n            var promise = Push.create(TEST_TITLE)\n                .then(function() {\n                    expect(promise.then).not.toBe(undefined);\n                })\n                .catch(function() {});\n        });\n\n        it('should pass in all API options correctly', function(done) {\n            // Vibrate omitted because Firefox will default to using the Notification API, not service workers\n            // Timeout, requestPermission, and event listeners also omitted from this src :(\n            Push.create(TEST_TITLE, {\n                body: TEST_BODY,\n                icon: TEST_ICON,\n                tag: TEST_TAG,\n                silent: true\n            }).then(function(wrapper) {\n                var notification = wrapper.get();\n\n                // Some browsers, like Safari, choose to omit this info\n                if (notification.title)\n                    expect(notification.title).toBe(TEST_TITLE);\n                if (notification.body)\n                    expect(notification.body).toBe(TEST_BODY);\n                if (notification.icon)\n                    expect(notification.icon).toContain(TEST_ICON); // Some browsers append the document location, so we gotta use toContain()\n\n                expect(notification.tag).toBe(TEST_TAG);\n\n                if (notification.hasOwnProperty('silent')) {\n                    expect(notification.silent).toBe(true);\n                }\n\n                done();\n            });\n        });\n\n        it('should return the increase the notification count', function(done) {\n            expect(Push.count()).toBe(0);\n\n            Push.create(TEST_TITLE).then(function() {\n                expect(Push.count()).toBe(1);\n                done();\n            });\n        });\n    });\n\n    describe('event listeners', function() {\n        var callback, // callback spy\n            testListener = function(name, cb) {\n                var event = new Event(name),\n                    options = {},\n                    key,\n                    promise;\n\n                key =\n                    'on' +\n                    name[0].toUpperCase() +\n                    name.substr(1, name.length - 1);\n\n                options[key] = callback;\n\n                Push.create(TEST_TITLE, options)\n                    .then(function(wrapper) {\n                        var notification = wrapper.get();\n                        notification.dispatchEvent(event);\n                        expect(callback).toHaveBeenCalled();\n                        cb();\n                    })\n                    .catch(function() {});\n            };\n\n        beforeAll(function() {\n            initRequestSpy(true);\n        });\n\n        beforeEach(function() {\n            callback = jasmine.createSpy('callback');\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n        });\n\n        it('should execute onClick listener correctly', function(done) {\n            testListener('click', done);\n        });\n\n        it('should execute onShow listener correctly', function(done) {\n            testListener('show', done);\n        });\n\n        it('should execute onError listener correctly', function(done) {\n            testListener('error', done);\n        });\n\n        it('should execute onClose listener correctly', function(done) {\n            testListener('close', done);\n        });\n    });\n\n    describe('closing notifications', function() {\n        var callback; // Callback spy\n        var closeSpy;\n\n        beforeAll(function() {\n            initRequestSpy(true);\n            jasmine.clock().uninstall();\n            jasmine.clock().install();\n        });\n\n        beforeEach(function() {\n            closeSpy = spyOn(window.Notification.prototype, 'close');\n\n            spyOn(Push.Permission, 'get').and.returnValue(\n                Push.Permission.DEFAULT\n            );\n\n            closeSpy.calls.reset();\n\n            Push.clear();\n\n            callback = jasmine.createSpy('callback');\n        });\n\n        it('should close notifications on close callback', function(done) {\n            Push.create(TEST_TITLE, {\n                onClose: callback\n            }).then(function(wrapper) {\n                var notification = wrapper.get();\n\n                expect(Push.count()).toBe(1);\n\n                notification.dispatchEvent(new Event('close'));\n\n                expect(Push.count()).toBe(0);\n\n                done();\n            });\n        });\n\n        it('should close notifications using wrapper', function(done) {\n            Push.create(TEST_TITLE, {\n                onClose: callback\n            }).then(function(wrapper) {\n                expect(Push.count()).toBe(1);\n\n                wrapper.close();\n\n                expect(closeSpy).toHaveBeenCalled();\n                expect(Push.count()).toBe(0);\n\n                done();\n            });\n        });\n\n        it('should close notifications using given timeout', function(done) {\n            Push.create(TEST_TITLE, {\n                timeout: TEST_TIMEOUT\n            }).then(function() {\n                jasmine.clock().tick(500);\n                expect(Push.count()).toBe(1);\n                expect(closeSpy).not.toHaveBeenCalled();\n                jasmine.clock().tick(TEST_TIMEOUT);\n                expect(closeSpy).toHaveBeenCalled();\n                expect(Push.count()).toBe(0);\n                done();\n            });\n        });\n\n        it('should close a notification given a tag', function(done) {\n            Push.create(TEST_TITLE, {\n                tag: TEST_TAG\n            }).then(function() {\n                expect(Push.count()).toBe(1);\n                expect(Push.close(TEST_TAG)).toBeTruthy();\n                expect(closeSpy).toHaveBeenCalled();\n                expect(Push.count()).toBe(0);\n                done();\n            });\n        });\n\n        it('should close all notifications when cleared', function(done) {\n            Promise.all([\n                Push.create(TEST_TITLE, {\n                    tag: TEST_TAG\n                }),\n                Push.create('hello world!', {\n                    tag: TEST_TAG_2\n                })\n            ]).then(function() {\n                expect(Push.count()).toBeGreaterThan(0);\n                expect(Push.clear()).toBeTruthy();\n                expect(closeSpy).toHaveBeenCalled();\n                expect(Push.count()).toBe(0);\n                done();\n            });\n        });\n    });\n} else {\n    describe('fallback functionality', function() {\n        it('should ensure fallback method fires correctly', function(done) {\n            var fallback = jasmine.createSpy('fallback');\n\n            Push.config({\n                fallback: fallback\n            });\n\n            Push.create(TEST_TITLE).then(function() {\n                expect(fallback).toHaveBeenCalled();\n                done();\n            });\n        });\n\n        it('should ensure all notification options are passed to the fallback', function(done) {\n            Push.config({\n                fallback: function(payload) {\n                    expect(payload.title).toBe(TEST_TITLE);\n                    expect(payload.body).toBe(TEST_BODY);\n                    expect(payload.icon).toBe(TEST_ICON);\n                    expect(payload.tag).toBe(TEST_TAG);\n                    done();\n                }\n            });\n\n            Push.create(TEST_TITLE, {\n                body: TEST_BODY,\n                icon: TEST_ICON,\n                tag: TEST_TAG\n            }).catch(function() {});\n        });\n    });\n}\n"
  }
]