diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml index cb527282..d4548db0 100644 --- a/.github/workflows/generate.yml +++ b/.github/workflows/generate.yml @@ -14,7 +14,7 @@ jobs: with: GH_PAGES_BRANCH: gh-pages TOOLCHAIN: bikeshed - SOURCE: docs/index.bs - DESTINATION: docs/index.html + SOURCE: index.bs + DESTINATION: index.html VALIDATE_MARKUP: true BUILD_FAIL_ON: fatal diff --git a/.pr-preview.json b/.pr-preview.json index 8150e400..62a1f311 100644 --- a/.pr-preview.json +++ b/.pr-preview.json @@ -1,5 +1,5 @@ { - "src_file": "docs/index.bs", + "src_file": "index.bs", "type": "bikeshed", "params": { "force": 1 diff --git a/README.md b/README.md index 6b57ba17..10e6d62c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Spec development happens via [issues in this repository](https://github.com/w3c/ Updates to the spec must reference [resolved issues marked `needs spec`](https://github.com/w3c/ServiceWorker/issues?q=is%3Aclosed+label%3A%22needs+spec%22). -To make edits to the design, please send pull requests against the Nightly spec on the master branch. We use [bikeshed](https://github.com/tabatkins/bikeshed). So, change `docs/index.bs` and submit it with the corresponding bikesheded `index.html`. +To make edits to the design, please send pull requests against the Nightly spec on the master branch. We use [bikeshed](https://github.com/tabatkins/bikeshed). So, change `index.bs` and submit it with the corresponding bikesheded `index.html`. ## Examples diff --git a/docs/spec/service_worker/index.html b/docs/spec/service_worker/index.html deleted file mode 100644 index 9a3317e1..00000000 --- a/docs/spec/service_worker/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -Moved… - - -

Moved to -https://w3c.github.io/ServiceWorker/

- \ No newline at end of file diff --git a/docs/spec/service_worker_1/index.html b/docs/spec/service_worker_1/index.html deleted file mode 100644 index 31b261fa..00000000 --- a/docs/spec/service_worker_1/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -Moved… - - -

Moved to -https://w3c.github.io/ServiceWorker/v1/

- \ No newline at end of file diff --git a/docs/v1/index.bs b/docs/v1/index.bs deleted file mode 100644 index 703b2de6..00000000 --- a/docs/v1/index.bs +++ /dev/null @@ -1,3403 +0,0 @@ -
-Title: Service Workers 1
-Status: ED
-ED: https://w3c.github.io/ServiceWorker/v1/
-TR: https://www.w3.org/TR/service-workers/
-Shortname: service-workers
-Level: 1
-Editor: Alex Russell, Google, slightlyoff@chromium.org
-Editor: Jungkee Song, Microsoft‚ represented Samsung until April 2018, jungkee.song@microsoft.com
-Editor: Jake Archibald, Google, jakearchibald@chromium.org
-Editor: Marijn Kruisselbrink, Google, mek@chromium.org
-Repository: w3c/ServiceWorker
-Group: serviceworkers
-!Tests: web-platform-tests service-workers/ (ongoing work)
-Warning: Custom
-Custom Warning Title: V1 Branch
-Custom Warning Text: This spec is a subset of [the nightly version](https://w3c.github.io/ServiceWorker/). It is advancing toward a W3C Recommendation. For implementers and developers who seek all the latest features, [Service Workers Nightly](https://w3c.github.io/ServiceWorker/) is the right document as is constantly reflects new requirements.
-Abstract: This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.
-Abstract:
-Abstract: The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.
-Abstract:
-Abstract: The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.
-Markup Shorthands: css no, markdown yes
-
- - - -
-spec: push; urlPrefix: https://w3c.github.io/push-api/
-    type: event
-        text: push; url: h-the-push-event
-
-spec: ecma-262; urlPrefix: http://tc39.github.io/ecma262/
-    type: dfn
-        text: Assert; url: sec-algorithm-conventions
-        text: [[Call]]; url: sec-ecmascript-function-objects-call-thisargument-argumentslist
-        text: promise; url: sec-promise-objects
-        text: DetachArrayBuffer; url: sec-detacharraybuffer
-        url: sec-list-and-record-specification-type
-            text: List
-            text: Record
-        text: map objects; url: sec-map-objects
-        text: InitializeHostDefinedRealm; url: sec-initializehostdefinedrealm
-        text: execution context; url: sec-execution-contexts
-
-spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/
-    type: enum; text: VisibilityState; url: VisibilityState
-    type: attribute; text: visibilityState; for: Document; url: dom-document-visibilitystate
-
-spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
-    type: attribute
-        urlPrefix: comms.html
-            text: origin; for: MessageEvent; url: dom-messageevent-origin
-            text: source; for: MessageEvent; url: dom-messageevent-source
-            text: ports; for: MessageEvent; url: dom-messageevent-ports
-            text: data; for: MessageEvent; url: dom-messageevent-data
-    type: dfn
-        urlPrefix: browsers.html
-            text: ancestor origins list; for: Location; url: concept-location-ancestor-origins-list
-        urlPrefix: syntax.html
-            text: delay the load event; for: document; url: delay-the-load-event
-
-spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
-    type: dfn
-        text: response; for: Response; url: concept-response-response
-        text: request; for: Request; url: concept-request-request
-        text: HTTP fetch; for: /; url: concept-http-fetch
-
-spec: rfc7230; urlPrefix: https://tools.ietf.org/html/rfc7230
-    type: dfn
-        text: field-value; for: http; url: section-3.2
-
-spec: rfc7231; urlPrefix: https://tools.ietf.org/html/rfc7231
-    type: dfn
-        text: Vary; url: section-7.1.4
-
-spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-referrer-policy/
-    type: dfn
-        text: Parse a referrer policy from a Referrer-Policy header; url: parse-referrer-policy-from-header
-
- -
-{
-  "unsanctioned-tracking": {
-    "href": "https://www.w3.org/2001/tag/doc/unsanctioned-tracking/",
-    "title": "Unsanctioned Web Tracking",
-    "date": "17 July 2015",
-    "status": "Finding of the W3C TAG",
-    "publisher": "W3C TAG"
-  }
-}
-
- -
-

Motivations

- - *This section is non-normative.* - - Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks. - - The [=/service worker=] is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the [=/service worker=], conceptually, between the network and a document renderer, allowing the [=/service worker=] to provide content for documents, even while offline. - - Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the [=/service worker=] is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep [=/service workers=] responsive in the face of a single-threaded execution model. As a result, APIs exposed by [=/service workers=] are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading. - - Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the [=/service worker=] is that errors should *always* be recoverable. Many details of the update process of [=/service workers=] are designed to avoid these hazards. - - [=/Service workers=] are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, [=/service workers=] bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. [=/Service workers=] may be started by user agents *without an attached document* and may be killed by the user agent at nearly any time. Conceptually, [=/service workers=] can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that [=/service workers=] may be started and killed many times a second. - - [=/Service workers=] are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope). -
- -
-

Model

- -
-

Service Worker

- - A service worker is a type of web worker. A [=/service worker=] executes in the registering [=/service worker client=]'s [=/origin=]. - - A [=/service worker=] has an associated state, which is one of "`parsed`", "`installing`", "`installed`", "`activating`", "`activated`", and "`redundant`". It is initially "`parsed`". - - A [=/service worker=] has an associated script url (a [=/URL=]). - - A [=/service worker=] has an associated type which is either "classic" or "module". Unless stated otherwise, it is "classic". - - A [=/service worker=] has an associated containing service worker registration (a [=/service worker registration=]), which contains itself. - - A [=/service worker=] has an associated global object (a {{ServiceWorkerGlobalScope}} object or null). - - A [=/service worker=] has an associated script resource (a script), which represents its own script resource. It is initially set to null. - - A script resource has an associated has ever been evaluated flag. It is initially unset. - - A script resource has an associated HTTPS state (an HTTPS state value). It is initially "none". - - A script resource has an associated referrer policy (a [=/referrer policy=]). It is initially the empty string. - - A [=/service worker=] has an associated script resource map which is an ordered map where the keys are [=/URLs=] and the values are [=/responses=]. - - A [=/service worker=] has an associated skip waiting flag. Unless stated otherwise it is unset. - - A [=/service worker=] has an associated classic scripts imported flag. It is initially unset. - - A [=/service worker=] has an associated set of event types to handle (a [=ordered set|set=]) whose [=list/item=] is an event listener's event type. It is initially an empty set. - - A [=/service worker=] has an associated set of extended events (a [=ordered set|set=]) whose [=list/item=] is an {{ExtendableEvent}}. It is initially an empty set. - -
-

Lifetime

- - The lifetime of a [=/service worker=] is tied to the execution lifetime of events and not references held by [=/service worker clients=] to the {{ServiceWorker}} object. - - A user agent *may* terminate [=/service workers=] at any time it: - - * Has no event to handle. - * Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events. -
- - A [=/service worker=] has an associated start status which can be null or a [=Completion=]. It is initially null. - - A [=/service worker=] is said to be running if its [=event loop=] is running. - -
-

Events

- - The Service Workers specification defines service worker events (each of which is an [=event=]) that include (see the list): - * Lifecycle events: {{install!!event}} and {{activate!!event}}. - * Functional events: {{fetch!!event}} and the [=events=] defined by other specifications that extend the Service Workers specification. (See the list.) - * {{message!!event}} and {{messageerror!!event}}. -
-
- -
-

Service Worker Registration

- - A service worker registration is a tuple of a [=service worker registration/scope url=] and a set of [=/service workers=], an installing worker, a waiting worker, and an active worker. A user agent *may* enable many [=/service worker registrations=] at a single origin so long as the [=service worker registration/scope url=] of the [=/service worker registration=] differs. A [=/service worker registration=] of an identical [=service worker registration/scope url=] when one already exists in the user agent causes the existing [=/service worker registration=] to be replaced. - - A [=/service worker registration=] has an associated scope url (a [=/URL=]). - - A [=/service worker registration=] has an associated installing worker (a [=/service worker=] or null) whose [=service worker/state=] is "`installing`". It is initially set to null. - - A [=/service worker registration=] has an associated waiting worker (a [=/service worker=] or null) whose [=service worker/state=] is "`installed`". It is initially set to null. - - A [=/service worker registration=] has an associated active worker (a [=/service worker=] or null) whose [=service worker/state=] is either "`activating`" or "`activated`". It is initially set to null. - - A [=/service worker registration=] has an associated last update check time. It is initially set to null. - - A [=/service worker registration=] is said to be stale if the registration's [=last update check time=] is non-null and the time difference in seconds calculated by the current time minus the registration's [=last update check time=] is greater than 86400. - - A [=/service worker registration=] has an associated update via cache mode, which is "`imports`", "`all`", or "`none`". It is initially set to "`imports`". - - A [=/service worker registration=] has one or more task queues that back up the tasks from its active worker's event loop's corresponding [=/task queues=]. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker's tasks to the [=/service worker registration=]'s [=service worker registration/task queues=] when the active worker is terminated and re-queues those tasks to the active worker's event loop's corresponding [=/task queues=] when the active worker spins off. Unlike the [=/task queues=] owned by event loops, the [=/service worker registration=]'s [=service worker registration/task queues=] are not processed by any event loops in and of itself. - - A [=/service worker registration=] is said to be unregistered if [=scope to registration map=][this [=/service worker registration=]'s [=service worker registration/scope url=]] is not this [=/service worker registration=]. - -
-

Lifetime

- - A user agent *must* persistently keep a list of registered [=/service worker registrations=] unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of [=/service worker registration=]'s [=service worker registration/scope url=], [=URL serializer|serialized=], and the corresponding [=/service worker registration=]. The lifetime of [=/service worker registrations=] is beyond that of the {{ServiceWorkerRegistration}} objects which represent them within the lifetime of their corresponding [=/service worker clients=]. -
-
- -
-

Service Worker Client

- - A service worker client is an [=environment=]. - - A [=/service worker client=] has an associated discarded flag. It is initially unset. - - Each [=/service worker client=] has the following [=environment discarding steps=]: - 1. Set |client|'s [=discarded flag=]. - - Note: Implementations can discard clients whose [=discarded flag=] is set. - - A [=/service worker client=] has an algorithm defined as the origin that returns the [=/service worker client=]'s [=environment settings object/origin=] if the [=/service worker client=] is an [=environment settings object=], and the [=/service worker client=]'s creation URL's [=url/origin=] otherwise. - - A window client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{Window}} object. - - A dedicated worker client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{DedicatedWorkerGlobalScope}} object. - - A shared worker client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{SharedWorkerGlobalScope}} object. - - A worker client is either a dedicated worker client or a shared worker client. -
- -
-

Control and Use

- - A [=/service worker client=] has an [=active service worker=] that serves its own loading and its subresources. When a [=/service worker client=] has a non-null [=active service worker=], it is said to be controlled by that [=active service worker=]. When a [=/service worker client=] is [=controlled=] by a [=/service worker=], it is said that the [=/service worker client=] is using the [=/service worker=]’s [=containing service worker registration=]. - A [=/service worker client=]'s [=active service worker=] is determined as explained in the following subsections. - - *The rest of the section is non-normative.* - - Note: The behavior in this section is not fully specified yet and will be specified in [HTML Standard](https://html.spec.whatwg.org). The work is tracked by the [issue](https://github.com/w3c/ServiceWorker/issues/765) and the [pull request](https://github.com/whatwg/html/pull/2809). For any Service Workers changes, we will incorporate them into [Service Workers Nightly](https://w3c.github.io/ServiceWorker/). - -
-

The window client case

- - A [=window client=] is [created](https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object) when a [=/browsing context=] is [created](https://html.spec.whatwg.org/#creating-a-new-browsing-context) and when it [=navigates=]. - - When a [=window client=] is [created](https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object) in the process of a [=/browsing context=] [creation](https://html.spec.whatwg.org/#creating-a-new-browsing-context): - - If the [=/browsing context=]'s initial [=active document=]'s [=/origin=] is an [=opaque origin=], the [=window client=]'s [=active service worker=] is set to null. - Otherwise, it is set to the creator [=document=]'s [=/service worker client=]'s [=active service worker=]. - - When a [=window client=] is [created](https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object) in the process of the [=/browsing context=]'s [=navigate|navigation=]: - - If the [=fetch=] is routed through [=/HTTP fetch=], the [=window client=]'s [=active service worker=] is set to the result of the service worker registration matching. - Otherwise, if the created [=document=]'s [=/origin=] is an [=opaque origin=] or not the [=same origin|same=] as its creator [=document=]'s [=/origin=], the [=window client=]'s [=active service worker=] is set to null. - Otherwise, it is set to the creator [=document=]'s [=/service worker client=]'s [=active service worker=]. - - Note: For an initial [=navigate|navigation=] with [=replacement enabled=], the initial [=window client=] that was [created](https://html.spec.whatwg.org/#set-up-a-window-environment-settings-object) when the [=/browsing context=] was [created](https://html.spec.whatwg.org/#creating-a-new-browsing-context) is reused, but the [=active service worker=] is determined by the same behavior as above. - - Note: Sandboxed <{iframe}>s without the sandboxing directives, `allow-same-origin` and `allow-scripts`, result in having the [=active service worker=] value of null as their [=/origin=] is an [=opaque origin=]. -
- -
-

The worker client case

- - A [=worker client=] is created when the user agent [=run a worker|runs a worker=]. - - When the [=worker client=] is created: - - When the [=fetch=] is routed through [=/HTTP fetch=], the [=worker client=]'s [=active service worker=] is set to the result of the service worker registration matching. - Otherwise, if the [=worker client=]'s [=service worker client/origin=] is an [=opaque origin=], or the [=/request=]'s [=request/URL=] is a [=blob URL=] and the [=worker client=]'s [=service worker client/origin=] is not the [=same origin|same=] as the [=/origin=] of the last [=set/item=] in the [=worker client=]'s [=/global object=]'s [=owner set=], the [=worker client=]'s [=active service worker=] is set to null. - Otherwise, it is set to the [=active service worker=] of the [=environment settings object=] of the last [=set/item=] in the [=worker client=]'s [=/global object=]'s [=owner set=]. -
- - Note: [=Window clients=] and [=worker clients=] with a [data: URL](https://tools.ietf.org/html/rfc2397#section-2) result in having the [=active service worker=] value of null as their [=/origin=] is an [=opaque origin=]. [=Window clients=] and [=worker clients=] with a [=blob URL=] can inherit the [=active service worker=] of their creator [=document=] or owner, but if the [=/request=]'s [=request/origin=] is not the [=same origin|same=] as the [=/origin=] of their creator [=document=] or owner, the [=active service worker=] is set to null. -
- -
-

Task Sources

- - The following additional task sources are used by [=/service workers=]. - - : The handle fetch task source - :: This task source is used for dispatching {{fetch!!event}} events to [=/service workers=]. - : The handle functional event task source - :: This task source is used for features that dispatch other functional events, e.g. {{push!!event}} events, to [=/service workers=]. - - Note: A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events. -
- -
-

User Agent Shutdown

- - A user agent *must* maintain the state of its stored [=/service worker registrations=] across restarts with the following rules: - - * An installing worker does not persist but is discarded. If the installing worker was the only [=/service worker=] for the [=/service worker registration=], the [=/service worker registration=] is discarded. - * A waiting worker promotes to an active worker. - - To attain this, the user agent *must* invoke Handle User Agent Shutdown when it terminates. -
-
-
-

Client Context

- -
- Bootstrapping with a service worker: - -
-      // scope defaults to the path the script sits in
-      // "/" in this example
-      navigator.serviceWorker.register("/serviceworker.js").then(registration => {
-        console.log("success!");
-        if (registration.installing) {
-          registration.installing.postMessage("Howdy from your installing page.");
-        }
-      }, err => {
-        console.error("Installing the worker failed!", err);
-      });
-    
-
- -
-

{{ServiceWorker}}

- -
-      [SecureContext, Exposed=(Window,Worker)]
-      interface ServiceWorker : EventTarget {
-        readonly attribute USVString scriptURL;
-        readonly attribute ServiceWorkerState state;
-        void postMessage(any message, optional sequence<object> transfer = []);
-
-        // event
-        attribute EventHandler onstatechange;
-      };
-      ServiceWorker includes AbstractWorker;
-
-      enum ServiceWorkerState {
-        "installing",
-        "installed",
-        "activating",
-        "activated",
-        "redundant"
-      };
-    
- - A {{ServiceWorker}} object represents a [=/service worker=]. Each {{ServiceWorker}} object is associated with a [=/service worker=]. Multiple separate objects implementing the {{ServiceWorker}} interface across documents and workers can all be associated with the same [=/service worker=] simultaneously. - - A {{ServiceWorker}} object has an associated {{ServiceWorkerState}} object which is itself associated with [=/service worker=]'s state. - -
-

Getting {{ServiceWorker}} instances

- - An [=environment settings object=] has a service worker object map, a [=/map=] where the [=map/keys=] are [=/service workers=] and the [=map/values=] are {{ServiceWorker}} objects. - -
- To get the service worker object representing |serviceWorker| (a [=/service worker=]) in |environment| (an [=environment settings object=]), run these steps: - - 1. Let |objectMap| be |environment|'s [=environment settings object/service worker object map=]. - 1. If |objectMap|[|serviceWorker|] does not [=map/exist=], then: - 1. Let |serviceWorkerObj| be a new {{ServiceWorker}} in |environment|'s [=environment settings object/Realm=], and associate it with |serviceWorker|. - 1. Set |serviceWorkerObj|'s {{ServiceWorker/state}} to |serviceWorker|'s [=service worker/state=]. - 1. Set |objectMap|[|serviceWorker|] to |serviceWorkerObj|. - 1. Return |objectMap|[|serviceWorker|]. -
-
- -
-

{{ServiceWorker/scriptURL}}

- - The scriptURL attribute *must* return the [=/service worker=]'s serialized [=service worker/script url=]. - -
- For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed: - -
-          // Script on the page https://example.com/app.html
-          navigator.serviceWorker.register("/service_worker.js");
-        
- - The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js". -
-
- -
-

{{ServiceWorker/state}}

- - The state attribute *must* return the value (in {{ServiceWorkerState}} enumeration) to which it was last set. -
- -
-

{{ServiceWorker/postMessage(message, transfer)}}

- - The postMessage(|message|, |transfer|) method *must* run these steps: - - 1. Let |serviceWorker| be the [=/service worker=] represented by the [=context object=]. - 1. Let |incumbentSettings| be the [=incumbent settings object=]. - 1. Let |incumbentGlobal| be |incumbentSettings|'s [=environment settings object/global object=]. - 1. Let |serializeWithTransferResult| be StructuredSerializeWithTransfer(|message|, |transfer|). Rethrow any exceptions. - 1. If the result of running the [=Should Skip Event=] algorithm with "message" and |serviceWorker| is true, then return. - 1. Run these substeps [=in parallel=]: - 1. If the result of running the [=Run Service Worker=] algorithm with |serviceWorker| is *failure*, then return. - 1. [=Queue a task=] on the [=DOM manipulation task source=] to run the following steps: - 1. Let |source| be determined by switching on the type of |incumbentGlobal|: -
-
{{ServiceWorkerGlobalScope}}
-
The result of [=getting the service worker object=] that represents |incumbentGlobal|'s [=ServiceWorkerGlobalScope/service worker=] in the [=relevant settings object=] of |serviceWorker|'s [=service worker/global object=].
- -
{{Window}}
-
a new {{WindowClient}} object that represents |incumbentGlobal|'s [=relevant settings object=].
- -
Otherwise
-
a new {{Client}} object that represents |incumbentGlobal|'s associated worker -
- 1. Let |origin| be the [=serialization of an origin|serialization=] of |incumbentSettings|'s [=environment settings object/origin=]. - 1. Let |destination| be the {{ServiceWorkerGlobalScope}} object associated with |serviceWorker|. - 1. Let |deserializeRecord| be StructuredDeserializeWithTransfer(|serializeWithTransferResult|, |destination|'s [=global object/Realm=]). - - If this throws an exception, catch it, [=fire an event=] named {{messageerror!!event}} at |destination|, using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to |origin| and the {{MessageEvent/source}} attribute initialized to |source|, and then abort these steps. - 1. Let |messageClone| be |deserializeRecord|.\[[Deserialized]]. - 1. Let |newPorts| be a new [=frozen array type|frozen array=] consisting of all {{MessagePort}} objects in |deserializeRecord|.\[[TransferredValues]], if any, maintaining their relative order. - 1. Let |e| be the result of [=creating an event=] named {{message!!event}}, using {{ExtendableMessageEvent}}, with the {{ExtendableMessageEvent/origin}} attribute initialized to |origin|, the {{ExtendableMessageEvent/source}} attribute initialized to |source|, the {{ExtendableMessageEvent/data}} attribute initialized to |messageClone|, and the {{ExtendableMessageEvent/ports}} attribute initialized to |newPorts|. - 1. [=Dispatch=] |e| at |destination|. - 1. Invoke [=Update Service Worker Extended Events Set=] with |serviceWorker| and |e|. -
- -
-

Event handler

- - The following is the event handler (and its corresponding event handler event type) that *must* be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorker}} interface: - - - - - - - - - - - - - - -
event handlerevent handler event type
onstatechange{{ServiceWorker/statechange}}
-
-
- -
-

{{ServiceWorkerRegistration}}

- -
-      [SecureContext, Exposed=(Window,Worker)]
-      interface ServiceWorkerRegistration : EventTarget {
-        readonly attribute ServiceWorker? installing;
-        readonly attribute ServiceWorker? waiting;
-        readonly attribute ServiceWorker? active;
-
-        readonly attribute USVString scope;
-        readonly attribute ServiceWorkerUpdateViaCache updateViaCache;
-
-        [NewObject] Promise<void> update();
-        [NewObject] Promise<boolean> unregister();
-
-        // event
-        attribute EventHandler onupdatefound;
-      };
-
-      enum ServiceWorkerUpdateViaCache {
-        "imports",
-        "all",
-        "none"
-      };
-    
- - A {{ServiceWorkerRegistration}} has a service worker registration (a [=/service worker registration=]). - -
-

Getting {{ServiceWorkerRegistration}} instances

- - An [=environment settings object=] has a service worker registration object map, a [=/map=] where the [=map/keys=] are [=/service worker registrations=] and the [=map/values=] are {{ServiceWorkerRegistration}} objects. - -
- To get the service worker registration object representing |registration| (a [=/service worker registration=]) in |environment| (an [=environment settings object=]), run these steps: - - 1. Let |objectMap| be |environment|'s [=environment settings object/service worker registration object map=]. - 1. If |objectMap|[|registration|] does not [=map/exist=], then: - 1. Let |registrationObject| be a new {{ServiceWorkerRegistration}} in |environment|'s [=environment settings object/Realm=]. - 1. Set |registrationObject|'s [=ServiceWorkerRegistration/service worker registration=] to |registration|. - 1. Set |registrationObject|'s {{ServiceWorkerRegistration/installing}} attribute to null. - 1. Set |registrationObject|'s {{ServiceWorkerRegistration/waiting}} attribute to null. - 1. Set |registrationObject|'s {{ServiceWorkerRegistration/active}} attribute to null. - 1. If |registration|'s [=service worker registration/installing worker=] is not null, then set |registrationObject|'s {{ServiceWorkerRegistration/installing}} attribute to the result of [=getting the service worker object=] that represents |registration|'s [=service worker registration/installing worker=] in |environment|. - 1. If |registration|'s [=service worker registration/waiting worker=] is not null, then set |registrationObject|'s {{ServiceWorkerRegistration/waiting}} attribute to the result of [=getting the service worker object=] that represents |registration|'s [=service worker registration/waiting worker=] in |environment|. - 1. If |registration|'s [=service worker registration/active worker=] is not null, then set |registrationObject|'s {{ServiceWorkerRegistration/active}} attribute to the result of [=getting the service worker object=] that represents |registration|'s [=service worker registration/active worker=] in |environment|. - 1. Set |objectMap|[|registration|] to |registrationObject|. - 1. Return |objectMap|[|registration|]. -
-
- -
- - - installing attribute *must* return the value to which it was last set. - - Note: Within a [=environment settings object/Realm=], there is only one {{ServiceWorker}} object per associated [=/service worker=]. -
- -
- - - waiting attribute *must* return the value to which it was last set. - - Note: Within a [=environment settings object/Realm=], there is only one {{ServiceWorker}} object per associated [=/service worker=]. -
- -
- - - active attribute *must* return the value to which it was last set. - - Note: Within a [=environment settings object/Realm=], there is only one {{ServiceWorker}} object per associated [=/service worker=]. -
- -
-

{{ServiceWorkerRegistration/scope}}

- - The scope attribute *must* return [=ServiceWorkerRegistration/service worker registration=]'s serialized [=service worker registration/scope url=]. - -
- In the example in [[#service-worker-url]], the value of registration.scope, obtained from navigator.serviceWorker.ready.then(registration => console.log(registration.scope)) for example, will be "https://example.com/". -
-
- -
-

{{ServiceWorkerRegistration/updateViaCache}}

- - The updateViaCache attribute *must* return [=ServiceWorkerRegistration/service worker registration=]'s [=service worker registration/update via cache mode=]. -
- -
-

{{ServiceWorkerRegistration/update()}}

- - update() method *must* run these steps: - - 1. Let |registration| be the [=ServiceWorkerRegistration/service worker registration=]. - 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. - 1. If |newestWorker| is null, return [=a promise rejected with=] an "{{InvalidStateError}}" {{DOMException}} and abort these steps. - 1. If the context object's relevant settings object's [=environment settings object/global object=] |globalObject| is a {{ServiceWorkerGlobalScope}} object, and |globalObject|'s associated [=ServiceWorkerGlobalScope/service worker=]'s state is "`installing`", return [=a promise rejected with=] an "{{InvalidStateError}}" {{DOMException}} and abort these steps. - 1. Let |promise| be a promise. - 1. Let |job| be the result of running Create Job with *update*, |registration|'s [=service worker registration/scope url=], |newestWorker|'s [=service worker/script url=], |promise|, and the context object's relevant settings object. - 1. Set |job|'s worker type to |newestWorker|'s [=service worker/type=]. - 1. Invoke Schedule Job with |job|. - 1. Return |promise|. -
- -
- - - Note: The {{ServiceWorkerRegistration/unregister()}} method unregisters the [=/service worker registration=]. It is important to note that the currently [=controlled=] [=/service worker client=]'s [=active service worker=]'s [=containing service worker registration=] is effective until all the [=/service worker clients=] (including itself) using this [=/service worker registration=] unload. That is, the {{ServiceWorkerRegistration/unregister()}} method only affects subsequent [=navigate|navigations=]. - - unregister() method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Let |job| be the result of running [=Create Job=] with *unregister*, the [=service worker registration/scope url=] of the [=ServiceWorkerRegistration/service worker registration=], null, |promise|, and the context object's relevant settings object. - 1. Invoke Schedule Job with |job|. - 1. Return |promise|. -
- -
-

Event handler

- - The following is the event handler (and its corresponding event handler event type) that *must* be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorkerRegistration}} interface: - - - - - - - - - - - - - - -
event handlerevent handler event type
onupdatefound{{updatefound!!event}}
-
-
- -
- - -
-      partial interface Navigator {
-        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
-      };
-
-      partial interface WorkerNavigator {
-        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
-      };
-    
- - The serviceWorker attribute *must* return the {{ServiceWorkerContainer}} object that is associated with the context object. -
- -
-

{{ServiceWorkerContainer}}

- -
-      [SecureContext, Exposed=(Window,Worker)]
-      interface ServiceWorkerContainer : EventTarget {
-        readonly attribute ServiceWorker? controller;
-        readonly attribute Promise<ServiceWorkerRegistration> ready;
-
-        [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options = {});
-
-        [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
-        [NewObject] Promise<FrozenArray<ServiceWorkerRegistration>> getRegistrations();
-
-        void startMessages();
-
-
-        // events
-        attribute EventHandler oncontrollerchange;
-        attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
-        attribute EventHandler onmessageerror;
-      };
-    
-
-      dictionary RegistrationOptions {
-        USVString scope;
-        WorkerType type = "classic";
-        ServiceWorkerUpdateViaCache updateViaCache = "imports";
-      };
-    
- - The user agent *must* create a {{ServiceWorkerContainer}} object when a {{Navigator}} object or a {{WorkerNavigator}} object is created and associate it with that object. - - A {{ServiceWorkerContainer}} provides capabilities to register, unregister, and update the [=/service worker registrations=], and provides access to the state of the [=/service worker registrations=] and their associated [=/service workers=]. - - A {{ServiceWorkerContainer}} has an associated service worker client, which is a [=/service worker client=] whose [=environment settings object/global object=] is associated with the {{Navigator}} object or the {{WorkerNavigator}} object that the {{ServiceWorkerContainer}} is retrieved from. - - A {{ServiceWorkerContainer}} object has an associated ready promise (a [=promise=] or null). It is initially null. - - A {{ServiceWorkerContainer}} object has a task source called the client message queue, initially empty. A [=ServiceWorkerContainer/client message queue=] can be enabled or disabled, and is initially disabled. When a {{ServiceWorkerContainer}} object's [=ServiceWorkerContainer/client message queue=] is enabled, the event loop *must* use it as one of its task sources. When the {{ServiceWorkerContainer}} object's relevant global object is a {{Window}} object, all tasks queued on its [=ServiceWorkerContainer/client message queue=] *must* be associated with its relevant settings object's responsible document. - -
- - - controller attribute *must* run these steps: - - 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. - 1. If |client|'s [=active service worker=] is null, then return null. - 1. Return the result of [=getting the service worker object=] that represents |client|'s [=active service worker=] in the [=context object=]'s [=relevant settings object=]. - - Note: {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} returns null if the request is a force refresh (shift+refresh). -
- -
- - - ready attribute *must* run these steps: - - 1. If the [=context object=]'s [=ServiceWorkerContainer/ready promise=] is null, then set the [=context object=]'s [=ServiceWorkerContainer/ready promise=] to [=a new promise=]. - 1. Let |readyPromise| be the [=context object=]'s [=ServiceWorkerContainer/ready promise=]. - 1. If |readyPromise| is pending, run the following substeps [=in parallel=]: - 1. Let |registration| be the result of running [=Match Service Worker Registration=] with the [=context object=]'s [=ServiceWorkerContainer/service worker client=]'s [=creation URL=]. - 1. If |registration| is not null, and |registration|'s [=active worker=] is not null, [=queue a task=] on |readyPromise|'s [=relevant settings object=]'s [=responsible event loop=], using the [=DOM manipulation task source=], to resolve |readyPromise| with the result of [=getting the service worker registration object=] that represents |registration| in |readyPromise|'s [=relevant settings object=]. - 1. Return |readyPromise|. - - Note: The returned [=ServiceWorkerContainer/ready promise=] will never reject. If it does not resolve in this algorithm, it will eventually resolve when a matching [=/service worker registration=] is registered and its [=active worker=] is set. (See the relevant [Activate algorithm step](#activate-resolve-ready-step).) -
- -
- - - Note: The {{ServiceWorkerContainer/register(scriptURL, options)}} method creates or updates a [=/service worker registration=] for the given [=service worker registration/scope url=]. If successful, a [=/service worker registration=] ties the provided |scriptURL| to a [=service worker registration/scope url=], which is subsequently used for navigation matching. - - register(|scriptURL|, |options|) method *must* run these steps: - - 1. Let |p| be a promise. - 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. - 1. Let |scriptURL| be the result of parsing |scriptURL| with the context object's relevant settings object's API base URL. - 1. If |scriptURL| is failure, reject |p| with a TypeError and abort these steps. - 1. Set |scriptURL|'s [=url/fragment=] to null. - - Note: The user agent does not store the [=url/fragment=] of the script's url. This means that the [=url/fragment=] does not have an effect on identifying [=/service workers=]. - - 1. If |scriptURL|'s [=url/scheme=] is not one of "http" and "https", reject |p| with a TypeError and abort these steps. - 1. If any of the strings in |scriptURL|'s [=url/path=] contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject |p| with a TypeError and abort these steps. - 1. Let |scopeURL| be null. - 1. If |options|.{{RegistrationOptions/scope}} is not present, set |scopeURL| to the result of parsing a string "./" with |scriptURL|. - - Note: The scope url for the registration is set to the location of the service worker script by default. - - 1. Else, set |scopeURL| to the result of parsing |options|.{{RegistrationOptions/scope}} with the context object's relevant settings object's API base URL. - 1. If |scopeURL| is failure, reject |p| with a TypeError and abort these steps. - 1. Set |scopeURL|'s [=url/fragment=] to null. - - Note: The user agent does not store the [=url/fragment=] of the scope url. This means that the [=url/fragment=] does not have an effect on identifying [=/service worker registrations=]. - - 1. If |scopeURL|'s [=url/scheme=] is not one of "http" and "https", reject |p| with a TypeError and abort these steps. - 1. If any of the strings in |scopeURL|'s [=url/path=] contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject |p| with a TypeError and abort these steps. - 1. Let |job| be the result of running Create Job with *register*, |scopeURL|, |scriptURL|, |p|, and |client|. - 1. Set |job|'s [=job/worker type=] to |options|.{{RegistrationOptions/type}}. - 1. Set |job|'s [=job/update via cache mode=] to |options|.{{RegistrationOptions/updateViaCache}}. - 1. Invoke Schedule Job with |job|. - 1. Return |p|. -
- -
- - - getRegistration(|clientURL|) method *must* run these steps: - - 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. - 1. Let |clientURL| be the result of parsing |clientURL| with the context object's relevant settings object's API base URL. - 1. If |clientURL| is failure, return a promise rejected with a TypeError. - 1. Set |clientURL|'s [=url/fragment=] to null. - 1. If the [=environment settings object/origin=] of |clientURL| is not |client|'s [=environment settings object/origin=], return a |promise| rejected with a "{{SecurityError}}" {{DOMException}}. - 1. Let |promise| be a new promise. - 1. Run the following substeps in parallel: - 1. Let |registration| be the result of running Match Service Worker Registration algorithm with |clientURL| as its argument. - 1. If |registration| is null, resolve |promise| with undefined and abort these steps. - 1. Resolve |promise| with the result of [=getting the service worker registration object=] that represents |registration| in |promise|'s [=relevant settings object=]. - 1. Return |promise|. -
- -
- - - getRegistrations() method *must* run these steps: - - 1. Let |client| be the [=context object=]'s [=ServiceWorkerContainer/service worker client=]. - 1. Let |promise| be [=a new promise=]. - 1. Run the following steps [=in parallel=]: - 1. Let |registrations| be a new [=list=]. - 1. [=map/For each=] |scope| → |registration| of [=scope to registration map=]: - 1. If the [=url/origin=] of the result of [=URL parser|parsing=] |scope| is the [=same origin|same=] as |client|'s [=environment settings object/origin=], then [=append=] |registration| to |registrations|. - 1. [=Queue a task=] on |promise|'s [=relevant settings object=]'s [=responsible event loop=], using the [=DOM manipulation task source=], to run the following steps: - 1. Let |registrationObjects| be a new [=list=]. - 1. [=list/For each=] |registration| of |registrations|: - 1. Let |registrationObj| be the result of [=getting the service worker registration object=] that represents |registration| in |promise|'s [=relevant settings object=]. - 1. [=list/Append=] |registrationObj| to |registrationObjects|. - 1. Resolve |promise| with [=create a frozen array|a new frozen array of=] |registrationObjects| in |promise|'s [=relevant Realm=]. - 1. Return |promise|. -
- -
- - - startMessages() method *must* enable the context object's [=ServiceWorkerContainer/client message queue=] if it is not enabled. -
- -
-

Event handlers

- - The following are the event handlers (and their corresponding event handler event types) that *must* be supported, as event handler IDL attributes, by all objects implementing the {{ServiceWorkerContainer}} interface: - - - - - - - - - - - - - - - - - - - - - - -
event handlerevent handler event type
oncontrollerchange{{ServiceWorkerContainer/controllerchange!!event}}
onmessage{{message!!event}}
onmessageerror{{messageerror!!event}}
- - The first time the context object's {{ServiceWorkerContainer/onmessage}} IDL attribute is set, its [=ServiceWorkerContainer/client message queue=] *must* be enabled. -
-
-
-

Events

- - The following event is dispatched on {{ServiceWorker}} object: - - - - - - - - - - - - - - - - -
Event nameInterfaceDispatched when…
statechange{{Event}}The {{ServiceWorker/state}} attribute of the {{ServiceWorker}} object is changed.
- - The following event is dispatched on {{ServiceWorkerRegistration}} object: - - - - - - - - - - - - - - - - -
Event nameInterfaceDispatched when…
updatefound{{Event}}The [=ServiceWorkerRegistration/service worker registration=]'s installing worker changes. (See step 8 of the Install algorithm.)
- - The following events are dispatched on {{ServiceWorkerContainer}} object: - - - - - - - - - - - - - - - - -
Event nameInterfaceDispatched when…
controllerchange{{Event}}The [=ServiceWorkerContainer/service worker client=]'s active service worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a [=/service worker=] causes activation of the [=/service worker registration=] to occur while [=/service worker clients=] are using the [=/service worker registration=], {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} immediately reflects the active worker as the [=/service worker=] that controls the [=/service worker client=].)
-
-
- -
-

Execution Context

- -
- Serving Cached Resources: - -
-      // caching.js
-      self.addEventListener("install", event => {
-        event.waitUntil(
-          // Open a cache of resources.
-          caches.open("shell-v1").then(cache => {
-            // Begins the process of fetching them.
-            // The coast is only clear when all the resources are ready.
-            return cache.addAll([
-              "/app.html",
-              "/assets/v1/base.css",
-              "/assets/v1/app.js",
-              "/assets/v1/logo.png",
-              "/assets/v1/intro_video.webm"
-            ]);
-          })
-        );
-      });
-
-      self.addEventListener("fetch", event => {
-        // No "fetch" events are dispatched to the service worker until it
-        // successfully installs and activates.
-
-        // All operations on caches are async, including matching URLs, so we use
-        // promises heavily. e.respondWith() even takes promises to enable this:
-        event.respondWith(
-          caches.match(e.request).then(response => {
-            return response || fetch(e.request);
-          }).catch(() => {
-            return caches.match("/fallback.html");
-          })
-        );
-      });
-    
-
- -
-

{{ServiceWorkerGlobalScope}}

- -
-      [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
-      interface ServiceWorkerGlobalScope : WorkerGlobalScope {
-        [SameObject] readonly attribute Clients clients;
-        [SameObject] readonly attribute ServiceWorkerRegistration registration;
-
-        [NewObject] Promise<void> skipWaiting();
-
-        attribute EventHandler oninstall;
-        attribute EventHandler onactivate;
-        attribute EventHandler onfetch;
-
-        attribute EventHandler onmessage;
-        attribute EventHandler onmessageerror;
-      };
-    
- - A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated force bypass cache for import scripts flag. It is initially unset. - - Note: {{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a [=/service worker=] is started, kept alive and killed by their relationship to events, not [=/service worker clients=]. Any type of synchronous requests must not be initiated inside of a [=/service worker=]. - -
-

{{ServiceWorkerGlobalScope/clients}}

- - The clients attribute *must* return the {{Clients}} object that is associated with the context object. -
- -
-

{{ServiceWorkerGlobalScope/registration}}

- - The registration attribute *must* return the result of [=getting the service worker registration object=] representing the [=context object=]'s [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=] in [=context object=]'s [=relevant settings object=]. -
- -
-

{{ServiceWorkerGlobalScope/skipWaiting()}}

- - Note: The {{ServiceWorkerGlobalScope/skipWaiting()}} method allows this [=/service worker=] to progress from the [=service worker/registration=]'s waiting position to active even while [=/service worker clients=] are using the [=service worker/registration=]. - - skipWaiting() method *must* run these steps: - - 1. Let |promise| be a new promise. - 1. Run the following substeps in parallel: - 1. Set [=ServiceWorkerGlobalScope/service worker=]'s skip waiting flag. - 1. Invoke [=Try Activate=] with [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. - 1. Resolve |promise| with undefined. - 1. Return |promise|. -
- -
-

Event handlers

- - The following are the event handlers (and their corresponding event handler event types) that *must* be supported, as event handler IDL attributes, by all objects implementing the {{ServiceWorkerGlobalScope}} interface: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
event handlerevent handler event type
oninstall{{install!!event}}
onactivate{{activate!!event}}
onfetch{{fetch!!event}}
onmessage{{message!!event}}
onmessageerror{{messageerror!!event}}
-
-
- -
-

{{Client}}

- -
-      [Exposed=ServiceWorker]
-      interface Client {
-        readonly attribute USVString url;
-        readonly attribute FrameType frameType;
-        readonly attribute DOMString id;
-        readonly attribute ClientType type;
-        void postMessage(any message, optional sequence<object> transfer = []);
-      };
-
-      [Exposed=ServiceWorker]
-      interface WindowClient : Client {
-        readonly attribute VisibilityState visibilityState;
-        readonly attribute boolean focused;
-        [SameObject] readonly attribute FrozenArray<USVString> ancestorOrigins;
-        [NewObject] Promise<WindowClient> focus();
-        [NewObject] Promise<WindowClient?> navigate(USVString url);
-      };
-
-      enum FrameType {
-        "auxiliary",
-        "top-level",
-        "nested",
-        "none"
-      };
-    
- - A {{Client}} object has an associated service worker client (a [=/service worker client=]). - - A {{Client}} object has an associated frame type, which is one of "`auxiliary`", "`top-level`", "`nested`", and "`none`". Unless stated otherwise it is "`none`". - - A {{WindowClient}} object has an associated browsing context, which is its [=Client/service worker client=]'s [=environment settings object/global object=]'s [=/browsing context=]. - - A {{WindowClient}} object has an associated visibility state, which is one of {{Document/visibilityState}} attribute value. - - A {{WindowClient}} object has an associated focus state, which is either true or false (initially false). - - A {{WindowClient}} object has an associated ancestor origins array. - -
-

{{Client/url}}

- - The url attribute *must* return the context object's associated [=Client/service worker client=]'s serialized creation URL. -
- -
-

{{Client/frameType}}

- - The frameType attribute *must* return the [=context object=]'s [=frame type=]. -
- -
-

{{Client/id}}

- - The id attribute *must* return its associated [=Client/service worker client=]'s [=environment/id=]. -
- -
-

{{Client/type}}

- - The type attribute *must* run these steps: - - 1. Let |client| be [=context object=]'s [=Client/service worker client=]. - 1. If |client| is an [=environment settings object=], then: - 1. If |client| is a [=window client=], return {{ClientType/"window"}}. - 1. Else if |client| is a [=dedicated worker client=], return {{ClientType/"worker"}}. - 1. Else if |client| is a [=shared worker client=], return {{ClientType/"sharedworker"}}. - 1. Else: - 1. Return {{ClientType/"window"}}. -
- -
-

{{Client/postMessage(message, transfer)}}

- - The postMessage(|message|, |transfer|) method *must* run these steps: - - 1. Let |contextObject| be the [=context object=]. - 1. Let |sourceSettings| be the |contextObject|'s [=relevant settings object=]. - 1. Let |serializeWithTransferResult| be StructuredSerializeWithTransfer(|message|, |transfer|). Rethrow any exceptions. - 1. Run the following steps [=in parallel=]: - 1. Let |targetClient| be null. - 1. For each [=/service worker client=] |client|: - 1. If |client| is the |contextObject|'s [=Client/service worker client=], set |targetClient| to |client|, and [=break=]. - 1. If |targetClient| is null, return. - 1. Let |destination| be the {{ServiceWorkerContainer}} object whose associated [=ServiceWorkerContainer/service worker client=] is |targetClient|. - 1. Add a [=task=] that runs the following steps to |destination|'s [=ServiceWorkerContainer/client message queue=]: - 1. Let |origin| be the [=serialization of an origin|serialization=] of |sourceSettings|'s [=environment settings object/origin=]. - 1. Let |source| be the result of [=getting the service worker object=] that represents |contextObject|'s [=relevant global object=]'s [=ServiceWorkerGlobalScope/service worker=] in |targetClient|. - 1. Let |deserializeRecord| be StructuredDeserializeWithTransfer(|serializeWithTransferResult|, |destination|'s [=relevant Realm=]). - - If this throws an exception, catch it, [=fire an event=] named {{messageerror!!event}} at |destination|, using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to |origin| and the {{MessageEvent/source}} attribute initialized to |source|, and then abort these steps. - 1. Let |messageClone| be |deserializeRecord|.\[[Deserialized]]. - 1. Let |newPorts| be a new [=frozen array type|frozen array=] consisting of all {{MessagePort}} objects in |deserializeRecord|.\[[TransferredValues]], if any. - 1. [=Dispatch|Dispatch an event=] named {{Window/message!!event}} at |destination|, using {{MessageEvent}}, with the {{MessageEvent/origin}} attribute initialized to |origin|, the {{MessageEvent/source}} attribute initialized to |source|, the {{MessageEvent/data}} attribute initialized to |messageClone|, and the {{MessageEvent/ports}} attribute initialized to |newPorts|. -
- -
-

{{WindowClient/visibilityState}}

- - The visibilityState attribute *must* return the context object's visibility state. -
- -
-

{{WindowClient/focused}}

- - The focused attribute *must* return the context object's focus state. -
- -
-

{{WindowClient/ancestorOrigins}}

- - The ancestorOrigins attribute *must* return the context object's associated [=WindowClient/ancestor origins array=]. -
- -
-

{{WindowClient/focus()}}

- - The focus() method *must* run these steps: - - 1. If this algorithm is not triggered by user activation, return a promise rejected with an "{{InvalidAccessError}}" {{DOMException}}. - 1. Let |serviceWorkerEventLoop| be the [=current global object=]'s [=event loop=]. - 1. Let |promise| be a new promise. - 1. [=Queue a task=] to run the following steps on the [=context object=]'s associated [=Client/service worker client=]'s [=responsible event loop=] using the [=user interaction task source=]: - 1. Run the [=focusing steps=] with the [=context object=]'s [=WindowClient/browsing context=]. - 1. Let |frameType| be the result of running [=Get Frame Type=] with the [=context object=]'s [=WindowClient/browsing context=]. - 1. Let |visibilityState| be the [=context object=]'s [=WindowClient/browsing context=]'s [=active document=]'s {{Document/visibilityState}} attribute value. - 1. Let |focusState| be the result of running the [=has focus steps=] with the [=context object=]'s [=WindowClient/browsing context=]'s [=active document=]. - 1. Let |ancestorOriginsList| be the [=context object=]'s [=WindowClient/browsing context=]'s [=active document=]'s [=relevant global object=]'s {{Location}} object's [=Location/ancestor origins list=]'s associated list. - 1. [=Queue a task=] to run the following steps on |serviceWorkerEventLoop| using the [=DOM manipulation task source=]: - 1. Let |windowClient| be the result of running [=Create Window Client=] with the [=context object=]'s associated [=Client/service worker client=], |frameType|, |visibilityState|, |focusState|, and |ancestorOriginsList|. - 1. If |windowClient|'s [=focus state=] is true, resolve |promise| with |windowClient|. - 1. Else, reject |promise| with a `TypeError`. - 1. Return |promise|. -
- -
-

{{WindowClient/navigate(url)}}

- - The navigate(url) method *must* run these steps: - - 1. Let |url| be the result of parsing |url| with the context object's relevant settings object's API base URL. - 1. If |url| is failure, return a promise rejected with a TypeError. - 1. If |url| is about:blank, return a promise rejected with a TypeError. - 1. If the context object's associated [=Client/service worker client=]'s active service worker is not the context object's relevant global object's [=ServiceWorkerGlobalScope/service worker=], return a promise rejected with a TypeError. - 1. Let |serviceWorkerEventLoop| be the [=current global object=]'s [=event loop=]. - 1. Let |promise| be a new promise. - 1. [=Queue a task=] to run the following steps on the [=context object=]'s associated [=Client/service worker client=]'s [=responsible event loop=] using the [=user interaction task source=]: - 1. Let |browsingContext| be the [=context object=]'s [=WindowClient/browsing context=]. - 1. If |browsingContext| has [=discard a document|discarded=] its {{Document}}, [=queue a task=] to reject |promise| with a `TypeError`, on |serviceWorkerEventLoop| using the [=DOM manipulation task source=], and abort these steps. - 1. *HandleNavigate*: [=Navigate=] |browsingContext| to |url| with [=exceptions enabled flag|exceptions enabled=]. The [=source browsing context=] must be |browsingContext|. - 1. If the algorithm steps invoked in the step labeled *HandleNavigate* [=throws=] an exception, [=queue a task=] to reject |promise| with the exception, on |serviceWorkerEventLoop| using the [=DOM manipulation task source=], and abort these steps. - 1. Let |frameType| be the result of running [=Get Frame Type=] with |browsingContext|. - 1. Let |visibilityState| be |browsingContext|'s active document's {{Document/visibilityState}} attribute value. - 1. Let |focusState| be the result of running the [=has focus steps=] with |browsingContext|'s [=active document=]. - 1. Let |ancestorOriginsList| be |browsingContext|'s [=active document=]'s [=relevant global object=]'s {{Location}} object's [=Location/ancestor origins list=]'s associated list. - 1. [=Queue a task=] to run the following steps on |serviceWorkerEventLoop| using the [=DOM manipulation task source=]: - 1. If |browsingContext|'s {{Window}} object's environment settings object's creation URL's [=url/origin=] is not the same as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=], resolve |promise| with null and abort these steps. - 1. Let |windowClient| be the result of running [=Create Window Client=] with the [=context object=]'s [=Client/service worker client=], |frameType|, |visibilityState|, |focusState|, and |ancestorOriginsList|. - 1. Resolve |promise| with |windowClient|. - 1. Return |promise|. -
-
- -
-

{{Clients}}

- -
-      [Exposed=ServiceWorker]
-      interface Clients {
-        // The objects returned will be new instances every time
-        [NewObject] Promise<any> get(DOMString id);
-        [NewObject] Promise<FrozenArray<Client>> matchAll(optional ClientQueryOptions options = {});
-        [NewObject] Promise<WindowClient?> openWindow(USVString url);
-        [NewObject] Promise<void> claim();
-      };
-    
-
-      dictionary ClientQueryOptions {
-        boolean includeUncontrolled = false;
-        ClientType type = "window";
-      };
-    
-
-      enum ClientType {
-        "window",
-        "worker",
-        "sharedworker",
-        "all"
-      };
-    
- - The user agent *must* create a {{Clients}} object when a {{ServiceWorkerGlobalScope}} object is created and associate it with that object. - -
-

{{Clients/get(id)}}

- - The get(|id|) method *must* run these steps: - - 1. Let |promise| be a new promise. - 1. Run these substeps in parallel: - 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the same as the associated [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: - 1. If |client|'s [=environment/id=] is not |id|, [=continue=]. - 1. Wait for either |client|'s [=environment/execution ready flag=] to be set or for |client|'s [=discarded flag=] to be set. - 1. If |client|'s [=environment/execution ready flag=] is set, then invoke [=Resolve Get Client Promise=] with |client| and |promise|, and abort these steps. - 1. Resolve |promise| with undefined. - 1. Return |promise|. -
- -
-

{{Clients/matchAll(options)}}

- - The matchAll(|options|) method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Run the following steps [=in parallel=]: - 1. Let |targetClients| be a new [=list=]. - 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the [=same origin|same=] as the associated [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: - 1. If |client|'s [=environment/execution ready flag=] is unset or |client|'s [=discarded flag=] is set, [=continue=]. - 1. If |client| is not a [=secure context=], [=continue=]. - 1. If |options|["{{ClientQueryOptions/includeUncontrolled}}"] is false, and if |client|'s [=active service worker=] is not the associated [=ServiceWorkerGlobalScope/service worker=], [=continue=]. - 1. Add |client| to |targetClients|. - 1. Let |matchedWindowData| be a new [=list=]. - 1. Let |matchedClients| be a new [=list=]. - 1. For each [=/service worker client=] |client| in |targetClients|: - 1. If |options|["{{ClientQueryOptions/type}}"] is {{ClientType/"window"}} or {{ClientType/"all"}}, and |client| is not an [=environment settings object=] or is a [=window client=], then: - 1. Let |windowData| be «[ "client" → |client|, "ancestorOriginsList" → a new [=list=] ]». - 1. Let |browsingContext| be null. - 1. Let |isClientEnumerable| be true. - 1. If |client| is an [=environment settings object=], set |browsingContext| to |client|'s [=environment settings object/global object=]'s [=/browsing context=]. - 1. Else, set |browsingContext| to |client|’s [=environment/target browsing context=]. - 1. [=Queue a task=] |task| to run the following substeps on |browsingContext|'s [=event loop=] using the [=user interaction task source=]: - 1. If |browsingContext| has been [=discard|discarded=], then set |isClientEnumerable| to false and abort these steps. - 1. If |client| is a window client and |client|'s [=responsible document=] is not |browsingContext|'s [=active document=], then set |isClientEnumerable| to false and abort these steps. - 1. Set |windowData|["`frameType`"] to the result of running [=Get Frame Type=] with |browsingContext|. - 1. Set |windowData|["`visibilityState`"] to |browsingContext|'s [=active document=]'s {{Document/visibilityState}} attribute value. - 1. Set |windowData|["`focusState`"] to the result of running the [=has focus steps=] with |browsingContext|'s [=active document=] as the argument. - 1. If |client| is a [=window client=], then set |windowData|["`ancestorOriginsList`"] to |browsingContext|'s [=active document=]'s [=relevant global object=]'s {{Location}} object's [=Location/ancestor origins list=]'s associated list. - 1. Wait for |task| to have executed. - - Note: Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken. - - 1. If |isClientEnumerable| is true, then: - 1. Add |windowData| to |matchedWindowData|. - 1. Else if |options|["{{ClientQueryOptions/type}}"] is {{ClientType/"worker"}} or {{ClientType/"all"}} and |client| is a [=dedicated worker client=], or |options|["{{ClientQueryOptions/type}}"] is {{ClientType/"sharedworker"}} or {{ClientType/"all"}} and |client| is a [=shared worker client=], then: - 1. Add |client| to |matchedClients|. - 1. [=Queue a task=] to run the following steps on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=]: - 1. Let |clientObjects| be a new [=list=]. - 1. [=list/For each=] |windowData| in |matchedWindowData|: - 1. Let |windowClient| be the result of running [=Create Window Client=] algorithm with |windowData|["`client`"], |windowData|["`frameType`"], |windowData|["`visibilityState`"], |windowData|["`focusState`"], and |windowData|["`ancestorOriginsList`"] as the arguments. - 1. [=Append=] |windowClient| to |clientObjects|. - 1. [=list/For each=] |client| in |matchedClients|: - 1. Let |clientObject| be the result of running [=Create Client=] algorithm with |client| as the argument. - 1. [=Append=] |clientObject| to |clientObjects|. - 1. Sort |clientObjects| such that: - * {{WindowClient}} objects whose [=WindowClient/browsing context=] has been [=focusing steps|focused=] are placed first, sorted in the most recently [=focusing steps|focused=] order. - * {{WindowClient}} objects whose [=WindowClient/browsing context=] has never been [=focusing steps|focused=] are placed next, sorted in their [=Client/service worker client=]'s creation order. - * {{Client}} objects whose associated [=Client/service worker client=] is a [=worker client=] are placed next, sorted in their [=Client/service worker client=]'s creation order. - - Note: [=Window clients=] are always placed before [=worker clients=]. - - 1. Resolve |promise| with [=create a frozen array|a new frozen array of=] |clientObjects| in |promise|'s [=relevant Realm=]. - 1. Return |promise|. -
- -
-

{{Clients/openWindow(url)}}

- - The openWindow(|url|) method *must* run these steps: - 1. Let |url| be the result of parsing |url| with the context object's relevant settings object's API base URL. - 1. If |url| is failure, return a promise rejected with a TypeError. - 1. If |url| is about:blank, return a promise rejected with a TypeError. - 1. If this algorithm is not triggered by user activation, return a promise rejected with an "{{InvalidAccessError}}" {{DOMException}}. - 1. Let |serviceWorkerEventLoop| be the [=current global object=]'s [=event loop=]. - 1. Let |promise| be a new promise. - 1. Run these substeps in parallel: - 1. Let |newContext| be a new [=top-level browsing context=]. - 1. [=Queue a task=] to run the following steps on |newContext|'s {{Window}} object's [=environment settings object=]'s [=responsible event loop=] using the [=user interaction task source=]: - 1. *HandleNavigate*: [=Navigate=] |newContext| to |url| with [=exceptions enabled flag|exceptions enabled=] and [=replacement enabled=]. - 1. If the algorithm steps invoked in the step labeled *HandleNavigate* [=throws=] an exception, [=queue a task=] to reject |promise| with the exception, on |serviceWorkerEventLoop| using the [=DOM manipulation task source=], and abort these steps. - 1. Let |frameType| be the result of running [=Get Frame Type=] with |newContext|. - 1. Let |visibilityState| be |newContext|'s active document's {{Document/visibilityState}} attribute value. - 1. Let |focusState| be the result of running the has focus steps with |newContext|'s active document as the argument. - 1. Let |ancestorOriginsList| be |newContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. - 1. [=Queue a task=] to run the following steps on |serviceWorkerEventLoop| using the [=DOM manipulation task source=]: - 1. If |newContext|'s {{Window}} object's [=environment settings object=]'s [=creation URL=]'s [=environment settings object/origin=] is not the [=same origin|same=] as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=], resolve |promise| with null and abort these steps. - 1. Let |client| be the result of running [=Create Window Client=] with |newContext|'s {{Window}} object's [=environment settings object=], |frameType|, |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. - 1. Resolve |promise| with |client|. - 1. Return |promise|. -
- -
-

{{Clients/claim()}}

- - The claim() method *must* run these steps: - - 1. If the [=ServiceWorkerGlobalScope/service worker=] is not an active worker, return a promise rejected with an "{{InvalidStateError}}" {{DOMException}}. - 1. Let |promise| be a new promise. - 1. Run the following substeps in parallel: - 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the same as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: - 1. If |client|'s [=environment/execution ready flag=] is unset or |client|'s [=discarded flag=] is set, [=continue=]. - 1. If |client| is not a [=secure context=], [=continue=]. - 1. Let |registration| be the result of running Match Service Worker Registration algorithm passing |client|'s creation URL as the argument. - 1. If |registration| is not the [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration, [=continue=]. - - Note: |registration| will be null if the [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=] is [=service worker registration/unregistered=]. - - 1. If |client|'s active service worker is not the [=ServiceWorkerGlobalScope/service worker=], then: - 1. Invoke Handle Service Worker Client Unload with |client| as the argument. - 1. Set |client|'s active service worker to [=ServiceWorkerGlobalScope/service worker=]. - 1. Invoke Notify Controller Change algorithm with |client| as the argument. - 1. Resolve |promise| with undefined. - 1. Return |promise|. -
-
- -
-

{{ExtendableEvent}}

- -
-      [Exposed=ServiceWorker]
-      interface ExtendableEvent : Event {
-        constructor(DOMString type, optional ExtendableEventInit eventInitDict = {});
-        void waitUntil(Promise<any> f);
-      };
-    
-
-      dictionary ExtendableEventInit : EventInit {
-        // Defined for the forward compatibility across the derived events
-      };
-    
- - An {{ExtendableEvent}} object has an associated extend lifetime promises (an array of promises). It is initially an empty array. - - An {{ExtendableEvent}} object has an associated pending promises count (the number of pending promises in the [=ExtendableEvent/extend lifetime promises=]). It is initially set to zero. - - An {{ExtendableEvent}} object has an associated timed out flag. It is initially unset, and is set after an optional user agent imposed delay if the [=ExtendableEvent/pending promises count=] is greater than zero. - - An {{ExtendableEvent}} object is said to be active when its [=ExtendableEvent/timed out flag=] is unset and either its [=ExtendableEvent/pending promises count=] is greater than zero or its [=dispatch flag=] is set. - - [=/Service workers=] have two lifecycle events, {{install!!event}} and {{activate!!event}}. [=/Service workers=] use the {{ExtendableEvent}} interface for {{activate!!event}} event and {{install!!event}} event. - - Service worker extensions that define event handlers *may* also use or extend the {{ExtendableEvent}} interface. - -
-

{{ExtendableEvent/waitUntil()|event.waitUntil(f)}}

- - Note: {{ExtendableEvent/waitUntil()}} method extends the lifetime of the event. - - waitUntil(|f|) method *must* run these steps: - - 1. Let |event| be the [=context object=]. - 1. [=ExtendableEvent/Add lifetime promise=] |f| to |event|. -
- -
- To add lifetime promise |promise| (a [=promise=]) to |event| (an {{ExtendableEvent}}), run these steps: - - 1. If |event|'s {{Event/isTrusted}} attribute is false, [=throw=] an "{{InvalidStateError}}" {{DOMException}}. - 1. If |event| is not [=ExtendableEvent/active=], [=throw=] an "{{InvalidStateError}}" {{DOMException}}. - - Note: If no lifetime extension promise has been added in the task that called the event handlers, calling {{ExtendableEvent/waitUntil()}} in subsequent asynchronous tasks will throw. - - 1. Add |promise| to |event|'s [=ExtendableEvent/extend lifetime promises=]. - 1. Increment |event|'s [=ExtendableEvent/pending promises count=] by one. - - Note: The [=ExtendableEvent/pending promises count=] is incremented even if the given promise has already been settled. The corresponding count decrement is done in the microtask queued by the reaction to the promise. - - 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |promise|, [=queue a microtask=] to run these substeps: - 1. Decrement |event|'s [=ExtendableEvent/pending promises count=] by one. - 1. If |event|'s [=ExtendableEvent/pending promises count=] is 0, then: - 1. Let |registration| be the [=current global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. - 1. If |registration| is [=service worker registration/unregistered=], invoke [=Try Clear Registration=] with |registration|. - 1. If |registration| is not null, invoke [=Try Activate=] with |registration|. - - The user agent *should not* [=terminate service worker|terminate=] a [=/service worker=] if [=Service Worker Has No Pending Events=] returns false for that [=/service worker=]. -
- - [=/Service workers=] and extensions that define event handlers *may* define their own behaviors, allowing the [=ExtendableEvent/extend lifetime promises=] to suggest operation length, and the rejected state of any of the promise in [=ExtendableEvent/extend lifetime promises=] to suggest operation failure. - - Note: [=/Service workers=] delay treating the [=installing worker=] as "`installed`" until all the [=promises=] in the {{install!!event}} event's [=extend lifetime promises=] resolve successfully. (See the relevant [Install algorithm step](#install-settle-step).) If any of the promises rejects, the installation fails. This is primarily used to ensure that a [=/service worker=] is not considered "`installed`" until all of the core caches it depends on are populated. Likewise, [=/service workers=] delay treating the [=active worker=] as "`activated`" until all the [=promises=] in the {{activate!!event}} event's [=extend lifetime promises=] settle. (See the relevant [Activate algorithm step](#activate-settle-step).) This is primarily used to ensure that any [=functional events=] are not dispatched to the [=/service worker=] until it upgrades database schemas and deletes the outdated cache entries. -
- -
-

{{FetchEvent}}

- -
-      [Exposed=ServiceWorker]
-      interface FetchEvent : ExtendableEvent {
-        constructor(DOMString type, FetchEventInit eventInitDict);
-        [SameObject] readonly attribute Request request;
-        readonly attribute DOMString clientId;
-
-        void respondWith(Promise<Response> r);
-      };
-    
-
-      dictionary FetchEventInit : ExtendableEventInit {
-        required Request request;
-        DOMString clientId = "";
-      };
-    
- - [=/Service workers=] have an essential functional event {{fetch!!event}}. For {{fetch!!event}} event, [=/service workers=] use the {{FetchEvent}} interface which extends the {{ExtendableEvent}} interface. - - Each event using {{FetchEvent}} interface has an associated potential response (a [=/response=]), initially set to null, and the following associated flags that are initially unset: - - * wait to respond flag - * respond-with entered flag - * respond-with error flag - -
-

{{FetchEvent/request|event.request}}

- - request attribute *must* return the value it was initialized to. -
- -
-

{{FetchEvent/clientId|event.clientId}}

- - clientId attribute *must* return the value it was initialized to. When an event is created the attribute *must* be initialized to the empty string. -
- -
-

{{FetchEvent/respondWith(r)|event.respondWith(r)}}

- - Note: Developers can set the argument |r| with either a [=promise=] that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a [=network error=] is returned to [=/Fetch=]. Renderer-side security checks about tainting for cross-origin content are tied to the types of [=filtered responses=] defined in [=/Fetch=]. - - respondWith(|r|) method *must* run these steps: - - 1. Let |event| be the [=context object=]. - 1. If |event|'s [=dispatch flag=] is unset, [=throw=] an "{{InvalidStateError}}" {{DOMException}}. - 1. If |event|'s [=FetchEvent/respond-with entered flag=] is set, [=throw=] an "{{InvalidStateError}}" {{DOMException}}. - 1. [=ExtendableEvent/Add lifetime promise=] |r| to |event|. - - Note: {{FetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called. - - 1. Set |event|'s [=stop propagation flag=] and [=stop immediate propagation flag=]. - 1. Set |event|'s [=FetchEvent/respond-with entered flag=]. - 1. Set |event|'s [=FetchEvent/wait to respond flag=]. - 1. Let |targetRealm| be |event|'s [=relevant Realm=]. - 1. [=Upon rejection=] of |r|: - 1. Set |event|'s [=FetchEvent/respond-with error flag=]. - 1. Unset |event|'s [=FetchEvent/wait to respond flag=]. - 1. [=Upon fulfillment=] of |r| with |response|: - 1. If |response| is not a {{Response}} object, then set the [=FetchEvent/respond-with error flag=]. - - Note: If the [=FetchEvent/respond-with error flag=] is set, a [=network error=] is returned to [=/Fetch=] through [=Handle Fetch=] algorithm. (See the step 21.1.) Otherwise, the value |response| is returned to [=/Fetch=] through [=Handle Fetch=] algorithm. (See the step 22.1.) - - 1. Else: - 1. Let |bytes| be an empty byte sequence. - 1. Let |end-of-body| be false. - 1. Let |done| be false. - 1. Let |potentialResponse| be a copy of |response|'s associated [=Response/response=], except for its [=response/body=]. - 1. If |response|'s [=response/body=] is non-null, run these substeps: - 1. Let |reader| be the result of [=get a reader|getting a reader=] from |response|'s [=response/body=]'s [=stream=]. - 1. Let |highWaterMark| be a non-negative, non-NaN number, chosen by the user agent. - 1. Let |sizeAlgorithm| be an algorithm that accepts a [=chunk=] object and returns a non-negative, non-NaN, non-infinite number, chosen by the user agent. - 1. Let |pull| be an action that runs these subsubsteps: - 1. Let |promise| be the result of [=read a chunk|reading a chunk=] from |response|'s [=response/body=]'s [=stream=] with |reader|. - 1. When |promise| is fulfilled with an object whose `done` property is false and whose `value` property is a `Uint8Array` object, append the bytes represented by the `value` property to |bytes| and perform ! [=DetachArrayBuffer=] with the `ArrayBuffer` object wrapped by the `value` property. - 1. When |promise| is fulfilled with an object whose `done` property is true, set |end-of-body| to true. - 1. When |promise| is fulfilled with a value that matches with neither of the above patterns, or |promise| is rejected, [=ReadableStream/error=] |newStream| with a `TypeError`. - 1. Let |cancel| be an action that [=ReadableStream/cancels=] |response|'s [=response/body=]'s [=stream=] with |reader|. - 1. Let |newStream| be the result of [=ReadableStream/construct a ReadableStream object=] with |highWaterMark|, |sizeAlgorithm|, |pull|, and |cancel| in |targetRealm|. - 1. Set |potentialResponse|'s [=response/body=] to a new [=/body=] whose [=stream=] is |newStream|. - 1. Run these subsubsteps repeatedly [=in parallel=] while |done| is false: - 1. If |newStream| is [=errored=], then set |done| to true. - 1. Otherwise, if |bytes| is empty and |end-of-body| is true, then [=ReadableStream/close=] |newStream| and set |done| to true. - 1. Otherwise, if |bytes| is not empty, run these subsubsubsteps: - 1. Let |chunk| be a subsequence of |bytes| starting from the beginning of |bytes|. - 1. Remove |chunk| from |bytes|. - 1. Let |buffer| be an `ArrayBuffer` object created in |targetRealm| and containing |chunk|. - 1. [=ReadableStream/Enqueue=] a `Uint8Array` object created in |targetRealm| and wrapping |buffer| to |newStream|. - - Note: These substeps are meant to produce the observable equivalent of "piping" |response|'s [=response/body=]'s [=stream=] into |potentialResponse|. - - 1. Set |event|'s [=FetchEvent/potential response=] to |potentialResponse|. - 1. Unset |event|'s [=FetchEvent/wait to respond flag=]. -
-
- -
-

{{ExtendableMessageEvent}}

- -
-      [Exposed=ServiceWorker]
-      interface ExtendableMessageEvent : ExtendableEvent {
-        constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict = {});
-        readonly attribute any data;
-        readonly attribute USVString origin;
-        readonly attribute DOMString lastEventId;
-        [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
-        readonly attribute FrozenArray<MessagePort> ports;
-      };
-    
-
-      dictionary ExtendableMessageEventInit : ExtendableEventInit {
-        any data = null;
-        USVString origin = "";
-        DOMString lastEventId = "";
-        (Client or ServiceWorker or MessagePort)? source = null;
-        sequence<MessagePort> ports = [];
-      };
-    
- - [=/Service workers=] define the extendable {{message!!event}} event to allow extending the lifetime of the event. For the {{message!!event}} event, [=/service workers=] use the {{ExtendableMessageEvent}} interface which extends the {{ExtendableEvent}} interface. - -
-

{{ExtendableMessageEvent/data|event.data}}

- - The data attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to null. It represents the message being sent. -
- -
-

{{ExtendableMessageEvent/origin|event.origin}}

- - The origin attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty string. It represents the [=environment settings object/origin=] of the [=/service worker client=] that sent the message. -
- -
-

{{ExtendableMessageEvent/lastEventId|event.lastEventId}}

- - The lastEventId attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty string. -
- -
-

{{ExtendableMessageEvent/source|event.source}}

- - The source attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to null. It represents the {{Client}} object from which the message is sent. -
- -
-

{{ExtendableMessageEvent/ports|event.ports}}

- - The ports attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty array. It represents the {{MessagePort}} array being sent. -
-
- -
-

Events

- - The following events, called [=service worker events=], are dispatched on {{ServiceWorkerGlobalScope}} object: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event nameInterfaceCategoryDispatched when…
install{{ExtendableEvent}}[=Lifecycle Event|Lifecycle=]The [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration's installing worker changes. (See step 11.2 of the Install algorithm.)
activate{{ExtendableEvent}}[=Lifecycle Event|Lifecycle=]The [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration's active worker changes. (See step 12.2 of the Activate algorithm.)
fetch{{FetchEvent}}[=Functional event|Functional=]The [=/http fetch=] invokes Handle Fetch with |request|. As a result of performing Handle Fetch, the [=ServiceWorkerGlobalScope/service worker=] returns a [=/response=] to the [=/http fetch=]. The [=/response=], represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{WindowOrWorkerGlobalScope/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
pushPushEvent[=Functional event|Functional=](See Firing a push event.)
notificationclickNotificationEvent[=Functional event|Functional=](See Activating a notification.)
notificationcloseNotificationEvent[=Functional event|Functional=](See Closing a notification.)
syncSyncEvent[=Functional event|Functional=](See Firing a sync event.)
canmakepaymentCanMakePaymentEvent[=Functional event|Functional=](See Handling a CanMakePaymentEvent.)
paymentrequestPaymentRequestEvent[=Functional event|Functional=](See Handling a PaymentRequestEvent.)
message{{ExtendableMessageEvent}}LegacyWhen it receives a message.
messageerror{{MessageEvent}}LegacyWhen it was sent a message that cannot be deserialized.
-
-
- - -
-

Caches

- - To allow authors to fully manage their content caches for offline use, the {{Window}} and the {{WorkerGlobalScope}} provide the asynchronous caching methods that open and manipulate {{Cache}} objects. An [=environment settings object/origin=] can have multiple, named {{Cache}} objects, whose contents are entirely under the control of scripts. Caches are not shared across [=/origins=], and they are completely isolated from the browser's HTTP cache. - -
-

Constructs

- - A request response list is a [=list=] of [=pairs=] consisting of a request (a [=/request=]) and a response (a [=/response=]). - - The relevant request response list is the instance that the [=context object=] represents. - - A name to cache map is an ordered map whose [=map/entry=] consists of a [=map/key=] (a string that represents the name of a [=request response list=]) and a [=map/value=] (a [=request response list=]). - - Each [=/origin=] has an associated [=name to cache map=]. - - The relevant name to cache map is the instance of the [=context object=]'s associated [=CacheStorage/global object=]'s [=environment settings object=]'s [=environment settings object/origin=]. -
- -
-

Understanding Cache Lifetimes

- - The {{Cache}} instances are not part of the browser's HTTP cache. The {{Cache}} objects are exactly what authors have to manage themselves. The {{Cache}} objects do not get updated unless authors explicitly request them to be. The {{Cache}} objects do not expire unless authors delete the entries. The {{Cache}} objects do not disappear just because the [=/service worker=] script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the [=/service worker=] that can safely operate on. -
- -
-

{{WindowOrWorkerGlobalScope/caches|self.caches}}

- -
-      partial interface WindowOrWorkerGlobalScope {
-        [SecureContext, SameObject] readonly attribute CacheStorage caches;
-      };
-    
- -
-

{{WindowOrWorkerGlobalScope/caches}}

- - caches attribute *must* return this object's associated {{CacheStorage}} object. -
-
- -
-

{{Cache}}

- -
-      [SecureContext, Exposed=(Window,Worker)]
-      interface Cache {
-        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options = {});
-        [NewObject] Promise<FrozenArray<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options = {});
-        [NewObject] Promise<void> add(RequestInfo request);
-        [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
-        [NewObject] Promise<void> put(RequestInfo request, Response response);
-        [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options = {});
-        [NewObject] Promise<FrozenArray<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options = {});
-      };
-    
-
-      dictionary CacheQueryOptions {
-        boolean ignoreSearch = false;
-        boolean ignoreMethod = false;
-        boolean ignoreVary = false;
-      };
-    
- - A {{Cache}} object represents a [=request response list=]. Multiple separate objects implementing the {{Cache}} interface across documents and workers can all be associated with the same [=request response list=] simultaneously. - - A cache batch operation is a [=struct=] that consists of: - * A type ("`delete`" or "`put`"). - * A request (a [=/request=]). - * A response (a [=/response=]). - * An options (a {{CacheQueryOptions}}). - -
-

{{Cache/match(request, options)}}

- - match(|request|, |options|) method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Run these substeps [=in parallel=]: - 1. Let |p| be the result of running the algorithm specified in {{Cache/matchAll(request, options)}} method with |request| and |options|. - 1. Wait until |p| settles. - 1. If |p| rejects with an exception, then: - 1. Reject |promise| with that exception. - 1. Else if |p| resolves with an array, |responses|, then: - 1. If |responses| is an empty array, then: - 1. Resolve |promise| with undefined. - 1. Else: - 1. Resolve |promise| with the first element of |responses|. - 1. Return |promise|. -
- -
-

{{Cache/matchAll(request, options)}}

- - matchAll(|request|, |options|) method *must* run these steps: - - 1. Let |r| be null. - 1. If the optional argument |request| is not omitted, then: - 1. If |request| is a {{Request}} object, then: - 1. Set |r| to |request|'s [=Request/request=]. - 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, return [=a promise resolved with=] an empty array. - 1. Else if |request| is a string, then: - 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this [=throws=] an exception, return [=a promise rejected with=] that exception. - 1. Let |realm| be the [=context object=]'s [=relevant realm=]. - 1. Let |promise| be [=a new promise=]. - 1. Run these substeps [=in parallel=]: - 1. Let |responses| be an empty [=list=]. - 1. If the optional argument |request| is omitted, then: - 1. [=list/For each=] |requestResponse| of the [=relevant request response list=]: - 1. Add a copy of |requestResponse|'s response to |responses|. - 1. Else: - 1. Let |requestResponses| be the result of running [=Query Cache=] with |r| and |options|. - 1. [=list/For each=] |requestResponse| of |requestResponses|: - 1. Add a copy of |requestResponse|'s response to |responses|. - 1. [=Queue a task=], on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to perform the following steps: - 1. Let |responseList| be a [=list=]. - 1. [=list/For each=] |response| of |responses|: - 1. Add a new {{Response}} object associated with |response| and a new {{Headers}} object whose guard is "immutable" to |responseList|. - 1. Resolve |promise| with a [=frozen array type|frozen array=] [=create a frozen array|created=] from |responseList|, in |realm|. - 1. Return |promise|. -
- -
-

{{Cache/add(request)}}

- - add(|request|) method *must* run these steps: - - 1. Let |requests| be an array containing only |request|. - 1. Let |responseArrayPromise| be the result of running the algorithm specified in {{Cache/addAll(requests)}} passing |requests| as the argument. - 1. Return the result of [=promise/reacting=] to |responseArrayPromise| with a fulfillment handler that returns undefined. -
- -
-

{{Cache/addAll(requests)}}

- - addAll(|requests|) method *must* run these steps: - - 1. Let |responsePromises| be an empty [=list=]. - 1. Let |requestList| be an empty [=list=]. - 1. For each |request| whose type is {{Request}} in |requests|: - 1. Let |r| be |request|'s [=Request/request=]. - 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "`http`" and "`https`", or |r|'s [=request/method=] is not \``GET`\`, return [=a promise rejected with=] a `TypeError`. - 1. For each |request| in |requests|: - 1. Let |r| be the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return [=a promise rejected with=] that exception. - 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", then: - 1. [=fetch/Terminate=] all the ongoing [=fetches=] initiated by |requests| with the aborted flag set. - 1. Return [=a promise rejected with=] a `TypeError`. - 1. If |r|'s [=request/client=]'s [=environment settings object/global object=] is a {{ServiceWorkerGlobalScope}} object, set |request|'s [=service-workers mode=] to "`foreign`". - 1. Set |r|'s [=request/initiator=] to "`fetch`" and [=request/destination=] to "`subresource`". - 1. Add |r| to |requestList|. - 1. Let |responsePromise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - * [=/Fetch=] |r|. - * To [=process response=] for |response|, run these substeps: - 1. If |response|'s [=response/type=] is "error", or |response|'s [=response/status=] is not an [=ok status=] or is `206`, reject |responsePromise| with a `TypeError`. - 1. Else if |response|'s [=response/header list=] contains a [=header=] [=header/named=] \``Vary`\`, then: - 1. Let |fieldValues| be the [=list=] containing the elements corresponding to the [=http/field-values=] of the [=Vary=] header. - 1. [=list/For each=] |fieldValue| of |fieldValues|: - 1. If |fieldValue| matches "`*`", then: - 1. Reject |responsePromise| with a `TypeError`. - 1. [=fetch/Terminate=] all the ongoing [=fetches=] initiated by |requests| with the aborted flag set. - 1. Abort these steps. - - * To [=process response end-of-body=] for |response|, run these substeps: - 1. If |response|'s [=response/aborted flag=] is set, reject |responsePromise| with an "{{AbortError}}" {{DOMException}} and abort these steps. - 1. Resolve |responsePromise| with |response|. - - Note: The cache commit is allowed when the response's body is fully received. - - 1. Add |responsePromise| to |responsePromises|. - 1. Let |p| be the result of [=getting a promise to wait for all=] of |responsePromises|. - 1. Return the result of [=promise/reacting=] to |p| with a fulfillment handler that, when called with argument |responses|, performs the following substeps: - 1. Let |operations| be an empty [=list=]. - 1. Let |index| be zero. - 1. For each |response| in |responses|: - 1. Let |operation| be a [=cache batch operation=]. - 1. Set |operation|'s [=cache batch operation/type=] to "`put`". - 1. Set |operation|'s [=cache batch operation/request=] to |requestList|[|index|]. - 1. Set |operation|'s [=cache batch operation/response=] to |response|. - 1. [=list/Append=] |operation| to |operations|. - 1. Increment |index| by one. - 1. Let |realm| be the [=context object=]'s [=relevant realm=]. - 1. Let |cacheJobPromise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. Let |errorData| be null. - 1. Invoke [=Batch Cache Operations=] with |operations|. If this [=throws=] an exception, set |errorData| to the exception. - 1. [=Queue a task=], on |cacheJobPromise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to perform the following substeps: - 1. If |errorData| is null, resolve |cacheJobPromise| with undefined. - 1. Else, reject |cacheJobPromise| with a [=exception/create|new=] [=exception=] with |errorData| and a user agent-defined [=exception/message=], in |realm|. - 1. Return |cacheJobPromise|. -
- -
-

{{Cache/put(request, response)}}

- - put(|request|, |response|) method *must* run these steps: - - 1. Let |r| be null. - 1. If |request| is a {{Request}} object, then: - 1. Set |r| to |request|'s [=Request/request=]. - 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "`http`" and "`https`", or |r|'s [=request/method=] is not \`GET\`, return [=a promise rejected with=] a `TypeError`. - 1. Else if |request| is a string, then: - 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this [=throws=] an exception, return [=a promise rejected with=] that exception. - 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "`http`" and "`https`", return [=a promise rejected with=] a `TypeError`. - 1. If |response|'s associated [=Response/response=]'s [=response/status=] is `206`, return [=a promise rejected with=] a `TypeError`. - 1. If |response|'s associated [=Response/response=]'s [=response/header list=] contains a header [=header/named=] \`Vary\`, then: - 1. Let |fieldValues| be the [=list=] containing the [=list/items=] corresponding to the [=Vary=] header's [=http/field-values=]. - 1. [=list/For each=] |fieldValue| in |fieldValues|: - 1. If |fieldValue| matches "`*`", return [=a promise rejected with=] a `TypeError`. - 1. If |response| is [=Body/disturbed=] or [=Body/locked=], return [=a promise rejected with=] a `TypeError`. - 1. Let |clonedResponse| be the result of [=response/clone|cloning=] |response|'s associated [=Response/response=]. - 1. If |response|'s body is non-null, run these substeps: - 1. Let |dummyStream| be an [=empty=] {{ReadableStream}} object. - 1. Set |response|'s [=response/body=] to a new [=/body=] whose [=stream=] is |dummyStream|. - 1. Let |reader| be the result of [=get a reader|getting a reader=] from |dummyStream|. - 1. [=Read all bytes=] from |dummyStream| with |reader|. - 1. Let |operations| be an empty [=list=]. - 1. Let |operation| be a [=cache batch operation=]. - 1. Set |operation|'s [=cache batch operation/type=] to "`put`". - 1. Set |operation|'s [=cache batch operation/request=] to |r|. - 1. Set |operation|'s [=cache batch operation/response=] to |clonedResponse|. - 1. [=list/Append=] |operation| to |operations|. - 1. Let |realm| be the [=context object=]'s [=relevant realm=]. - 1. Let |cacheJobPromise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. Let |errorData| be null. - 1. Invoke [=Batch Cache Operations=] with |operations|. If this [=throws=] an exception, set |errorData| to the exception. - 1. [=Queue a task=], on |cacheJobPromise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to perform the following substeps: - 1. If |errorData| is null, resolve |cacheJobPromise| with undefined. - 1. Else, reject |cacheJobPromise| with a [=exception/create|new=] [=exception=] with |errorData| and a user agent-defined [=exception/message=], in |realm|. - 1. Return |cacheJobPromise|. -
- -
-

{{Cache/delete(request, options)}}

- - delete(|request|, |options|) method *must* run these steps: - - 1. Let |r| be null. - 1. If |request| is a {{Request}} object, then: - 1. Set |r| to |request|'s [=Request/request=]. - 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, return [=a promise resolved with=] false. - 1. Else if |request| is a string, then: - 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this [=throws=] an exception, return [=a promise rejected with=] that exception. - 1. Let |operations| be an empty [=list=]. - 1. Let |operation| be a [=cache batch operation=]. - 1. Set |operation|'s [=cache batch operation/type=] to "`delete`". - 1. Set |operation|'s [=cache batch operation/request=] to |r|. - 1. Set |operation|'s [=cache batch operation/options=] to |options|. - 1. [=list/Append=] |operation| to |operations|. - 1. Let |realm| be the [=context object=]'s [=relevant realm=]. - 1. Let |cacheJobPromise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. Let |errorData| be null. - 1. Let |requestResponses| be the result of running [=Batch Cache Operations=] with |operations|. If this [=throws=] an exception, set |errorData| to the exception. - 1. [=Queue a task=], on |cacheJobPromise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to perform the following substeps: - 1. If |errorData| is null, then: - 1. If |requestResponses| [=list/is not empty=], resolve |cacheJobPromise| with true. - 1. Else, resolve |cacheJobPromise| with false. - 1. Else, reject |cacheJobPromise| with a [=exception/create|new=] [=exception=] with |errorData| and a user agent-defined [=exception/message=], in |realm|. - 1. Return |cacheJobPromise|. -
- -
-

{{Cache/keys(request, options)}}

- - keys(|request|, |options|) method *must* run these steps: - - 1. Let |r| be null. - 1. If the optional argument |request| is not omitted, then: - 1. If |request| is a {{Request}} object, then: - 1. Set |r| to |request|'s [=Request/request=]. - 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, return [=a promise resolved with=] an empty array. - 1. Else if |request| is a string, then: - 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this [=throws=] an exception, return [=a promise rejected with=] that exception. - 1. Let |realm| be the [=context object=]'s [=relevant realm=]. - 1. Let |promise| be [=a new promise=]. - 1. Run these substeps [=in parallel=]: - 1. Let |requests| be an empty [=list=]. - 1. If the optional argument |request| is omitted, then: - 1. [=list/For each=] |requestResponse| of the [=relevant request response list=]: - 1. Add |requestResponse|'s request to |requests|. - 1. Else: - 1. Let |requestResponses| be the result of running [=Query Cache=] with |r| and |options|. - 1. [=list/For each=] |requestResponse| of |requestResponses|: - 1. Add |requestResponse|'s request to |requests|. - 1. [=Queue a task=], on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to perform the following steps: - 1. Let |requestList| be a [=list=]. - 1. [=list/For each=] |request| of |requests|: - 1. Add a new {{Request}} object associated with |request| and a new associated {{Headers}} object whose [=guard=] is "`immutable`" to |requestList|. - 1. Resolve |promise| with a [=frozen array type|frozen array=] [=create a frozen array|created=] from |requestList|, in |realm|. - 1. Return |promise|. -
-
- -
-

{{CacheStorage}}

- -
-      [SecureContext, Exposed=(Window,Worker)]
-      interface CacheStorage {
-        [NewObject] Promise<any> match(RequestInfo request, optional MultiCacheQueryOptions options = {});
-        [NewObject] Promise<boolean> has(DOMString cacheName);
-        [NewObject] Promise<Cache> open(DOMString cacheName);
-        [NewObject] Promise<boolean> delete(DOMString cacheName);
-        [NewObject] Promise<sequence<DOMString>> keys();
-      };
-
-      dictionary MultiCacheQueryOptions : CacheQueryOptions {
-        DOMString cacheName;
-      };
-    
- - - Note: {{CacheStorage}} interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39. - - The user agent *must* create a {{CacheStorage}} object when a {{Window}} object or a {{WorkerGlobalScope}} object is created and associate it with that global object. - - A {{CacheStorage}} object represents a name to cache map of its associated [=CacheStorage/global object=]'s environment settings object's [=environment settings object/origin=]. Multiple separate objects implementing the {{CacheStorage}} interface across documents and workers can all be associated with the same name to cache map simultaneously. - -
-

{{CacheStorage/match(request, options)}}

- - match(|request|, |options|) method *must* run these steps: - - 1. If |options|.{{MultiCacheQueryOptions/cacheName}} is [=present=], then: - 1. Return [=a new promise=] |promise| and run the following substeps [=in parallel=]: - 1. [=map/For each=] |cacheName| → |cache| of the [=relevant name to cache map=]: - 1. If |options|.{{MultiCacheQueryOptions/cacheName}} matches |cacheName|, then: - 1. Resolve |promise| with the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with |request| and |options| (providing |cache| as thisArgument to the `[[Call]]` internal method of {{Cache/match(request, options)}}.) - 1. Abort these steps. - 1. Resolve |promise| with undefined. - 1. Else: - 1. Let |promise| be [=a promise resolved with=] undefined. - 1. [=map/For each=] cacheName → |cache| of the [=relevant name to cache map=]: - 1. Set |promise| to the result of [=promise/reacting=] to itself with a fulfillment handler that, when called with argument |response|, performs the following substeps: - 1. If |response| is not undefined, return |response|. - 1. Return the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with |request| and |options| as the arguments (providing |cache| as thisArgument to the `[[Call]]` internal method of {{Cache/match(request, options)}}.) - 1. Return |promise|. -
- -
-

{{CacheStorage/has(cacheName)}}

- - has(|cacheName|) method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. [=map/For each=] |key| → value of the [=relevant name to cache map=]: - 1. If |cacheName| matches |key|, resolve |promise| with true and abort these steps. - 1. Resolve |promise| with false. - 1. Return |promise|. -
- -
-

{{CacheStorage/open(cacheName)}}

- - open(|cacheName|) method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. [=map/For each=] |key| → |value| of the [=relevant name to cache map=]: - 1. If |cacheName| matches |key|, then: - 1. Resolve |promise| with a new {{Cache}} object that represents |value|. - 1. Abort these steps. - 1. Let |cache| be a new [=request response list=]. - 1. [=map/Set=] the [=relevant name to cache map=][|cacheName|] to |cache|. If this cache write operation failed due to exceeding the granted quota limit, reject |promise| with a "{{QuotaExceededError}}" {{DOMException}} and abort these steps. - 1. Resolve |promise| with a new {{Cache}} object that represents |cache|. - 1. Return |promise|. -
- -
-

{{CacheStorage/delete(cacheName)}}

- - delete(|cacheName|) method *must* run these steps: - - 1. Let |promise| be the result of running the algorithm specified in {{CacheStorage/has(cacheName)}} method with |cacheName|. - 1. Return the result of [=promise/reacting=] to |promise| with a fulfillment handler that, when called with argument |cacheExists|, performs the following substeps: - 1. If |cacheExists| is false, then: - 1. Return false. - 1. Let |cacheJobPromise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. [=map/Remove=] the [=relevant name to cache map=][|cacheName|]. - 1. Resolve |cacheJobPromise| with true. - - Note: After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional. - - 1. Return |cacheJobPromise|. -
- -
-

{{CacheStorage/keys()}}

- - keys() method *must* run these steps: - - 1. Let |promise| be [=a new promise=]. - 1. Run the following substeps [=in parallel=]: - 1. Let |cacheKeys| be the result of [=map/get the keys|getting the keys=] of the [=relevant name to cache map=]. - - Note: The [=list/items=] in the result [=ordered set=] are in the order that their corresponding entry was added to the [=name to cache map=]. - - 1. Resolve |promise| with |cacheKeys|. - 1. Return |promise|. -
-
-
- -
-

Security Considerations

- -
-

Secure Context

- - [=/Service workers=] *must* execute in secure contexts. [=/Service worker clients=] *must* also be secure contexts to register a [=/service worker registration=], to get access to the [=/service worker registrations=] and the [=/service workers=], to do messaging with the [=/service workers=], and to be manipulated by the [=/service workers=]. - - Note: This effectively means that [=/service workers=] and their [=/service worker clients=] need to be hosted over HTTPS. A user agent can allow localhost (see the requirements), 127.0.0.0/8, and ::1/128 for development purposes. The primary reason for this restriction is to protect users from the risks associated with insecure contexts. -
- -
-

Content Security Policy

- - Whenever a user agent invokes the [=Run Service Worker=] algorithm with a [=/service worker=] |serviceWorker|: - - * If |serviceWorker|'s script resource was delivered with a Content-Security-Policy HTTP header containing the value |policy|, the user agent *must* enforce |policy| for |serviceWorker|. - * If |serviceWorker|'s script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value |policy|, the user agent *must* monitor |policy| for |serviceWorker|. - - The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS). -
- -
-

Origin Relativity

- -
-

Origin restriction

- - *This section is non-normative.* - - A [=/service worker=] executes in the registering [=/service worker client=]'s [=environment settings object/origin=]. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other [=/origins=]. Therefore, [=/service workers=] cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that [=/service workers=] create the opportunity for a bad actor to turn a bad day into a bad eternity. -
- -
-

{{WorkerGlobalScope/importScripts(urls)}}

- - When the importScripts(|urls|) method is called on a {{ServiceWorkerGlobalScope}} object, the user agent *must* import scripts into worker global scope, given this {{ServiceWorkerGlobalScope}} object and |urls|, and with the following steps to [=fetching scripts/perform the fetch=] given the [=/request=] |request|: - - 1. Let |serviceWorker| be |request|'s [=request/client=]'s [=environment settings object/global object=]'s [=ServiceWorkerGlobalScope/service worker=]. - 1. If |serviceWorker|'s [=script resource map=][|request|'s [=request/url=]] [=map/exists=], return the [=map/entry=]'s [=map/value=]. - 1. If |serviceWorker|'s [=state=] is not "`parsed`" or "`installing`" return a [=network error=]. - 1. Let |registration| be |serviceWorker|'s [=containing service worker registration=]. - 1. Set |request|'s [=service-workers mode=] to "`none`". - 1. Set |request|'s [=request/cache mode=] to "`no-cache`" if any of the following are true: - * |registration|'s [=service worker registration/update via cache mode=] is "`none`". - * The [=current global object=]'s [=force bypass cache for import scripts flag=] is set. - * |registration| is [=stale=]. - 1. Let |response| be the result of [=fetch|fetching=] |request|. - 1. Set |response| to |response|'s [=unsafe response=]. - 1. If |response|’s [=response/cache state=] is not "`local`", set |registration|’s [=service worker registration/last update check time=] to the current time. - 1. [=Extract a MIME type=] from the |response|'s [=response/header list=]. If this MIME type (ignoring parameters) is not a [=JavaScript MIME type=], return a [=network error=]. - 1. If |response|'s [=response/type=] is not "`error`", and |response|'s [=response/status=] is an ok status, then: - 1. [=map/Set=] |serviceWorker|'s [=script resource map=][|request|'s [=request/url=]] to |response|. - 1. Set |serviceWorker|'s [=classic scripts imported flag=]. - 1. Return |response|. -
-
- -
-

Cross-Origin Resources and CORS

- - *This section is non-normative.* - - Applications tend to cache items that come from a CDN or other [=environment settings object/origin=]. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to [=/fetch=] many sorts of off-[=environment settings object/origin=] resources when appropriate CORS headers are set. - [=/Service workers=] enable this by allowing {{Cache|Caches}} to [=/fetch=] and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding [=Response/responses=] are basic filtered response, the objects stored are {{Response}} objects whose corresponding [=Response/responses=] are either CORS filtered responses or opaque filtered responses. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding [=Response/responses=] are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases. -
- -
-

Path restriction

- - *This section is non-normative.* - - In addition to the [[#origin-restriction|origin restriction]], service workers are restricted by the [=url/path=] of the service worker script. For example, a service worker script at https://www.example.com/~bob/sw.js can be registered for the [=service worker registration/scope url=] https://www.example.com/~bob/ but not for the scope https://www.example.com/ or https://www.example.com/~alice/. This provides some protection for sites that host multiple-user content in separated directories on the same origin. However, the path restriction is not considered a hard security boundary, as only origins are. Sites are encouraged to use different origins to securely isolate segments of the site if appropriate. - - Servers can remove the path restriction by setting a [=Service-Worker-Allowed=] header on the service worker script. -
- -
-

Service worker script request

- - *This section is non-normative.* - - To further defend against malicious registration of a service worker on a site, this specification requires that: - * The [=Service-Worker=] header is present on service worker script requests, and - * Service worker scripts are served with a [=JavaScript MIME type=]. -
- -
-

Implementer Concerns

- - *This section is non-normative.* - - The implementers are encouraged to note: - - * Plug-ins should not load via [=/service workers=]. As plug-ins may get their security origins from their own urls, the embedding [=/service worker=] cannot handle it. For this reason, the Handle Fetch algorithm makes <embed> and <object> requests immediately fallback to the network without dispatching {{fetch!!event}} event. - * Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with [=/service workers=]. -
- -
-

Privacy

- - [=/Service workers=] introduce new persistent storage features including scope to registration map (for [=/service worker registrations=] and their [=/service workers=]), [=request response list=] and name to cache map (for caches), and [=script resource map=] (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages *should* be cleared when users intend to clear them and *should* maintain and interoperate with existing user controls e.g. purging all existing persistent storages. -
-
- -
-

Extensibility

- - Service Workers specification is extensible from other specifications. - -
-

Define API bound to Service Worker Registration

- - Specifications *may* define an API tied to a [=/service worker registration=] by using partial interface definition to the {{ServiceWorkerRegistration}} interface where it *may* define the specification specific attributes and methods: - -
-      partial interface ServiceWorkerRegistration {
-        // e.g. define an API namespace
-        readonly attribute APISpaceType APISpace;
-        // e.g. define a method
-        Promise<T> methodName(/* list of arguments */);
-      };
-    
-
- -
-

Define Functional Event

- - Specifications *may* define a functional event by extending {{ExtendableEvent}} interface: - -
-      // e.g. define FunctionalEvent interface
-      interface FunctionalEvent : ExtendableEvent {
-        // add a functional event's own attributes and methods
-      };
-    
-
- -
-

Define Event Handler

- - Specifications *may* define an event handler attribute for the corresponding functional event using partial interface definition to the {{ServiceWorkerGlobalScope}} interface: - -
-      partial interface ServiceWorkerGlobalScope {
-        attribute EventHandler onfunctionalevent;
-      };
-    
-
- -
-

Firing Functional Events

- - To request a [=functional event=] dispatch to the [=service worker registration/active worker=] of a [=/service worker registration=], specifications *should* invoke [=Fire Functional Event=]. -
-
- -
-

Appendix A: Algorithms

- - The following definitions are the user agent's internal data structures used throughout the specification. - - A scope to registration map is an ordered map where the keys are [=service worker registration/scope urls=], [=URL serializer|serialized=], and the values are [=/service worker registrations=]. - - A job is an abstraction of one of register, update, and unregister request for a [=/service worker registration=]. - -
- A job has a job type, which is one of *register*, *update*, and *unregister*. - - A job has a scope url (a [=/URL=]). - - A job has a script url (a [=/URL=]). - - A job has a worker type ("classic" or "module"). - - A job has an update via cache mode, which is "`imports`", "`all`", or "`none`". - - A job has a client (a [=/service worker client=]). It is initially null. - - A job has a job promise (a promise). It is initially null. - - A [=job=] has a containing job queue (a [=job queue=] or null). It is initially null. - - A job has a list of equivalent jobs (a list of jobs). It is initially the empty list. - - A [=job=] has a force bypass cache flag. It is initially unset. -
- - - Two jobs are equivalent when their job type is the same and: - - * For *register* and *update* jobs, both their [=job/scope url=] and the [=job/script url=] are the same. - * For *unregister* jobs, their [=job/scope url=] is the same. - - A job queue is a thread safe [=queue=] used to synchronize the set of concurrent [=jobs=]. The [=job queue=] contains [=jobs=] as its [=queue/items=]. A [=job queue=] is initially empty. - - A scope to job queue map is an ordered map where the keys are [=service worker registration/scope urls=], [=URL serializer|serialized=], and the values are [=job queues=]. - -
-

Create Job

- - : Input - :: |jobType|, a job type - :: |scopeURL|, a [=/URL=] - :: |scriptURL|, a [=/URL=] - :: |promise|, a promise - :: |client|, a [=/service worker client=] - : Output - :: |job|, a job - - 1. Let |job| be a new job. - 1. Set |job|'s [=job/job type=] to |jobType|. - 1. Set |job|'s [=job/scope url=] to |scopeURL|. - 1. Set |job|'s [=job/script url=] to |scriptURL|. - 1. Set |job|'s [=job/job promise=] to |promise|. - 1. Set |job|'s [=job/client=] to |client|. - 1. Return |job|. -
- -
-

Schedule Job

- - : Input - :: |job|, a job - : Output - :: none - - 1. Let |jobQueue| be null. - 1. Let |jobScope| be |job|'s [=job/scope url=], [=URL serializer|serialized=]. - 1. If [=scope to job queue map=][|jobScope|] does not [=map/exist=], [=map/set=] [=scope to job queue map=][|jobScope|] to a new [=job queue=]. - 1. Set |jobQueue| to [=scope to job queue map=][|jobScope|]. - 1. If |jobQueue| is empty, then: - 1. Set |job|'s [=containing job queue=] to |jobQueue|, and [=queue/enqueue=] |job| to |jobQueue|. - 1. Invoke [=Run Job=] with |jobQueue|. - 1. Else: - 1. Let |lastJob| be the element at the back of |jobQueue|. - 1. If |job| is [=equivalent=] to |lastJob| and |lastJob|'s [=job/job promise=] has not settled, append |job| to |lastJob|'s [=list of equivalent jobs=]. - 1. Else, set |job|'s [=containing job queue=] to |jobQueue|, and [=queue/enqueue=] |job| to |jobQueue|. -
- -
-

Run Job

- - : Input - :: jobQueue, a [=job queue=] - : Output - :: none - - 1. Assert: |jobQueue| [=queue/is not empty=]. - 1. [=Queue a task=] to run these steps: - 1. Let |job| be the first [=queue/item=] in |jobQueue|. - 1. If |job|'s [=job type=] is *register*, run [=Register=] with |job| [=in parallel=]. - 1. Else if |job|'s [=job type=] is *update*, run [=Update=] with |job| [=in parallel=]. - - Note: For a register job and an update job, the user agent delays queuing a task for running the job until after a {{Document/DOMContentLoaded}} event has been dispatched to the document that initiated the job. - - 1. Else if |job|'s [=job type=] is *unregister*, run [=Unregister=] with |job| [=in parallel=]. -
- -
-

Finish Job

- - : Input - :: |job|, a [=job=] - : Output - :: none - - 1. Let |jobQueue| be |job|'s [=containing job queue=]. - 1. Assert: the first [=queue/item=] in |jobQueue| is |job|. - 1. [=Dequeue=] from |jobQueue|. - 1. If |jobQueue| [=queue/is not empty=], invoke [=Run Job=] with |jobQueue|. -
- -
-

Resolve Job Promise

- - : Input - :: |job|, a [=job=] - :: |value|, any - : Output - :: none - - 1. If |job|'s [=job/client=] is not null, [=queue a task=], on |job|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to run the following substeps: - 1. Let |convertedValue| be null. - 1. If |job|'s [=job/job type=] is either *register* or *update*, set |convertedValue| to the result of [=getting the service worker registration object=] that represents |value| in |job|'s [=job/client=]. - 1. Else, set |convertedValue| to |value|, in |job|'s [=job/client=]'s [=environment settings object/Realm=]. - 1. Resolve |job|'s [=job/job promise=] with |convertedValue|. - 1. For each |equivalentJob| in |job|'s list of equivalent jobs: - 1. If |equivalentJob|'s [=job/client=] is null, continue to the next iteration of the loop. - 1. [=Queue a task=], on |equivalentJob|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to run the following substeps: - 1. Let |convertedValue| be null. - 1. If |equivalentJob|'s [=job/job type=] is either *register* or *update*, set |convertedValue| to the result of [=getting the service worker registration object=] that represents |value| in |equivalentJob|'s [=job/client=]. - 1. Else, set |convertedValue| to |value|, in |equivalentJob|'s [=job/client=]'s [=environment settings object/Realm=]. - 1. Resolve |equivalentJob|'s [=job/job promise=] with |convertedValue|. -
- -
-

Reject Job Promise

- - : Input - :: |job|, a [=job=] - :: |errorData|, the information necessary to [=exception/create|create an exception=] - : Output - :: none - - 1. If |job|'s [=job/client=] is not null, [=queue a task=], on |job|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to reject |job|'s [=job/job promise=] with a [=exception/create|new=] [=exception=] with |errorData| and a user agent-defined [=exception/message=], in |job|'s [=job/client=]'s [=environment settings object/Realm=]. - 1. For each |equivalentJob| in |job|'s [=list of equivalent jobs=]: - 1. If |equivalentJob|'s [=job/client=] is null, [=iteration/continue=]. - 1. [=Queue a task=], on |equivalentJob|'s [=job/client=]'s [=responsible event loop=] using the [=DOM manipulation task source=], to reject |equivalentJob|'s [=job/job promise=] with a [=exception/create|new=] [=exception=] with |errorData| and a user agent-defined [=exception/message=], in |equivalentJob|'s [=job/client=]'s [=environment settings object/Realm=]. -
- -
-

Register

- - : Input - :: |job|, a job - : Output - :: none - - 1. If the result of running potentially trustworthy origin with the [=environment settings object/origin=] of |job|'s [=job/script url=] as the argument is Not Trusted, then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Invoke Finish Job with |job| and abort these steps. - 1. If the [=environment settings object/origin=] of |job|'s [=job/script url=] is not |job|'s [=job/client=]'s [=environment settings object/origin=], then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Invoke Finish Job with |job| and abort these steps. - 1. If the [=environment settings object/origin=] of |job|'s [=job/scope url=] is not |job|'s [=job/client=]'s [=environment settings object/origin=], then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Invoke Finish Job with |job| and abort these steps. - 1. Let |registration| be the result of running the Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. - 1. If |registration| is not null, then: - 1. Let |newestWorker| be the result of running the Get Newest Worker algorithm passing |registration| as the argument. - 1. If |newestWorker| is not null, |job|'s [=job/script url=] [=url/equals=] |newestWorker|'s [=service worker/script url=], and |job|'s [=job/update via cache mode=]'s value equals |registration|'s [=service worker registration/update via cache mode=]'s value, then: - 1. Invoke [=Resolve Job Promise=] with |job| and |registration|. - 1. Invoke Finish Job with |job| and abort these steps. - 1. Else: - 1. Invoke Set Registration algorithm with |job|'s [=job/scope url=] and |job|'s [=job/update via cache mode=]. - 1. Invoke Update algorithm passing |job| as the argument. -
- -
-

Update

- - : Input - :: |job|, a job - : Output - :: none - - 1. Let |registration| be the result of running the Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. - 1. If |registration| is null, then: - 1. Invoke [=Reject Job Promise=] with |job| and `TypeError`. - 1. Invoke Finish Job with |job| and abort these steps. - 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as the argument. - 1. If |job|'s job type is *update*, and |newestWorker|'s [=service worker/script url=] does not [=url/equal=] |job|'s [=job/script url=], then: - 1. Invoke [=Reject Job Promise=] with |job| and `TypeError`. - 1. Invoke Finish Job with |job| and abort these steps. - 1. Let |httpsState| be "none". - 1. Let |referrerPolicy| be the empty string. - 1. Let |hasUpdatedResources| be false. - 1. Let |updatedResourceMap| be an [=ordered map=] where the [=map/keys=] are [=/URLs=] and the [=map/values=] are [=/responses=]. - 1. Switching on |job|'s worker type, run these substeps with the following options: - - : "classic" - :: Fetch a classic worker script given |job|’s serialized [=job/script url=], |job|’s [=job/client=], "serviceworker", and the to-be-created environment settings object for this service worker. - : "module" - :: Fetch a module worker script graph given |job|’s serialized [=job/script url=], |job|’s [=job/client=], "serviceworker", "omit", and the to-be-created environment settings object for this service worker. - -
-

Note: This step has two known issues.

-

First, using the to-be-created [=environment settings object=] rather than a concrete [=environment settings object=]. This is used due to the unique processing model of service workers compared to the processing model of other [=web workers=]. The script fetching algorithms of HTML standard originally designed for other [=web workers=] require an [=environment settings object=] of the execution environment, but service workers fetch a script separately in the [=Update=] algorithm before the script later runs multiple times through the [=Run Service Worker=] algorithm.

-

Second, the [=fetch a classic worker script=] algorithm and the [=fetch a module worker script graph=] algorithm in HTML take |job|’s [=job/client=] as an argument. |job|’s [=job/client=] is null when passed from the [=Soft Update=] algorithm.

-

These issues are tracked in the [issue #1013](https://github.com/w3c/ServiceWorker/issues/1013) of the Service Workers GitHub repository. We will address these issues in [Service Workers Nightly](https://w3c.github.io/ServiceWorker/).

-
- - To [=fetching scripts/perform the fetch=] given |request|, run the following steps: - - 1. Append \`Service-Worker\`/\`script\` to |request|'s [=request/header list=]. - - Note: See the definition of the Service-Worker header in Appendix B: Extended HTTP headers. - - 1. Set |request|'s [=request/cache mode=] to "no-cache" if any of the following are true: - * |registration|'s [=service worker registration/update via cache mode=] is not "`all`". - * |job|'s [=force bypass cache flag=] is set. - * |newestWorker| is not null and |registration| is [=stale=]. - - Note: Even if the cache mode is not set to "no-cache", the user agent obeys Cache-Control header's max-age value in the network layer to determine if it should bypass the browser cache. - - 1. Set |request|'s [=service-workers mode=] to "`none`". - 1. If the [=fetching scripts/is top-level=] flag is unset, then return the result of [=/fetching=] |request|. - 1. Set |request|'s [=request/redirect mode=] to "error". - 1. [=/Fetch=] |request|, and asynchronously wait to run the remaining steps as part of fetch's process response for the [=/response=] |response|. - 1. [=Extract a MIME type=] from the |response|'s [=response/header list=]. If this MIME type (ignoring parameters) is not a [=JavaScript MIME type=], then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Asynchronously complete these steps with a [=network error=]. - 1. Let |serviceWorkerAllowed| be the result of [=extracting header list values=] given \`Service-Worker-Allowed\` and |response|'s [=response/header list=]. - - Note: See the definition of the [=Service-Worker-Allowed=] header in Appendix B: Extended HTTP headers. - - 1. Set |httpsState| to |response|'s [=response/HTTPS state=]. - 1. Set |referrerPolicy| to the result of parse a referrer policy from a Referrer-Policy header of |response|. - 1. If |serviceWorkerAllowed| is failure, then: - 1. Asynchronously complete these steps with a network error. - 1. Let |scopeURL| be |registration|'s [=service worker registration/scope url=]. - 1. Let |maxScopeString| be null. - 1. If |serviceWorkerAllowed| is null, then: - 1. Let |resolvedScope| be the result of [=URL parser|parsing=] "`./`" using |job|'s [=job/script url=] as the [=base URL=]. - 1. Set |maxScopeString| to "`/`", followed by the strings in |resolvedScope|'s [=url/path=] (including empty strings), separated from each other by "`/`". - - Note: The final item in |resolvedScope|'s [=url/path=] will always be an empty string, so |maxScopeString| will have a trailing "`/`". - - 1. Else: - 1. Let |maxScope| be the result of [=URL parser|parsing=] |serviceWorkerAllowed| using |job|'s [=job/script url=] as the [=base URL=]. - 1. If |maxScope|'s [=url/origin=] is |job|'s [=job/script url=]'s [=url/origin=], then: - 1. Set |maxScopeString| to "`/`", followed by the strings in |maxScope|'s [=url/path=] (including empty strings), separated from each other by "`/`". - 1. Let |scopeString| be "`/`", followed by the strings in |scopeURL|'s [=url/path=] (including empty strings), separated from each other by "`/`". - 1. If |maxScopeString| is null or |scopeString| does not start with |maxScopeString|, then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Asynchronously complete these steps with a network error. - 1. Set |updatedResourceMap|[|request|'s [=request/url=]] to |response|. - 1. If |response|'s [=response/cache state=] is not "`local`", set |registration|'s last update check time to the current time. - 1. If |newestWorker| is null, or |newestWorker|'s [=script resource map=][|request|'s [=request/url=]]'s [=response/body=] is not byte-for-byte identical with |response|'s [=response/body=], set |hasUpdatedResources| to true. - 1. Else if |newestWorker|'s [=classic scripts imported flag=] is set, then: - 1. [=map/For each=] |url| → |storedResponse| of |newestWorker|'s [=script resource map=]: - 1. Let |request| be a new [=/request=] whose [=request/url=] is |url|, [=request/client=] is |job|'s [=job/client=], [=request/destination=] is "`script`", [=request/parser metadata=] is "`not parser-inserted`", [=request/synchronous flag=] is set, and whose [=request/use-URL-credentials flag=] is set. - 1. Set |request|'s [=request/cache mode=] to "`no-cache`" if any of the following are true: - * |registration|'s [=service worker registration/update via cache mode=] is "`none`". - * |job|'s [=force bypass cache flag=] is set. - * |registration| is [=stale=]. - 1. Let |fetchedResponse| be the result of [=fetch|fetching=] |request|. - 1. Set |fetchedResponse| to |fetchedResponse|'s [=unsafe response=]. - 1. Set |updatedResourceMap|[|request|'s [=request/url=]] to |fetchedResponse|. - 1. If |fetchedResponse|'s [=response/cache state=] is not "`local`", set |registration|’s [=last update check time=] to the current time. - 1. [=Extract a MIME type=] from the |fetchedResponse|'s [=response/header list=]. If this MIME type (ignoring parameters) is not a [=JavaScript MIME type=], asynchronously complete these steps with a [=network error=]. - 1. If |fetchedResponse|'s [=response/type=] is "`error`", or |fetchedResponse|'s [=response/status=] is not an [=ok status=], asynchronously complete these steps with a [=network error=]. - 1. If |fetchedResponse|'s [=response/body=] is not byte-for-byte identical with |storedResponse|'s [=response/body=], set |hasUpdatedResources| to true. - - Note: The control does not break the loop in this step to continue with all the imported scripts to populate the cache. - 1. Return true. - - If the algorithm asynchronously completes with null, then: - - 1. Invoke [=Reject Job Promise=] with |job| and `TypeError`. - - Note: This will do nothing if [=Reject Job Promise=] was previously invoked with "{{SecurityError}}" {{DOMException}}. - - 1. If |newestWorker| is null, then [=map/remove=] [=scope to registration map=][|scopeURL|, [=URL serializer|serialized=]]. - 1. Invoke Finish Job with |job| and abort these steps. - - Else, continue the rest of these steps after the algorithm's asynchronous completion, with |script| being the asynchronous completion value. - 1. If |hasUpdatedResources| is false, then: - 1. Invoke [=Resolve Job Promise=] with |job| and |registration|. - 1. Invoke [=Finish Job=] with |job| and abort these steps. - 1. Let |worker| be a new [=/service worker=]. - 1. Set |worker|'s [=service worker/script url=] to |job|'s [=job/script url=], |worker|'s script resource to |script|, and |worker|'s [=service worker/type=] to |job|'s worker type. - 1. [=map/For each=] |url| → |response| of |updatedResourceMap|: - 1. Set |worker|'s [=script resource map=][|url|] to |response|. - 1. Set |worker|'s script resource's HTTPS state to |httpsState|. - 1. Set |worker|'s script resource's [=script resource/referrer policy=] to |referrerPolicy|. - 1. Let |forceBypassCache| be true if |job|'s [=job/force bypass cache flag=] is set, and false otherwise. - 1. Let |runResult| be the result of running the [=Run Service Worker=] algorithm with |worker| and |forceBypassCache|. - 1. If |runResult| is *failure* or an [=abrupt completion=], then: - 1. Invoke [=Reject Job Promise=] with |job| and `TypeError`. - 1. If |newestWorker| is null, then [=map/remove=] [=scope to registration map=][|registration|'s [=service worker registration/scope url=], [[=URL serializer|serialized=]]. - 1. Invoke [=Finish Job=] with |job|. - 1. Else, invoke [=Install=] algorithm with |job|, |worker|, and |registration| as its arguments. -
- -
-

Soft Update

- - The user agent *may* call this as often as it likes to check for updates. - - : Input - :: |registration|, a [=/service worker registration=] - :: |forceBypassCache|, an optional boolean, false by default - - Note: Implementers may use |forceBypassCache| to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs. - - : Output - :: None - - 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. - 1. If |newestWorker| is null, abort these steps. - 1. Let |job| be the result of running Create Job with *update*, |registration|'s [=service worker registration/scope url=], |newestWorker|'s [=service worker/script url=], null, and null. - 1. Set |job|'s worker type to |newestWorker|'s [=service worker/type=]. - 1. Set |job|'s [=force bypass cache flag=] if |forceBypassCache| is true. - 1. Invoke Schedule Job with |job|. -
- -
-

Install

- - : Input - :: |job|, a job - :: |worker|, a [=/service worker=] - :: |registration|, a [=/service worker registration=] - : Output - :: none - - 1. Let |installFailed| be false. - 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. - 1. Run the Update Registration State algorithm passing |registration|, "installing" and |worker| as the arguments. - 1. Run the Update Worker State algorithm passing |registration|'s installing worker and "`installing`" as the arguments. - 1. Assert: |job|'s [=job/job promise=] is not null. - 1. Invoke [=Resolve Job Promise=] with |job| and |registration|. - 1. Let |settingsObjects| be all [=environment settings objects=] whose [=environment settings object/origin=] is |registration|'s [=service worker registration/scope url=]'s [=url/origin=]. - 1. For each |settingsObject| of |settingsObjects|, [=queue a task=] on |settingsObject|'s [=responsible event loop=] in the [=DOM manipulation task source=] to run the following steps: - 1. Let |registrationObjects| be every {{ServiceWorkerRegistration}} object in |settingsObject|'s [=environment settings object/realm=], whose [=ServiceWorkerRegistration/service worker registration=] is |registration|. - 1. For each |registrationObject| of |registrationObjects|, [=fire an event=] on |registrationObject| named `updatefound`. - 1. Let |installingWorker| be |registration|'s installing worker. - 1. If the result of running the [=Should Skip Event=] algorithm with |installingWorker| and "install" is false, then: - 1. Let |forceBypassCache| be true if |job|'s [=job/force bypass cache flag=] is set, and false otherwise. - 1. If the result of running the [=Run Service Worker=] algorithm with |installingWorker| and |forceBypassCache| is *failure*, then: - 1. Set |installFailed| to true. - 1. Else: - 1. [=Queue a task=] |task| on |installingWorker|'s [=event loop=] using the [=DOM manipulation task source=] to run the following steps: - 1. Let |e| be the result of creating an event with {{ExtendableEvent}}. - 1. Initialize |e|’s {{Event/type}} attribute to {{install!!event}}. - 1. Dispatch |e| at |installingWorker|'s [=service worker/global object=]. - 1. *WaitForAsynchronousExtensions*: Run the following substeps in parallel: - 1. Wait until |e| is not [=ExtendableEvent/active=]. - 1. If |e|'s [=ExtendableEvent/timed out flag=] is set, set |installFailed| to true. - 1. Let |p| be the result of [=getting a promise to wait for all=] of |e|'s [=extend lifetime promises=]. - 1. [=Upon rejection=] of |p|, set |installFailed| to true. - - If |task| is discarded, set |installFailed| to true. - - 1. Wait for |task| to have executed or been discarded. - 1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete. - 1. If |installFailed| is true, then: - 1. Run the Update Worker State algorithm passing |registration|'s [=installing worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. - 1. If |newestWorker| is null, then [=map/remove=] [=scope to registration map=][|registration|'s [=service worker registration/scope url=], [[=URL serializer|serialized=]]. - 1. Invoke Finish Job with |job| and abort these steps. - 1. If |registration|'s waiting worker is not null, then: - 1. [=Terminate Service Worker|Terminate=] |registration|'s [=waiting worker=]. - 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=waiting worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "waiting" and |registration|'s installing worker as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. - 1. Run the Update Worker State algorithm passing |registration|'s waiting worker and "`installed`" as the arguments. - 1. Invoke Finish Job with |job|. - 1. Wait for all the tasks queued by Update Worker State invoked in this algorithm to have executed. - 1. Invoke [=Try Activate=] with |registration|. - - Note: If [=Try Activate=] does not trigger [=Activate=] here, [=Activate=] is tried again when the last client controlled by the existing [=active worker=] is [=Handle Service Worker Client Unload|unloaded=], {{ServiceWorkerGlobalScope/skipWaiting()}} is asynchronously called, or the [=extend lifetime promises=] for the existing [=active worker=] settle. -
- -
-

Activate

- - : Input - :: |registration|, a [=/service worker registration=] - : Output - :: None - - 1. If |registration|'s waiting worker is null, abort these steps. - 1. If |registration|'s [=active worker=] is not null, then: - 1. [=Terminate Service Worker|Terminate=] |registration|'s [=active worker=]. - 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=active worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "active" and |registration|'s waiting worker as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. - 1. Run the Update Worker State algorithm passing |registration|'s active worker and "`activating`" as the arguments. - - Note: Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated. - - Note: Make sure to design activation handlers to do non-essential work (like cleanup). This is because activation handlers may not all run to completion, especially in the case of browser termination during activation. A Service Worker should be designed to function properly, even if the activation handlers do not all complete successfully. - - 1. Let |matchedClients| be a [=list=] of [=/service worker clients=] whose creation URL matches |registration|'s [=service worker registration/scope url=]. - 1. [=list/For each=] |client| of |matchedClients|, [=queue a task=] on |client|'s [=responsible event loop=], using the [=DOM manipulation task source=], to run the following substeps: - 1. Let |readyPromise| be |client|'s [=environment settings object/global object=]'s {{ServiceWorkerContainer}} object's [=ServiceWorkerContainer/ready promise=]. - 1. If |readyPromise| is null, then [=continue=]. - 1. If |readyPromise| is pending, resolve |readyPromise| with the the result of [=getting the service worker registration object=] that represents |registration| in |readyPromise|'s [=relevant settings object=]. - 1. [=list/For each=] |client| of |matchedClients|: - 1. If |client| is a window client, unassociate |client|'s responsible document from its application cache, if it has one. - 1. Else if |client| is a shared worker client, unassociate |client|'s [=environment settings object/global object=] from its application cache, if it has one. - - Note: Resources will now use the service worker registration instead of the existing application cache. - - 1. For each [=/service worker client=] |client| who is using |registration|: - 1. Set |client|'s active worker to |registration|'s active worker. - 1. Invoke Notify Controller Change algorithm with |client| as the argument. - 1. Let |activeWorker| be |registration|'s active worker. - 1. If the result of running the [=Should Skip Event=] algorithm with |activeWorker| and "activate" is false, then: - 1. If the result of running the [=Run Service Worker=] algorithm with |activeWorker| is not *failure*, then: - 1. [=Queue a task=] |task| on |activeWorker|'s [=event loop=] using the [=DOM manipulation task source=] to run the following steps: - 1. Let |e| be the result of creating an event with {{ExtendableEvent}}. - 1. Initialize |e|’s {{Event/type}} attribute to {{activate!!event}}. - 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. - 1. *WaitForAsynchronousExtensions*: Wait, [=in parallel=], until |e| is not [=ExtendableEvent/active=]. - 1. Wait for |task| to have executed or been discarded. - 1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete. - 1. Run the Update Worker State algorithm passing |registration|'s active worker and "`activated`" as the arguments. -
- -
-

Try Activate

- - : Input - :: |registration|, a [=/service worker registration=] - : Output - :: None - - 1. If |registration|'s [=waiting worker=] is null, return. - 1. If |registration|'s [=active worker=] is not null and |registration|'s [=active worker=]'s [=state=] is "`activating`", return. - - Note: If the existing active worker is still in activating state, the activation of the waiting worker is delayed. - - 1. Invoke [=Activate=] with |registration| if either of the following is true: - * |registration|'s [=active worker=] is null. - * The result of running [=Service Worker Has No Pending Events=] with |registration|’s [=active worker=] is true, and no [=/service worker client=] is [=using=] |registration| or |registration|’s [=waiting worker=]'s [=skip waiting flag=] is set. -
- -
-

Run Service Worker

- - : Input - :: |serviceWorker|, a [=/service worker=] - :: |forceBypassCache|, an optional boolean, false by default - : Output - :: a [=Completion=] or *failure* - - Note: This algorithm blocks until the service worker is [=running=] or fails to start. - - 1. If |serviceWorker| is [=running=], then return |serviceWorker|'s [=start status=]. - 1. If |serviceWorker|'s [=state=] is "`redundant`", then return *failure*. - 1. Assert: |serviceWorker|'s [=start status=] is null. - 1. Let |script| be |serviceWorker|'s [=service worker/script resource=]. - 1. Assert: |script| is not null. - 1. Let |startFailed| be false. - 1. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the following steps in that context: - 1. Call the JavaScript [=InitializeHostDefinedRealm|InitializeHostDefinedRealm()=] abstract operation with the following customizations: - * For the global object, create a new {{ServiceWorkerGlobalScope}} object. Let |workerGlobalScope| be the created object. - * Let |realmExecutionContext| be the created [=execution context|JavaScript execution context=]. - 1. Set |serviceWorker|'s [=service worker/global object=] to |workerGlobalScope|. - 1. Let |workerEventLoop| be a newly created event loop. - 1. Let |settingsObject| be a new environment settings object whose algorithms are defined as follows: - - : The [=environment settings object/realm execution context=] - :: Return |realmExecutionContext|. - : The [=environment settings object/global object=] - :: Return |workerGlobalScope|. - : The responsible event loop - :: Return |workerEventLoop|. - : The [=environment settings object/referrer policy=] - :: Return |workerGlobalScope|'s [=WorkerGlobalScope/referrer policy=]. - : The API URL character encoding - :: Return UTF-8. - : The API base URL - :: Return |serviceWorker|'s [=service worker/script url=]. - : The [=environment settings object/origin=] - :: Return its registering [=/service worker client=]'s [=environment settings object/origin=]. - : The creation URL - :: Return |workerGlobalScope|'s [=WorkerGlobalScope/url=]. - : The [=environment settings object/HTTPS state=] - :: Return |workerGlobalScope|'s [=WorkerGlobalScope/HTTPS state=]. - - 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/url=] to |serviceWorker|'s [=service worker/script url=]. - 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/HTTPS state=] to |serviceWorker|'s script resource's HTTPS state. - 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/referrer policy=] to |serviceWorker|'s script resource's [=script resource/referrer policy=]. - 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/type=] to |serviceWorker|'s [=service worker/type=]. - 1. Set |workerGlobalScope|'s [=ServiceWorkerGlobalScope/force bypass cache for import scripts flag=] if |forceBypassCache| is true. - 1. Create a new {{WorkerLocation}} object and associate it with |workerGlobalScope|. - 1. If |serviceWorker| is an active worker, and there are any tasks queued in |serviceWorker|'s containing service worker registration's [=service worker registration/task queues=], queue them to |serviceWorker|'s event loop's [=/task queues=] in the same order using their original task sources. - 1. Let |evaluationStatus| be the result of running the classic script |script| if |script| is a classic script, otherwise, the result of running the module script |script| if |script| is a [=module script=]. - 1. If |evaluationStatus|.\[[Value]] is empty, this means the script was not evaluated. Set |startFailed| to true and abort these steps. - 1. If the script was aborted by the [=Terminate Service Worker=] algorithm, set |startFailed| to true and abort these steps. - 1. Set |serviceWorker|'s [=start status=] to |evaluationStatus|. - 1. If |script|'s has ever been evaluated flag is unset, then: - 1. For each |eventType| of |settingsObject|'s [=environment settings object/global object=]'s associated list of event listeners' event types: - 1. [=set/Append=] |eventType| to |workerGlobalScope|'s associated [=ServiceWorkerGlobalScope/service worker=]'s set of event types to handle. - - Note: If the global object's associated list of event listeners does not have any event listener added at this moment, the service worker's set of event types to handle remains an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script. - - 1. Set |script|'s has ever been evaluated flag. - 1. Run the responsible event loop specified by |settingsObject| until it is destroyed. - 1. Empty |workerGlobalScope|'s list of active timers. - 1. Wait for |serviceWorker| to be [=running=], or for |startFailed| to be true. - 1. If |startFailed| is true, then return *failure*. - 1. Return |serviceWorker|'s [=start status=]. -
- -
-

Terminate Service Worker

- - : Input - :: |serviceWorker|, a [=/service worker=] - : Output - :: None - - 1. Run the following steps [=in parallel=] with |serviceWorker|'s main loop: - 1. Let |serviceWorkerGlobalScope| be |serviceWorker|'s [=service worker/global object=]. - 1. Set |serviceWorkerGlobalScope|'s [=WorkerGlobalScope/closing=] flag to true. - 1. [=set/Remove=] all the [=list/items=] from |serviceWorker|'s [=set of extended events=]. - 1. If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in |serviceWorkerGlobalScope|'s event loop's [=/task queues=], queue them to |serviceWorker|'s containing service worker registration's corresponding [=service worker registration/task queues=] in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from |serviceWorkerGlobalScope|'s event loop's [=/task queues=] without processing them. - - Note: This effectively means that the fetch events and the other functional events such as push events are backed up by the registration's task queues while the other tasks including message events are discarded. - - 1. [=Abort a running script|Abort the script=] currently running in |serviceWorker|. - 1. Set |serviceWorker|'s [=start status=] to null. -
- -
-

Handle Fetch

- - The [=Handle Fetch=] algorithm is the entry point for the [=/fetch=] handling handed to the [=/service worker=] context. - - : Input - :: |request|, a [=/request=] - : Output - :: |response|, a [=/response=] - - 1. Let |handleFetchFailed| be false. - 1. Let |respondWithEntered| be false. - 1. Let |eventCanceled| be false. - 1. Let |response| be null. - 1. Let |registration| be null. - 1. Let |client| be |request|'s [=request/client=]. - 1. Let |reservedClient| be |request|'s [=request/reserved client=]. - 1. Assert: |request|'s [=request/destination=] is not "serviceworker". - 1. If |request|'s [=request/destination=] is either "embed" or "object", then: - 1. Return null. - 1. Else if |request| is a non-subresource request, then: - - Note: If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration. - - 1. If |reservedClient| is not null and is an environment settings object, then: - 1. If |reservedClient| is not a secure context, return null. - 1. Else: - 1. If |request|'s [=request/url=] is not a potentially trustworthy URL, return null. - 1. If |request| is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null. - 1. Set |registration| to the result of running Match Service Worker Registration algorithm passing |request|'s [=request/url=] as the argument. - 1. If |registration| is null or |registration|'s active worker is null, return null. - 1. If |request|'s [=request/destination=] is not {{RequestDestination/"report"}}, set |reservedClient|'s active service worker to |registration|'s active worker. - - Note: From this point, the [=/service worker client=] starts to use its active service worker's containing service worker registration. - - 1. Else if |request| is a subresource request, then: - 1. If |client|'s active service worker is non-null, set |registration| to |client|'s active service worker's containing service worker registration. - 1. Else, return null. - 1. Let |activeWorker| be |registration|'s active worker. - 1. Let |shouldSoftUpdate| be true if any of the following are true, and false otherwise: - * |request| is a [=non-subresource request=]. - * |request| is a [=subresource request=] and |registration| is [=stale=]. - 1. If the result of running the [=Should Skip Event=] algorithm with "fetch" and |activeWorker| is true, then: - 1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|. - 1. Return null. - 1. If |activeWorker|'s state is "`activating`", wait for |activeWorker|'s state to become "`activated`". - 1. If the result of running the [=Run Service Worker=] algorithm with |activeWorker| is *failure*, then set |handleFetchFailed| to true. - 1. Else [=queue a task=] |task| to run the following substeps: - 1. Let |e| be the result of creating an event with {{FetchEvent}}. - 1. Initialize |e|’s {{Event/type}} attribute to {{fetch!!event}}. - 1. Initialize |e|’s {{Event/cancelable}} attribute to true. - 1. Initialize |e|’s {{FetchEvent/request}} attribute to a new {{Request}} object associated with |request| and a new associated {{Headers}} object whose [=guard=] is "`immutable`". - 1. If |request| is a non-subresource request and |request|'s [=request/destination=] is not {{RequestDestination/"report"}}, initialize |e|'s {{FetchEvent/clientId}} attribute to the empty string, and to |client|'s [=environment/id=] otherwise. - 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. - 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |e|. - 1. If |e|'s [=FetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true. - 1. If |e|'s [=FetchEvent/wait to respond flag=] is set, then: - 1. Wait until |e|'s [=FetchEvent/wait to respond flag=] is unset. - 1. If |e|'s [=FetchEvent/respond-with error flag=] is set, set |handleFetchFailed| to true. - 1. Else, set |response| to |e|'s [=FetchEvent/potential response=]. - 1. If |e|'s canceled flag is set, set |eventCanceled| to true. - - If |task| is discarded, set |handleFetchFailed| to true. - - The |task| *must* use |activeWorker|'s event loop and the handle fetch task source. - - 1. Wait for |task| to have executed or for |handleFetchFailed| to be true. - 1. If |shouldSoftUpdate| is true, then [=in parallel=] run the [=Soft Update=] algorithm with |registration|. - 1. If |respondWithEntered| is false, then return a [=network error=] if |eventCanceled| is true and null otherwise. - 1. If |handleFetchFailed| is true, then return a [=network error=]. - 1. Return |response|. -
- -
-

Should Skip Event

- : Input - :: |eventName|, a string - :: |serviceWorker|, a [=/service worker=] - : Output - :: a boolean - - Note: To avoid unnecessary delays, this specification permits skipping event dispatch when no event listeners for the event have been deterministically added in the service worker's global during the very first script execution. - - 1. If |serviceWorker|'s [=set of event types to handle=] does not [=set/contain=] |eventName|, then the user agent *may* return true. - 1. Return false. -
- -
-

Fire Functional Event

- - : Input - :: |eventName|, a string - :: |eventConstructor|, an event constructor that extends {{ExtendableEvent}} - :: |registration|, a [=/service worker registration=] - :: |initialization|, optional property initialization for |event|, constructed from |eventConstructor| - :: |postDispatchSteps|, optional steps to run on the [=service worker registration/active worker=]'s event loop, with |dispatchedEvent| set to the instance of |eventConstructor| that was [=dispatched=]. - : Output - :: None - - 1. Assert: |registration|'s [=active worker=] is not null. - 1. Let |activeWorker| be |registration|'s [=active worker=]. - 1. If the result of running [=Should Skip Event=] with |eventName| and |activeWorker| is true, then: - 1. If |registration| is [=stale=], then [=in parallel=] run the [=Soft Update=] algorithm with |registration|. - 2. Return. - 1. If |activeWorker|'s [=state=] is "`activating`", wait for |activeWorker|'s [=state=] to become "`activated`". - 1. If the result of running the [=Run Service Worker=] algorithm with |activeWorker| is *failure*, then: - 1. If |registration| is [=stale=], then [=in parallel=] run the [=Soft Update=] algorithm with |registration|. - 2. Return. - 1. [=Queue a task=] |task| to run these substeps: - 1. Let |event| be the result of [=creating an event=] with |eventConstructor| and the [=relevant realm=] of |activeWorker|'s [=service worker/global object=]. - 1. If |initialization| is not null, then initialize |event| with |initialization|. - 1. [=Dispatch=] |event| on |activeWorker|'s [=service worker/global object=]. - 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |event|. - 1. If |postDispatchSteps| is not null, then run |postDispatchSteps| passing |event| as |dispatchedEvent|. - - The |task| *must* use |activeWorker|'s [=event loop=] and the [=handle functional event task source=]. - - 1. Wait for |task| to have executed or been discarded. - 1. If |registration| is [=stale=], then [=in parallel=] run the [=Soft Update=] algorithm with |registration|. - -
- To fire an "`amazingthing`" event (which is of type `AmazingThingEvent`) on a particular |serviceWorkerRegistration|, and initialize the event object's properties, the prose would be: - - 1. [=Fire Functional Event=] "`amazingthing`" using `AmazingThingEvent` on |serviceWorkerRegistration| with the following properties: - : propertyName - :: value - : anotherPropertyName - :: anotherValue - - Then run the following steps with |dispatchedEvent|: - - 1. Do whatever you need to with |dispatchedEvent| on the service worker's event loop. - - Note that the initialization steps and post-dispatch steps are optional. If they aren't needed, the prose would be: - - 1. [=Fire Functional Event=] "`whatever`" using {{ExtendableEvent}} on |serviceWorkerRegistration|. -
-
- -
-

Handle Service Worker Client Unload

- - The user agent *must* run these steps when a [=/service worker client=] unloads by unloading or terminating. - - : Input - :: |client|, a [=/service worker client=] - : Output - :: None - - 1. Run the following steps atomically. - 1. Let |registration| be the [=/service worker registration=] used by |client|. - 1. If |registration| is null, abort these steps. - 1. If any other [=/service worker client=] is using |registration|, abort these steps. - 1. If |registration| is [=service worker registration/unregistered=], invoke [=Try Clear Registration=] with |registration|. - 1. Invoke [=Try Activate=] with |registration|. -
- -
-

Handle User Agent Shutdown

- - : Input - :: None - : Output - :: None - - 1. [=map/For each=] scope → |registration| of scope to registration map: - 1. If |registration|'s installing worker |installingWorker| is not null, then: - 1. If |registration|'s [=waiting worker=] is null and |registration|'s [=active worker=] is null, invoke Clear Registration with |registration| and continue to the next iteration of the loop. - 1. Else, set |installingWorker| to null. - 1. If |registration|'s waiting worker is not null, run the following substep in parallel: - 1. Invoke Activate with |registration|. -
- -
-

Update Service Worker Extended Events Set

- - : Input - :: |worker|, a [=/service worker=] - :: |event|, an [=event=] - : Output - :: None - - 1. Assert: |event|'s [=dispatch flag=] is unset. - 1. For each |item| of |worker|'s [=set of extended events=]: - 1. If |item| is not [=ExtendableEvent/active=], [=set/remove=] |item| from |worker|'s [=set of extended events=]. - 1. If |event| is [=ExtendableEvent/active=], [=set/append=] |event| to |worker|'s [=set of extended events=]. -
- -
-

Unregister

- - : Input - :: |job|, a job - : Output - :: none - - 1. If the [=environment settings object/origin=] of |job|'s [=job/scope url=] is not |job|'s [=job/client=]'s [=environment settings object/origin=], then: - 1. Invoke [=Reject Job Promise=] with |job| and "{{SecurityError}}" {{DOMException}}. - 1. Invoke Finish Job with |job| and abort these steps. - 1. Let |registration| be the result of running Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. - 1. If |registration| is null, then: - 1. Invoke Resolve Job Promise with |job| and false. - 1. Invoke Finish Job with |job| and abort these steps. - 1. [=map/Remove=] [=scope to registration map=][|job|'s [=job/scope url=]]. - 1. Invoke Resolve Job Promise with |job| and true. - 1. Invoke [=Try Clear Registration=] with |registration|. - - Note: If [=Try Clear Registration=] does not trigger [=Clear Registration=] here, [=Clear Registration=] is tried again when the last client [=using=] the registration is [=Handle Service Worker Client Unload|unloaded=] or the [=extend lifetime promises=] for the registration's service workers settle. - - 1. Invoke Finish Job with |job|. -
- -
-

Set Registration

- - : Input - :: |scope|, a [=/URL=] - :: |updateViaCache|, an [=service worker registration/update via cache mode=] - : Output - :: |registration|, a [=/service worker registration=] - - 1. Run the following steps atomically. - 1. Let |scopeString| be [=URL serializer|serialized=] |scope| with the *exclude fragment flag* set. - 1. Let |registration| be a new [=/service worker registration=] whose [=service worker registration/scope url=] is set to |scope| and [=service worker registration/update via cache mode=] is set to |updateViaCache|. - 1. [=map/Set=] scope to registration map[|scopeString|] to |registration|. - 1. Return |registration|. -
- -
-

Clear Registration

- - : Input - :: |registration|, a [=/service worker registration=] - : Output - :: None - - 1. Run the following steps atomically. - 1. If |registration|'s installing worker is not null, then: - 1. [=Terminate Service Worker|Terminate=] |registration|'s [=installing worker=]. - 1. Run the Update Worker State algorithm passing |registration|'s [=installing worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. - 1. If |registration|'s waiting worker is not null, then: - 1. [=Terminate Service Worker|Terminate=] |registration|'s [=waiting worker=]. - 1. Run the Update Worker State algorithm passing |registration|'s [=waiting worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. - 1. If |registration|'s active worker is not null, then: - 1. [=Terminate Service Worker|Terminate=] |registration|'s [=active worker=]. - 1. Run the Update Worker State algorithm passing |registration|'s [=active worker=] and "`redundant`" as the arguments. - 1. Run the Update Registration State algorithm passing |registration|, "active" and null as the arguments. -
- -
-

Try Clear Registration

- - : Input - :: |registration|, a [=/service worker registration=] - : Output - :: None - - 1. Invoke [=Clear Registration=] with |registration| if no [=/service worker client=] is [=using=] |registration| and all of the following conditions are true: - * |registration|'s [=installing worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=installing worker=] is true. - * |registration|'s [=waiting worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=waiting worker=] is true. - * |registration|'s [=active worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=active worker=] is true. -
- -
-

Update Registration State

- - : Input - :: |registration|, a [=/service worker registration=] - :: |target|, a string (one of "`installing`", "`waiting`", and "`active`") - :: |source|, a [=/service worker=] or null - : Output - :: None - - 1. Let |registrationObjects| be an array containing all the {{ServiceWorkerRegistration}} objects associated with |registration|. - 1. If |target| is "`installing`", then: - 1. Set |registration|'s [=installing worker=] to |source|. - 1. For each |registrationObject| in |registrationObjects|: - 1. [=Queue a task=] to set the {{ServiceWorkerRegistration/installing}} attribute of |registrationObject| to null if |registration|’s [=installing worker=] is null, or the result of [=getting the service worker object=] that represents |registration|’s [=installing worker=] in |registrationObject|'s [=relevant settings object=]. - 1. Else if |target| is "`waiting`", then: - 1. Set |registration|'s [=waiting worker=] to |source|. - 1. For each |registrationObject| in |registrationObjects|: - 1. [=Queue a task=] to set the {{ServiceWorkerRegistration/waiting}} attribute of |registrationObject| to null if |registration|’s [=waiting worker=] is null, or the result of [=getting the service worker object=] that represents |registration|’s [=waiting worker=] in |registrationObject|'s [=relevant settings object=]. - 1. Else if |target| is "`active`", then: - 1. Set |registration|'s [=service worker registration/active worker=] to |source|. - 1. For each |registrationObject| in |registrationObjects|: - 1. [=Queue a task=] to set the {{ServiceWorkerRegistration/active}} attribute of |registrationObject| to null if |registration|’s [=active worker=] is null, or the result of [=getting the service worker object=] that represents |registration|’s [=active worker=] in |registrationObject|'s [=relevant settings object=]. - - The [=task=] *must* use |registrationObject|'s [=relevant settings object=]'s [=responsible event loop=] and the [=DOM manipulation task source=]. -
- -
-

Update Worker State

- - : Input - :: |worker|, a [=/service worker=] - :: |state|, a [=/service worker=] [=service worker/state=] - : Output - :: None - - 1. Set |worker|'s [=service worker/state=] to |state|. - 1. Let |settingsObjects| be all [=environment settings objects=] whose [=environment settings object/origin=] is |worker|'s [=service worker/script url=]'s [=url/origin=]. - 1. For each |settingsObject| of |settingsObjects|, [=queue a task=] on |settingsObject|'s [=responsible event loop=] in the [=DOM manipulation task source=] to run the following steps: - 1. Let |objectMap| be |settingsObject|'s [=environment settings object/service worker object map=]. - 1. If |objectMap|[|worker|] does not [=map/exist=], then abort these steps. - 1. Let |workerObj| be |objectMap|[|worker|]. - 1. Set |workerObj|'s {{ServiceWorker/state}} to |state|. - 1. [=Fire an event=] named {{statechange!!event}} at |workerObj|. -
- -
-

Notify Controller Change

- - : Input - :: |client|, a [=/service worker client=] - : Output - :: None - - 1. Assert: |client| is not null. - 1. If |client| is an [=environment settings object=], queue a task to [=fire an event=] named controllerchange at the {{ServiceWorkerContainer}} object that |client| is [=ServiceWorkerContainer/service worker client|associated=] with. - - The task *must* use |client|'s responsible event loop and the DOM manipulation task source. -
- -
-

Match Service Worker Registration

- - : Input - :: |clientURL|, a [=/URL=] - : Output - :: A [=/service worker registration=] - - 1. Run the following steps atomically. - 1. Let |clientURLString| be serialized |clientURL|. - 1. Let |matchingScopeString| be the empty string. - 1. Let |scopeStringSet| be the result of [=map/get the keys|getting the keys=] from scope to registration map. - 1. Set |matchingScopeString| to the longest value in |scopeStringSet| which the value of |clientURLString| starts with, if it exists. - - Note: The URL string matching in this step is prefix-based rather than path-structural. E.g. a client URL string with "https://example.com/prefix-of/resource.html" will match a registration for a scope with "https://example.com/prefix". The URL string comparison is safe for the same-origin security as HTTP(S) URLs are always [=URL serializer|serialized=] with a trailing slash at the end of the origin part of the URLs. - - 1. Let |matchingScope| be null. - 1. If |matchingScopeString| is not the empty string, then: - 1. Set |matchingScope| to the result of parsing |matchingScopeString|. - 1. Assert: |matchingScope|'s [=url/origin=] and |clientURL|'s [=url/origin=] are [=same origin=]. - 1. Return the result of running [=Get Registration=] algorithm passing |matchingScope| as the argument. -
- -
-

Get Registration

- - : Input - :: |scope|, a [=/URL=] - : Output - :: A [=/service worker registration=] - - 1. Run the following steps atomically. - 1. Let |scopeString| be the empty string. - 1. If |scope| is not null, set |scopeString| to [=URL serializer|serialized=] |scope| with the *exclude fragment flag* set. - 1. [=map/For each=] |key| → |value| of scope to registration map: - 1. If |scopeString| matches |key|, then return |value|. - 1. Return null. -
- -
-

Get Newest Worker

- - : Input - :: |registration|, a [=/service worker registration=] - : Output - :: |newestWorker|, a [=/service worker=] - - 1. Run the following steps atomically. - 1. Let |newestWorker| be null. - 1. If |registration|'s installing worker is not null, set |newestWorker| to |registration|'s installing worker. - 1. Else if |registration|'s waiting worker is not null, set |newestWorker| to |registration|'s waiting worker. - 1. Else if |registration|'s active worker is not null, set |newestWorker| to |registration|'s active worker. - 1. Return |newestWorker|. -
- -
-

Service Worker Has No Pending Events

- - : Input - :: |worker|, a [=/service worker=] - : Output - :: True or false, a boolean - - 1. For each |event| of |worker|'s [=set of extended events=]: - 1. If |event| is [=ExtendableEvent/active=], return false. - 1. Return true. -
- -
-

Create Client

- - : Input - :: |client|, a [=/service worker client=] - : Output - :: |clientObject|, a {{Client}} object - - 1. Let |clientObject| be a new {{Client}} object. - 1. Set |clientObject|'s [=Client/service worker client=] to |client|. - 1. Return |clientObject|. -
- -
-

Create Window Client

- - : Input - :: |client|, a [=/service worker client=] - :: |frameType|, a string - :: |visibilityState|, a string - :: |focusState|, a boolean - :: |ancestorOriginsList|, a list - : Output - :: |windowClient|, a {{WindowClient}} object - - 1. Let |windowClient| be a new {{WindowClient}} object. - 1. Set |windowClient|'s [=Client/service worker client=] to |client|. - 1. Set |windowClient|'s [=frame type=] to |frameType|. - 1. Set |windowClient|'s [=visibility state=] to |visibilityState|. - 1. Set |windowClient|'s [=focus state=] to |focusState|. - 1. Set |windowClient|'s [=WindowClient/ancestor origins array=] to a [=frozen array type|frozen array=] created from |ancestorOriginsList|. - 1. Return |windowClient|. -
- -
-

Get Frame Type

- - : Input - :: |browsingContext|, a [=/browsing context=] - : Output - :: frameType, a string - - 1. Return the value by switching on the type of |browsingContext|: - : [=Nested browsing context=] - :: "nested" - - : [=Auxiliary browsing context=] - :: "auxiliary" - - : Otherwise - :: "top-level" -
- -
-

Resolve Get Client Promise

- - : Input - :: |client|, a [=/service worker client=] - :: |promise|, a [=promise=] - - : Output - :: none - - 1. If |client| is an [=environment settings object=], then: - 1. If |client| is not a [=secure context=], [=queue a task=] to reject |promise| with a "{{SecurityError}}" {{DOMException}}, on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], and abort these steps. - 1. Else: - 1. If |client|’s [=creation URL=] is not a [=potentially trustworthy URL=], [=queue a task=] to reject |promise| with a "{{SecurityError}}" {{DOMException}}, on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], and abort these steps. - 1. If |client| is an [=environment settings object=] and is not a [=window client=], then: - 1. Let |clientObject| be the result of running [=Create Client=] algorithm with |client| as the argument. - 1. [=Queue a task=] to resolve |promise| with |clientObject|, on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=], and abort these steps. - 1. Else: - 1. Let |browsingContext| be null. - 1. If |client| is an [=environment settings object=], set |browsingContext| to |client|'s [=environment settings object/global object=]'s [=/browsing context=]. - 1. Else, set |browsingContext| to |client|’s [=environment/target browsing context=]. - 1. [=Queue a task=] to run the following steps on |browsingContext|'s [=event loop=] using the [=user interaction task source=]: - 1. Let |frameType| be the result of running [=Get Frame Type=] with |browsingContext|. - 1. Let |visibilityState| be |browsingContext|'s [=active document=]'s {{Document/visibilityState}} attribute value. - 1. Let |focusState| be the result of running the [=has focus steps=] with |browsingContext|'s [=active document=] as the argument. - 1. Let |ancestorOriginsList| be the empty list. - 1. If |client| is a [=window client=], set |ancestorOriginsList| to |browsingContext|'s [=active document=]'s [=relevant global object=]'s {{Location}} object's [=Location/ancestor origins list=]'s associated list. - 1. [=Queue a task=] to run the following steps on |promise|'s [=relevant settings object=]'s [=responsible event loop=] using the [=DOM manipulation task source=]: - 1. If |client|'s [=discarded flag=] is set, resolve |promise| with undefined and abort these steps. - 1. Let |windowClient| be the result of running [=Create Window Client=] with |client|, |frameType|, |visibilityState|, |focusState|, and |ancestorOriginsList|. - 1. Resolve |promise| with |windowClient|. -
- -
-

Query Cache

- - : Input - :: |requestQuery|, a [=/request=] - :: |options|, a {{CacheQueryOptions}} object, optional - :: |targetStorage|, a [=request response list=], optional - : Output - :: |resultList|, a [=request response list=] - - 1. Let |resultList| be an empty [=list=]. - 1. Let |storage| be null. - 1. If the optional argument |targetStorage| is omitted, set |storage| to the [=relevant request response list=]. - 1. Else, set |storage| to |targetStorage|. - 1. [=list/For each=] |requestResponse| of |storage|: - 1. Let |cachedRequest| be |requestResponse|'s request. - 1. Let |cachedResponse| be |requestResponse|'s response. - 1. If [=Request Matches Cached Item=] with |requestQuery|, |cachedRequest|, |cachedResponse|, and |options| returns true, then: - 1. Let |requestCopy| be a copy of |cachedRequest|. - 1. Let |responseCopy| be a copy of |cachedResponse|. - 1. Add |requestCopy|/|responseCopy| to |resultList|. - 1. Return |resultList|. -
- -
-

Request Matches Cached Item

- - : Input - :: |requestQuery|, a [=/request=] - :: |request|, a [=/request=] - :: |response|, a [=/response=] or null, optional, defaulting to null - :: |options|, a {{CacheQueryOptions}} object, optional - : Output - :: a boolean - - 1. If |options|.{{CacheQueryOptions/ignoreMethod}} is false and |request|'s [=request/method=] is not \``GET`\`, return false. - 1. Let |queryURL| be |requestQuery|'s [=request/url=]. - 1. Let |cachedURL| be |request|'s [=request/url=]. - 1. If |options|.{{CacheQueryOptions/ignoreSearch}} is true, then: - 1. Set |cachedURL|'s [=url/query=] to the empty string. - 1. Set |queryURL|'s [=url/query=] to the empty string. - 1. If |queryURL| does not [=url/equal=] |cachedURL| with the *exclude fragment flag* set, then return false. - 1. If |response| is null, |options|.{{CacheQueryOptions/ignoreVary}} is true, or |response|'s [=response/header list=] does not [=header list/contain=] \``Vary`\`, then return true. - 1. Let |fieldValues| be the [=list=] containing the elements corresponding to the [=http/field-values=] of the [=Vary=] header for the [=header/value=] of the [=header=] with [=header/name=] \``Vary`\`. - 1. For each |fieldValue| in |fieldValues|: - 1. If |fieldValue| matches "`*`", or the [=header list/combine|combined value=] given |fieldValue| and |request|'s [=request/header list=] does not match the [=header list/combine|combined value=] given |fieldValue| and |requestQuery|'s [=request/header list=], then return false. - 1. Return true. -
- -
-

Batch Cache Operations

- - : Input - :: |operations|, a [=list=] of [=cache batch operation=] objects - : Output - :: |resultList|, a [=request response list=] - - 1. Let |cache| be the [=relevant request response list=]. - 1. Let |backupCache| be a new [=request response list=] that is a copy of |cache|. - 1. Let |addedItems| be an empty [=list=]. - 1. Try running the following substeps atomically: - 1. Let |resultList| be an empty [=list=]. - 1. [=list/For each=] |operation| in |operations|: - 1. If |operation|'s [=cache batch operation/type=] matches neither "`delete`" nor "`put`", throw a TypeError. - 1. If |operation|'s [=cache batch operation/type=] matches "`delete`" and |operation|'s [=cache batch operation/response=] is not null, throw a TypeError. - 1. If the result of running [=Query Cache=] with |operation|'s [=cache batch operation/request=], |operation|'s [=cache batch operation/options=], and |addedItems| [=list/is not empty=], [=throw=] an "{{InvalidStateError}}" {{DOMException}}. - 1. Let |requestResponses| be an empty [=list=]. - 1. If |operation|'s [=cache batch operation/type=] matches "`delete`", then: - 1. Set |requestResponses| to the result of running [=Query Cache=] with |operation|'s [=cache batch operation/request=] and |operation|'s [=cache batch operation/options=]. - 1. [=list/For each=] |requestResponse| in |requestResponses|: - 1. [=list/Remove=] the [=list/item=] whose value matches |requestResponse| from |cache|. - 1. Else if |operation|'s [=cache batch operation/type=] matches "`put`", then: - 1. If |operation|'s [=cache batch operation/response=] is null, throw a TypeError. - 1. Let |r| be |operation|'s [=cache batch operation/request=]'s associated [=Request/request=]. - 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", throw a TypeError. - 1. If |r|'s [=request/method=] is not \`GET\`, throw a TypeError. - 1. If |operation|'s [=cache batch operation/options=] is not null, throw a TypeError. - 1. Set |requestResponses| to the result of running [=Query Cache=] with |operation|'s [=cache batch operation/request=]. - 1. [=list/For each=] |requestResponse| of |requestResponses|: - 1. [=list/Remove=] the [=list/item=] whose value matches |requestResponse| from |cache|. - 1. [=list/Append=] |operation|'s [=cache batch operation/request=]/|operation|'s [=cache batch operation/response=] to |cache|. - 1. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "{{QuotaExceededError}}" {{DOMException}}. - 1. [=list/Append=] |operation|'s [=cache batch operation/request=]/|operation|'s [=cache batch operation/response=] to |addedItems|. - 1. [=Append=] |operation|'s [=cache batch operation/request=]/|operation|'s [=cache batch operation/response=] to |resultList|. - 1. Return |resultList|. - 1. And then, if an exception was thrown, then: - 1. [=list/Remove=] all the [=list/items=] from the [=relevant request response list=]. - 1. [=list/For each=] |requestResponse| of |backupCache|: - 1. [=list/Append=] |requestResponse| to the [=relevant request response list=]. - 1. [=Throw=] the exception. - - Note: When an exception is [=throw|thrown=], the implementation does undo (roll back) any changes made to the cache storage during the batch operation job. -
-
- -
-

Appendix B: Extended HTTP headers

- -
-

Service Worker Script Request

- - An HTTP request to [=/fetch=] a [=/service worker=]'s script resource will include the following header: - - : \`Service-Worker\` - :: Indicates this request is a [=/service worker=]'s script resource request. - - Note: This header helps administrators log the requests and detect threats. -
- -
-

Service Worker Script Response

- - An HTTP response to a [=/service worker=]'s script resource request can include the following header: - - : \`Service-Worker-Allowed\` - :: Indicates the user agent will override the path restriction, which limits the maximum allowed [=service worker registration/scope url=] that the script can control, to the given value. - - Note: The value is a URL. If a relative URL is given, it is parsed against the script's URL. - -
- Default scope: - -
-        // Maximum allowed scope defaults to the path the script sits in
-        // "/js/" in this example
-        navigator.serviceWorker.register("/js/sw.js").then(() => {
-          console.log("Install succeeded with the default scope '/js/'.");
-        });
-      
-
- -
- Upper path without Service-Worker-Allowed header: - -
-        // Set the scope to an upper path of the script location
-        // Response has no Service-Worker-Allowed header
-        navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(() => {
-          console.error("Install failed due to the path restriction violation.");
-        });
-      
-
- -
- Upper path with Service-Worker-Allowed header: - -
-        // Set the scope to an upper path of the script location
-        // Response included "Service-Worker-Allowed : /"
-        navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(() => {
-          console.log("Install succeeded as the max allowed scope was overriden to '/'.");
-        });
-      
-
- -
- A path restriction voliation even with Service-Worker-Allowed header: - -
-        // Set the scope to an upper path of the script location
-        // Response included "Service-Worker-Allowed : /foo"
-        navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(() => {
-          console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
-        });
-      
-
-
- -
-

Syntax

- - ABNF for the values of the headers used by the [=/service worker=]'s script resource requests and responses: - -
-      Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
-    
- - Note: The validation of the Service-Worker-Allowed header's values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF. -
-
- -
-

Acknowledgements

- - - Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress. - - Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him. - - In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref, Jinho Bang, Yutaka Hirano, isonmad, Ali Alabbas, Philip Jägenstedt, Mike Pennisi, and Eric Willigers. - - Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process. - - The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance. - - Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support. -
diff --git a/docs/index.bs b/index.bs similarity index 100% rename from docs/index.bs rename to index.bs diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/LICENSE b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/LICENSE deleted file mode 100644 index 80d612b0..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2014 Google Inc. All rights reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/README.md b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/README.md deleted file mode 100644 index 65d3e06c..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/README.md +++ /dev/null @@ -1,23 +0,0 @@ -Web Spec framework -=========================== - -This is a [Polymer](http://www.polymer-project.org/)-based HTML framework for -writing W3C-flavored web specifications. It's heavily influenced in both spirit and code by Jeff Yasskin's [HTML Document Framework for writing ISO C++ documents and papers](https://github.com/cplusplus/html-doc-framework). To use it for your document, you should - -1. [Install Bower.](http://bower.io/#installing-bower) -2. Install this package by running `bower install slightlyoff/web-spec-framework` in the root directory of your document. -3. Import this package into your main HTML file by adding two lines inside the `` element: - -```HTML - - -``` - -Before we can accept a contribution to this project, you'll need to sign the -Contributor License Agreement at https://developers.google.com/open-source/cla/individual. - -### `jk` - -This one isn't really C++-specific: it allows partitioning a main document -into multiple pieces. `other.html`'s body will be copied in place of the -`` element. diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/algorithm.html b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/algorithm.html deleted file mode 100644 index a09bd9f5..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/algorithm.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/base.css b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/base.css deleted file mode 100644 index 68705382..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/base.css +++ /dev/null @@ -1,167 +0,0 @@ -body { - padding: 2em 1em 2em 70px; - margin: 0; - font-family: 'Open Sans', sans-serif; - color: black; - background: white; - background-position: top left; - background-attachment: fixed; - background-repeat: no-repeat; - background-image: url(//www.w3.org/StyleSheets/TR/logo-WD); - line-height: 1.5em; - font-size: 14px; -} - -:link { color: #00C; background: transparent } -:visited { color: #609; background: transparent } -a:active { color: #C00; background: transparent } - -a:link img, -a:visited img { - border: none; -} - -.logo > a { - border-bottom: none; -} - -figure { - width: 600px; - margin: 0 auto; - display: block; -} - -figcaption { - font-size: 0.8em; -} - -h1, h2, h3, h4 { - font-family: 'Open Sans', sans-serif; - color: #005A9C; - padding: 0; - margin: 1.5em 0 0.3em 0; -} - -h1 { - font-size: 3em; - line-height: 1em; - margin: 1em 0; -} - -h2, h3 { - margin: 1.5em 0 0.3em 0; -} - -a { - color: black; -} - -code { - background-color: #eee; - font-family: 'Droid Sans Mono', monospace; - font-size: 0.8em; -} - -body > pre.prettyprint, -body > section pre { - background-color: #eee; - padding: 0 2em 1em 2em; - margin: 0; - border: none; -} - -address { - font-style: normal; -} - -object { - margin: 0 auto; - display: block; -} - -header > ul { - font-family: 'Open Sans', sans-serif; - font-size: 0.8em; - list-style: none; - margin: 0 -1em; - padding: 0.3em 0; - background-color: #eee; -} - -header > ul > li { - display: inline; - margin: 0 0 0 1em; -} - -header > ul > li:nth-of-type(3) { - display: inline; - margin: 0 0 0 5em; -} - -header > ul a { - color: #666; -} - -header > ul a:hover { - color: #000; -} - -code > ins { - background-color: #BBFFDF; - text-decoration: none; -} - -code > del { - background-color: #FF979D; -} - -var { - color: #005A9C; - font-style: normal; -} - -dt { - font-weight: bold; -} - -dt, dd { - margin-top: 0; - margin-bottom: 0; -} - -.warning:before { - content: "WARNING: "; - font-weight: bold; -} - -.warning { - padding: 10px 10px; - width: 100%; - background: #fffaba; - box-sizing: border-box; -} - -dfn { - font-style: normal; - font-weight: bold; - background-color: #f9f9f9; - padding: 0 2px; - outline: 1px solid #eee; -} - -dfn.no-references { - background-color: #ffefef; -} - -dfn:target, a:target { - background-color: #FFFF91; -} - -a { - text-decoration: none; - border-bottom: 1px solid #666; -} - -a[href*=dfn-] { - border-bottom: 1px dotted #ccc; -} diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower.json b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower.json deleted file mode 100644 index 6f8b2080..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "web-spec-framework", - "version": "0.1.0-pre", - "description": "A set of custom HTML elements to make writing well-formatted web specifications easier.", - "main": "framework.html", - "homepage": "https://github.com/slightlyof/web-spec-framework", - "ignore": [ - "**/.*", - "bower_components", - "test", - "tests" - ], - "dependencies": { - "polymer": "~0.2.0", - "polymer-ajax": "Polymer/polymer-ajax#0.2.0" - } -} \ No newline at end of file diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/.bower.json b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/.bower.json deleted file mode 100644 index 054f4a07..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/.bower.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "platform", - "main": "platform.js", - "homepage": "https://github.com/Polymer/platform", - "authors": [ - "The Polymer Authors" - ], - "description": "Integrate platform polyfills: load, build, test", - "keywords": [ - "polymer", - "web", - "components" - ], - "license": "BSD", - "private": true, - "version": "0.2.0", - "_release": "0.2.0", - "_resolution": { - "type": "version", - "tag": "0.2.0", - "commit": "2364ac16efa5904e97c27ad8ae93a02332771343" - }, - "_source": "git://github.com/Polymer/platform.git", - "_target": "0.2.0", - "_originalSource": "Polymer/platform" -} \ No newline at end of file diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/AUTHORS b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/AUTHORS deleted file mode 100644 index 06177657..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -# Names should be added to this file with this pattern: -# -# For individuals: -# Name -# -# For organizations: -# Organization -# -Google Inc. <*@google.com> diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/CONTRIBUTING.md b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/CONTRIBUTING.md deleted file mode 100644 index 1de2f341..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/CONTRIBUTING.md +++ /dev/null @@ -1,73 +0,0 @@ -# Contributing - -Want to contribute to Polymer? Great! - -We are more than happy to accept external contributions to the project in the form of [feedback](https://groups.google.com/forum/?fromgroups=#!forum/polymer-dev), [bug reports](../../issues), and pull requests. - -## Contributor License Agreement - -Before we can accept patches, there's a quick web form you need to fill out. - -- If you're contributing as an individual (e.g. you own the intellectual property), fill out [this form](http://code.google.com/legal/individual-cla-v1.0.html). -- If you're contributing under a company, fill out [this form](http://code.google.com/legal/corporate-cla-v1.0.html) instead. - -This CLA asserts that contributions are owned by you and that we can license all work under our [license](LICENSE). - -Other projects require a similar agreement: jQuery, Firefox, Apache, Node, and many more. - -[More about CLAs](https://www.google.com/search?q=Contributor%20License%20Agreement) - -## Initial setup - -Here's an easy guide that should get you up and running: - -1. Setup Grunt: `sudo npm install -g grunt-cli` -1. Fork the project on github and pull down your copy. - > replace the {{ username }} with your username and {{ repository }} with the repository name - - git clone git@github.com:{{ username }}/{{ repository }}.git --recursive - - Note the `--recursive`. This is necessary for submodules to initialize properly. If you don't do a recursive clone, you'll have to init them manually: - - git submodule init - git submodule update - - Download and run the `pull-all.sh` script to install the sibling dependencies. - - git clone git://github.com/Polymer/tools.git && tools/bin/pull-all.sh - -1. Test your change - > in the repo you've made changes to, run the tests: - - cd $REPO - npm install - grunt test - -1. Commit your code and make a pull request. - -That's it for the one time setup. Now you're ready to make a change. - -## Submitting a pull request - -We iterate fast! To avoid potential merge conflicts, it's a good idea to pull from the main project before making a change and submitting a pull request. The easiest way to do this is setup a remote called `upstream` and do a pull before working on a change: - - git remote add upstream git://github.com/Polymer/{{ repository }}.git - -Then before making a change, do a pull from the upstream `master` branch: - - git pull upstream master - -To make life easier, add a "pull upstream" alias in your `.gitconfig`: - - [alias] - pu = !"git fetch origin -v; git fetch upstream -v; git merge upstream/master" - -That will pull in changes from your forked repo, the main (upstream) repo, and merge the two. Then it's just a matter of running `git pu` before a change and pushing to your repo: - - git checkout master - git pu - # make change - git commit -a -m 'Awesome things.' - git push - -Lastly, don't forget to submit the pull request. diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/LICENSE b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/LICENSE deleted file mode 100644 index 92d60b01..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/PATENTS b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/PATENTS deleted file mode 100644 index e1209633..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/PATENTS +++ /dev/null @@ -1,23 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Polymer project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Polymer, where such license applies only to those -patent claims, both currently owned or controlled by Google and acquired -in the future, licensable by Google that are necessarily infringed by -this implementation of Polymer. This grant does not include claims -that would be infringed only as a consequence of further modification of -this implementation. If you or your agent or exclusive licensee -institute or order or agree to the institution of patent litigation -against any entity (including a cross-claim or counterclaim in a -lawsuit) alleging that this implementation of Polymer or any code -incorporated within this implementation of Polymer constitutes -direct or contributory patent infringement, or inducement of patent -infringement, then any patent rights granted to you under this License -for this implementation of Polymer shall terminate as of the date -such litigation is filed. diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/README.md b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/README.md deleted file mode 100644 index 65b661ed..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Platform -======== - -Aggregated polyfills the Polymer platform. - -[![Analytics](https://ga-beacon.appspot.com/UA-39334307-2/Polymer/platform/README)](https://github.com/igrigorik/ga-beacon) diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/bower.json b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/bower.json deleted file mode 100644 index b7dd9266..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/bower.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "platform", - "main": "platform.js", - "homepage": "https://github.com/Polymer/platform", - "authors": [ - "The Polymer Authors" - ], - "description": "Integrate platform polyfills: load, build, test", - "keywords": [ - "polymer", - "web", - "components" - ], - "license": "BSD", - "private": true, - "version": "0.2.0" -} \ No newline at end of file diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/build.log b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/build.log deleted file mode 100644 index 589ca50a..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/build.log +++ /dev/null @@ -1,48 +0,0 @@ -BUILD LOG ---------- -Build Time: 2014-02-14T15:57:20 - -NODEJS INFORMATION -================== -nodejs: v0.10.25 -chai: 1.9.0 -grunt: 0.4.2 -grunt-audit: 0.0.2 -grunt-concat-sourcemap: 0.4.1 -grunt-contrib-concat: 0.3.0 -grunt-contrib-uglify: 0.3.2 -grunt-contrib-yuidoc: 0.5.0 -grunt-karma: 0.6.2 -karma: 0.10.9 -karma-chrome-launcher: 0.1.2 -karma-coffee-preprocessor: 0.1.2 -karma-crbot-reporter: 0.0.4 -karma-firefox-launcher: 0.1.3 -karma-html2js-preprocessor: 0.1.0 -karma-ie-launcher: 0.1.1 -karma-jasmine: 0.1.5 -karma-mocha: 0.1.1 -karma-phantomjs-launcher: 0.1.2 -karma-requirejs: 0.2.1 -karma-safari-launcher: 0.1.1 -karma-script-launcher: 0.1.0 -mocha: 1.17.1 -requirejs: 2.1.10 - -REPO REVISIONS -============== -CustomElements: 18efac1ed0fa054536a9efae2ddea678ddb986b1 -HTMLImports: 69486ed9670afe6da872ed673e8a8d0448db16a8 -NodeBind: eb5ee7941f712cbee755da24ab7553e2d90fb99d -PointerEvents: 1d551ce7af420577f150f5c922fc54b97f04c84d -PointerGestures: 0cded24896294ebecdfdad47583468f714a0a34e -ShadowDOM: 308a7c2e67032f746b5e52f4e27320ffe3a57ecd -TemplateBinding: 279934127f6777bdfb9f752e98eb0da172fbca1b -WeakMap: a0947a9a0f58f5733f464755c3b86de624b00a5d -observe-js: 3ba9aeec73f7864d519fb13c6f38cb10923cdfd9 -platform: 6460c3d51b30b50d311eb1d7b055f29affa26f74 -polymer-expressions: 470cced7cf167bd164f0b924ceb088dd7a8240b9 - -BUILD HASHES -============ -build/platform.js: d0831d90d53d03c34a5382fdace5432599c97850 \ No newline at end of file diff --git a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/platform.js b/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/platform.js deleted file mode 100644 index 1324b4f9..00000000 --- a/publish/service_worker/FPWD-service-workers-20140501/assets/web-spec-framework/bower_components/platform/platform.js +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2012 The Polymer Authors. All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// @version: 0.2.0 -function PointerGestureEvent(a,b){var c=b||{},d=document.createEvent("Event"),e={bubbles:Boolean(c.bubbles)===c.bubbles||!0,cancelable:Boolean(c.cancelable)===c.cancelable||!0};d.initEvent(a,e.bubbles,e.cancelable);for(var f,g=Object.keys(c),h=0;h>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),function(a){"use strict";function b(){function a(a){b=a}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=[],c={};if(Object.observe(c,a),c.id=1,c.id=2,delete c.id,Object.deliverChangeRecords(a),3!==b.length)return!1;if("new"==b[0].type&&"updated"==b[1].type&&"deleted"==b[2].type)L="new",M="updated",N="reconfigured",O="deleted";else if("add"!=b[0].type||"update"!=b[1].type||"delete"!=b[2].type)return console.error("Unexpected change record names for Object.observe. Using dirty-checking instead"),!1;return Object.unobserve(c,a),c=[0],Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),2!=b.length?!1:b[0].type!=P||b[1].type!=P?!1:(Array.unobserve(c,a),!0)}function c(){if(a.document&&"securityPolicy"in a.document&&!a.document.securityPolicy.allowsEval)return!1;try{var b=new Function("","return true;");return b()}catch(c){return!1}}function d(a){return+a===a>>>0}function e(a){return+a}function f(a){return a===Object(a)}function g(a,b){return a===b?0!==a||1/a===1/b:S(a)&&S(b)?!0:a!==a&&b!==b}function h(a){return"string"!=typeof a?!1:(a=a.trim(),""==a?!0:"."==a[0]?!1:$.test(a))}function i(a,b){if(b!==_)throw Error("Use Path.get to retrieve path objects");return""==a.trim()?this:d(a)?(this.push(a),this):(a.split(/\s*\.\s*/).filter(function(a){return a}).forEach(function(a){this.push(a)},this),void(R&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn())))}function j(a){if(a instanceof i)return a;null==a&&(a=""),"string"!=typeof a&&(a=String(a));var b=ab[a];if(b)return b;if(!h(a))return bb;var b=new i(a,_);return ab[a]=b,b}function k(b){for(var c=0;db>c&&b.check_();)c++;return a.testingExposeCycleCount&&(a.dirtyCheckCycleCount=c),c>0}function l(a){for(var b in a)return!1;return!0}function m(a){return l(a.added)&&l(a.removed)&&l(a.changed)}function n(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function o(){if(!eb.length)return!1;for(var a=0;a=0?(i[c]=void 0,h.push(b)):h.indexOf(b)<0&&(h.push(b),Object.observe(b,d)),a(Object.getPrototypeOf(b))}}function b(){if(k=!1,j){var b=i===hb?[]:i;i=h,h=b;var c;for(var f in e)c=e[f],c&&c.state_==kb&&c.iterateObjects_(a);for(var g=0;gb||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function I(a,b,c,d){for(var e=E(b,c,d),f=!1,g=0,h=0;h=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.indexi.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.indexh)continue;I(c,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return c}function K(a,b){var c=[];return J(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?void(b.removed[0]!==a[b.index]&&c.push(b)):void(c=c.concat(G(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)))}),c}var L="add",M="update",N="reconfigure",O="delete",P="splice",Q=b(),R=c(),S=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},T="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},U="[$_a-zA-Z]",V="[$_a-zA-Z0-9]",W=U+"+"+V+"*",X="(?:[0-9]|[1-9]+[0-9]+)",Y="(?:"+W+"|"+X+")",Z="(?:"+Y+")(?:\\s*\\.\\s*"+Y+")*",$=new RegExp("^"+Z+"$"),_={},ab={};i.get=j,i.prototype=T({__proto__:[],valid:!0,toString:function(){return this.join(".")},getValueFrom:function(a){for(var b=0;bd&&b);a.testingExposeCycleCount&&(a.dirtyCheckCycleCount=d),qb=!1}}},pb&&(a.Platform.clearObservers=function(){ob=[]}),w.prototype=T({__proto__:t.prototype,arrayObserve:!1,connect_:function(){Q?this.directObserver_=q(this,this.value_,this.arrayObserve):this.oldObject_=this.copyObject(this.value_)},copyObject:function(a){var b=Array.isArray(a)?[]:{};for(var c in a)b[c]=a[c];return Array.isArray(a)&&(b.length=a.length),b},check_:function(a){var b,c;if(Q){if(!a)return!1;c={},b=D(this.value_,a,c)}else c=this.oldObject_,b=n(this.value_,this.oldObject_);return m(b)?!1:(Q||(this.oldObject_=this.copyObject(this.value_)),this.report_([b.added||{},b.removed||{},b.changed||{},function(a){return c[a]}]),!0)},disconnect_:function(){Q?(this.directObserver_.close(),this.directObserver_=void 0):this.oldObject_=void 0},deliver:function(){this.state_==kb&&(Q?this.directObserver_.deliver(!1):k(this))},discardChanges:function(){return this.directObserver_?this.directObserver_.deliver(!0):this.oldObject_=this.copyObject(this.value_),this.value_}}),x.prototype=T({__proto__:w.prototype,arrayObserve:!0,copyObject:function(a){return a.slice()},check_:function(a){var b;if(Q){if(!a)return!1;b=K(this.value_,a)}else b=G(this.value_,0,this.value_.length,this.oldObject_,0,this.oldObject_.length);return b&&b.length?(Q||(this.oldObject_=this.copyObject(this.value_)),this.report_([b]),!0):!1}}),x.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;ej;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(this.equals(a[b+k-1],d[e+j-1]))i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i},spliceOperationsFromEditDistances:function(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(ub):(e.push(vb),d=g),b--,c--):f==h?(e.push(xb),b--,d=h):(e.push(wb),c--,d=i)}else e.push(xb),b--;else e.push(wb),c--;return e.reverse(),e},calcSplices:function(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=this.sharedPrefix(a,d,i)),c==a.length&&f==d.length&&(h=this.sharedSuffix(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,c-b==0&&f-e==0)return[];if(b==c){for(var j=E(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[E(b,[],c-b)];for(var k=this.spliceOperationsFromEditDistances(this.calcEditDistances(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;od;d++)if(!this.equals(a[d],b[d]))return d;return c},sharedSuffix:function(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&this.equals(a[--d],b[--e]);)f++;return f},calculateSplices:function(a,b){return this.calcSplices(a,0,a.length,b,0,b.length)},equals:function(a,b){return a===b}};var yb=new F;a.Observer=t,a.Observer.runEOM_=fb,a.Observer.hasObjectObserve=Q,a.ArrayObserver=x,a.ArrayObserver.calculateSplices=function(a,b){return yb.calculateSplices(a,b)},a.ArraySplice=F,a.ObjectObserver=w,a.PathObserver=y,a.CompoundObserver=z,a.Path=i,a.ObserverTransform=B,a.Observer.changeRecordTypes={add:L,update:M,reconfigure:N,"delete":O,splice:P}}("undefined"!=typeof global&&global&&"undefined"!=typeof module&&module?global:this||window),window.Platform=window.Platform||{},window.logFlags=window.logFlags||{},function(a){var b=a.flags||{};location.search.slice(1).split("&").forEach(function(a){a=a.split("="),a[0]&&(b[a[0]]=a[1]||!0)});var c=document.currentScript||document.querySelector('script[src*="platform.js"]');if(c)for(var d,e=c.attributes,f=0;f=0;b--)if(!c(a[b]))return a[b];return null}function i(a,d){for(var e=[];a;){for(var g=[],i=d,j=void 0;i;){var l=null;if(g.length){if(c(i)&&(l=h(g),k(j))){var n=g[g.length-1];g.push(n)}}else g.push(i);if(m(i,a))return g[g.length-1];b(i)&&g.pop(),j=i,i=f(i,l,e)}a=b(a)?a.host:a.parentNode}}function j(b){return a.insertionParentTable.get(b)}function k(a){return j(a)}function l(a){for(var b;b=a.parentNode;)a=b;return a}function m(a,b){return l(a)===l(b)}function n(a,b){return a===b?!0:a instanceof Q.ShadowRoot?n(l(a.host),b):!1}function o(a){return S.get(a)?void 0:(S.set(a,!0),p(P(a),P(a.target)))}function p(b,c){if(T.get(b))throw new Error("InvalidStateError");T.set(b,!0),a.renderAllPending();var d=g(c);return"load"===b.type&&2===d.length&&d[0].target instanceof Q.Document&&d.shift(),_.set(b,d),q(b,d)&&r(b,d)&&s(b,d),X.set(b,v.NONE),V.delete(b,null),T.delete(b),b.defaultPrevented}function q(a,b){for(var c,d=b.length-1;d>0;d--){var e=b[d].target,f=b[d].currentTarget;if(e!==f&&(c=v.CAPTURING_PHASE,!t(b[d],a,c)))return!1}return!0}function r(a,b){var c=v.AT_TARGET;return t(b[0],a,c)}function s(a,b){for(var c,d=a.bubbles,e=1;e=f;f++){var g=b[f].currentTarget,h=l(g);n(e,h)&&(f!==d||g instanceof Q.Node)&&(a[c++]=g)}a.length=c}return a},stopPropagation:function(){Y.set(this,!0)},stopImmediatePropagation:function(){Y.set(this,!0),Z.set(this,!0)}},N(ab,v,document.createEvent("Event"));var bb=x("UIEvent",v),cb=x("CustomEvent",v),db={get relatedTarget(){return W.get(this)||P(O(this).relatedTarget)}},eb=M({initMouseEvent:y("initMouseEvent",14)},db),fb=M({initFocusEvent:y("initFocusEvent",5)},db),gb=x("MouseEvent",bb,eb),hb=x("FocusEvent",bb,fb),ib=Object.create(null),jb=function(){try{new window.FocusEvent("focus")}catch(a){return!1}return!0}();if(!jb){var kb=function(a,b,c){if(c){var d=ib[c];b=M(M({},d),b)}ib[a]=b}; -kb("Event",{bubbles:!1,cancelable:!1}),kb("CustomEvent",{detail:null},"Event"),kb("UIEvent",{view:null,detail:0},"Event"),kb("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),kb("FocusEvent",{relatedTarget:null},"UIEvent")}A.prototype=Object.create(v.prototype),M(A.prototype,{get returnValue(){return this.impl.returnValue},set returnValue(a){this.impl.returnValue=a}});var lb=window.EventTarget,mb=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(a){var b=a.prototype;mb.forEach(function(a){Object.defineProperty(b,a+"_",{value:b[a]})})}),D.prototype={addEventListener:function(a,b,c){if(B(b)&&!C(a)){var d=new u(a,b,c),e=R.get(this);if(e){for(var f=0;fd;d++)b[d]=f(a[d]);return b.length=e,b}function e(a,b){a.prototype[b]=function(){return d(this.impl[b].apply(this.impl,arguments))}}var f=a.wrap;c.prototype={item:function(a){return this[a]}},b(c.prototype,"item"),a.wrappers.NodeList=c,a.addWrapNodeListMethod=e,a.wrapNodeList=d}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){y(a instanceof v)}function c(a){var b=new x;return b[0]=a,b.length=1,b}function d(a,b,c){A(b,"childList",{removedNodes:c,previousSibling:a.previousSibling,nextSibling:a.nextSibling})}function e(a,b){A(a,"childList",{removedNodes:b})}function f(a,b,d,e){if(a instanceof DocumentFragment){var f=h(a);J=!0;for(var g=f.length-1;g>=0;g--)a.removeChild(f[g]),f[g].parentNode_=b;J=!1;for(var g=0;ge;e++)d.appendChild(F(b[e]));return d}function q(a){if(void 0!==a.firstChild_)for(var b=a.firstChild_;b;){var c=b;b=b.nextSibling_,c.parentNode_=c.previousSibling_=c.nextSibling_=void 0}a.firstChild_=a.lastChild_=void 0}function r(a){if(a.invalidateShadowRenderer()){for(var b=a.firstChild;b;){y(b.parentNode===a);var c=b.nextSibling,d=F(b),e=d.parentNode;e&&Q.call(e,d),b.previousSibling_=b.nextSibling_=b.parentNode_=null,b=c}a.firstChild_=a.lastChild_=null}else for(var c,f=F(a),g=f.firstChild;g;)c=g.nextSibling,Q.call(f,g),g=c}function s(a){var b=a.parentNode;return b&&b.invalidateShadowRenderer()}function t(a){for(var b,c=0;c>>0}function c(a){d.call(this,a)}var d=a.wrappers.CharacterData,e=(a.enqueueMutation,a.mixin),f=a.registerWrapper,g=window.Text;c.prototype=Object.create(d.prototype),e(c.prototype,{splitText:function(a){a=b(a);var c=this.data;if(a>c.length)throw new Error("IndexSizeError");var d=c.slice(0,a),e=c.slice(a);this.data=d;var f=this.ownerDocument.createTextNode(e);return this.parentNode&&this.parentNode.insertBefore(f,this.nextSibling),f}}),f(g,c,document.createTextNode("")),a.wrappers.Text=c}(window.ShadowDOMPolyfill),function(a){"use strict";function b(b,c){var d=b.parentNode;if(d&&d.shadowRoot){var e=a.getRendererForHost(d);e.dependsOnAttribute(c)&&e.invalidate()}}function c(a,b,c){k(a,"attributes",{name:b,namespace:null,oldValue:c})}function d(a){h.call(this,a)}function e(a,c,d){var e=d||c;Object.defineProperty(a,c,{get:function(){return this.impl[c]},set:function(a){this.impl[c]=a,b(this,e)},configurable:!0,enumerable:!0})}var f=a.ChildNodeInterface,g=a.GetElementsByInterface,h=a.wrappers.Node,i=a.ParentNodeInterface,j=a.SelectorsInterface,k=(a.addWrapNodeListMethod,a.enqueueMutation),l=a.mixin,m=(a.oneOf,a.registerWrapper),n=a.wrappers,o=window.Element,p=["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"].filter(function(a){return o.prototype[a]}),q=p[0],r=o.prototype[q];d.prototype=Object.create(h.prototype),l(d.prototype,{createShadowRoot:function(){var b=new n.ShadowRoot(this);this.impl.polymerShadowRoot_=b;var c=a.getRendererForHost(this);return c.invalidate(),b},get shadowRoot(){return this.impl.polymerShadowRoot_||null},setAttribute:function(a,d){var e=this.impl.getAttribute(a);this.impl.setAttribute(a,d),c(this,a,e),b(this,a)},removeAttribute:function(a){var d=this.impl.getAttribute(a);this.impl.removeAttribute(a),c(this,a,d),b(this,a)},matches:function(a){return r.call(this.impl,a)}}),p.forEach(function(a){"matches"!==a&&(d.prototype[a]=function(a){return this.matches(a)})}),o.prototype.webkitCreateShadowRoot&&(d.prototype.webkitCreateShadowRoot=d.prototype.createShadowRoot),e(d.prototype,"id"),e(d.prototype,"className","class"),l(d.prototype,f),l(d.prototype,g),l(d.prototype,i),l(d.prototype,j),m(o,d,document.createElementNS(null,"x")),a.matchesNames=p,a.wrappers.Element=d}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a){case"&":return"&";case"<":return"<";case">":return">";case'"':return""";case" ":return" "}}function c(a){return a.replace(z,b)}function d(a){return a.replace(A,b)}function e(a){for(var b={},c=0;c";case Node.TEXT_NODE:var k=a.data;return b&&C[b.localName]?k:d(k);case Node.COMMENT_NODE:return"";default:throw console.error(a),new Error("not implemented")}}function g(a){a instanceof y.HTMLTemplateElement&&(a=a.content);for(var b="",c=a.firstChild;c;c=c.nextSibling)b+=f(c,a);return b}function h(a,b,c){var d=c||"div";a.textContent="";var e=w(a.ownerDocument.createElement(d));e.innerHTML=b;for(var f;f=e.firstChild;)a.appendChild(x(f))}function i(a){o.call(this,a)}function j(a,b){var c=w(a.cloneNode(!1));c.innerHTML=b;for(var d,e=w(document.createDocumentFragment());d=c.firstChild;)e.appendChild(d);return x(e)}function k(b){return function(){return a.renderAllPending(),this.impl[b]}}function l(a){p(i,a,k(a))}function m(b){Object.defineProperty(i.prototype,b,{get:k(b),set:function(c){a.renderAllPending(),this.impl[b]=c},configurable:!0,enumerable:!0})}function n(b){Object.defineProperty(i.prototype,b,{value:function(){return a.renderAllPending(),this.impl[b].apply(this.impl,arguments)},configurable:!0,enumerable:!0})}var o=a.wrappers.Element,p=a.defineGetter,q=a.enqueueMutation,r=a.mixin,s=a.nodesWereAdded,t=a.nodesWereRemoved,u=a.registerWrapper,v=a.snapshotNodeList,w=a.unwrap,x=a.wrap,y=a.wrappers,z=/[&\u00A0"]/g,A=/[&\u00A0<>]/g,B=e(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),C=e(["style","script","xmp","iframe","noembed","noframes","plaintext","noscript"]),D=/MSIE/.test(navigator.userAgent),E=window.HTMLElement,F=window.HTMLTemplateElement;i.prototype=Object.create(o.prototype),r(i.prototype,{get innerHTML(){return g(this)},set innerHTML(a){if(D&&C[this.localName])return void(this.textContent=a);var b=v(this.childNodes);this.invalidateShadowRenderer()?this instanceof y.HTMLTemplateElement?h(this.content,a):h(this,a,this.tagName):!F&&this instanceof y.HTMLTemplateElement?h(this.content,a):this.impl.innerHTML=a;var c=v(this.childNodes);q(this,"childList",{addedNodes:c,removedNodes:b}),t(b),s(c)},get outerHTML(){return f(this,this.parentNode)},set outerHTML(a){var b=this.parentNode;if(b){b.invalidateShadowRenderer();var c=j(b,a);b.replaceChild(c,this)}},insertAdjacentHTML:function(a,b){var c,d;switch(String(a).toLowerCase()){case"beforebegin":c=this.parentNode,d=this;break;case"afterend":c=this.parentNode,d=this.nextSibling;break;case"afterbegin":c=this,d=this.firstChild;break;case"beforeend":c=this,d=null;break;default:return}var e=j(c,b);c.insertBefore(e,d)}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollWidth"].forEach(l),["scrollLeft","scrollTop"].forEach(m),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(n),u(E,i,document.createElement("b")),a.wrappers.HTMLElement=i,a.getInnerHTML=g,a.setInnerHTML=h}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=a.wrap,g=window.HTMLCanvasElement;b.prototype=Object.create(c.prototype),d(b.prototype,{getContext:function(){var a=this.impl.getContext.apply(this.impl,arguments);return a&&f(a)}}),e(g,b,document.createElement("canvas")),a.wrappers.HTMLCanvasElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLContentElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get select(){return this.getAttribute("select")},set select(a){this.setAttribute("select",a)},setAttribute:function(a,b){c.prototype.setAttribute.call(this,a,b),"select"===String(a).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),f&&e(f,b),a.wrappers.HTMLContentElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}function c(a,b){if(!(this instanceof c))throw new TypeError("DOM object constructor cannot be called as a function.");var e=f(document.createElement("img"));d.call(this,e),g(e,this),void 0!==a&&(e.width=a),void 0!==b&&(e.height=b)}var d=a.wrappers.HTMLElement,e=a.registerWrapper,f=a.unwrap,g=a.rewrap,h=window.HTMLImageElement;b.prototype=Object.create(d.prototype),e(h,b,document.createElement("img")),c.prototype=b.prototype,a.wrappers.HTMLImageElement=b,a.wrappers.Image=c}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLShadowElement;b.prototype=Object.create(c.prototype),d(b.prototype,{}),f&&e(f,b),a.wrappers.HTMLShadowElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){if(!a.defaultView)return a;var b=k.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);k.set(a,b)}return b}function c(a){for(var c,d=b(a.ownerDocument),e=h(d.createDocumentFragment());c=a.firstChild;)e.appendChild(c);return e}function d(a){if(e.call(this,a),!l){var b=c(a);j.set(this,i(b))}}var e=a.wrappers.HTMLElement,f=a.mixin,g=a.registerWrapper,h=a.unwrap,i=a.wrap,j=new WeakMap,k=new WeakMap,l=window.HTMLTemplateElement;d.prototype=Object.create(e.prototype),f(d.prototype,{get content(){return l?i(this.impl.content):j.get(this)}}),l&&g(l,d),a.wrappers.HTMLTemplateElement=d}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.registerWrapper,e=window.HTMLMediaElement;b.prototype=Object.create(c.prototype),d(e,b,document.createElement("audio")),a.wrappers.HTMLMediaElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}function c(a){if(!(this instanceof c))throw new TypeError("DOM object constructor cannot be called as a function.");var b=f(document.createElement("audio"));d.call(this,b),g(b,this),b.setAttribute("preload","auto"),void 0!==a&&b.setAttribute("src",a)}var d=a.wrappers.HTMLMediaElement,e=a.registerWrapper,f=a.unwrap,g=a.rewrap,h=window.HTMLAudioElement;b.prototype=Object.create(d.prototype),e(h,b,document.createElement("audio")),c.prototype=b.prototype,a.wrappers.HTMLAudioElement=b,a.wrappers.Audio=c}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){return a.replace(/\s+/g," ").trim()}function c(a){e.call(this,a)}function d(a,b,c,f){if(!(this instanceof d))throw new TypeError("DOM object constructor cannot be called as a function.");var g=i(document.createElement("option"));e.call(this,g),h(g,this),void 0!==a&&(g.text=a),void 0!==b&&g.setAttribute("value",b),c===!0&&g.setAttribute("selected",""),g.selected=f===!0}var e=a.wrappers.HTMLElement,f=a.mixin,g=a.registerWrapper,h=a.rewrap,i=a.unwrap,j=a.wrap,k=window.HTMLOptionElement;c.prototype=Object.create(e.prototype),f(c.prototype,{get text(){return b(this.textContent)},set text(a){this.textContent=b(String(a))},get form(){return j(i(this).form)}}),g(k,c,document.createElement("option")),d.prototype=c.prototype,a.wrappers.HTMLOptionElement=c,a.wrappers.Option=d}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a.localName){case"content":return new c(a);case"shadow":return new e(a);case"template":return new f(a)}d.call(this,a)}var c=a.wrappers.HTMLContentElement,d=a.wrappers.HTMLElement,e=a.wrappers.HTMLShadowElement,f=a.wrappers.HTMLTemplateElement,g=(a.mixin,a.registerWrapper),h=window.HTMLUnknownElement;b.prototype=Object.create(d.prototype),g(h,b),a.wrappers.HTMLUnknownElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";var b=a.registerObject,c="http://www.w3.org/2000/svg",d=document.createElementNS(c,"title"),e=b(d),f=Object.getPrototypeOf(e.prototype).constructor;a.wrappers.SVGElement=f}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){m.call(this,a)}var c=a.mixin,d=a.registerWrapper,e=a.unwrap,f=a.wrap,g=window.SVGUseElement,h="http://www.w3.org/2000/svg",i=f(document.createElementNS(h,"g")),j=document.createElementNS(h,"use"),k=i.constructor,l=Object.getPrototypeOf(k.prototype),m=l.constructor;b.prototype=Object.create(l),"instanceRoot"in j&&c(b.prototype,{get instanceRoot(){return f(e(this).instanceRoot)},get animatedInstanceRoot(){return f(e(this).animatedInstanceRoot)}}),d(g,b,j),a.wrappers.SVGUseElement=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.mixin,e=a.registerWrapper,f=a.wrap,g=window.SVGElementInstance;g&&(b.prototype=Object.create(c.prototype),d(b.prototype,{get correspondingElement(){return f(this.impl.correspondingElement)},get correspondingUseElement(){return f(this.impl.correspondingUseElement)},get parentNode(){return f(this.impl.parentNode)},get childNodes(){throw new Error("Not implemented")},get firstChild(){return f(this.impl.firstChild)},get lastChild(){return f(this.impl.lastChild)},get previousSibling(){return f(this.impl.previousSibling)},get nextSibling(){return f(this.impl.nextSibling)}}),e(g,b),a.wrappers.SVGElementInstance=b)}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.mixin,d=a.registerWrapper,e=a.unwrap,f=a.unwrapIfNeeded,g=a.wrap,h=window.CanvasRenderingContext2D;c(b.prototype,{get canvas(){return g(this.impl.canvas)},drawImage:function(){arguments[0]=f(arguments[0]),this.impl.drawImage.apply(this.impl,arguments)},createPattern:function(){return arguments[0]=e(arguments[0]),this.impl.createPattern.apply(this.impl,arguments)}}),d(h,b,document.createElement("canvas").getContext("2d")),a.wrappers.CanvasRenderingContext2D=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.mixin,d=a.registerWrapper,e=a.unwrapIfNeeded,f=a.wrap,g=window.WebGLRenderingContext;if(g){c(b.prototype,{get canvas(){return f(this.impl.canvas)},texImage2D:function(){arguments[5]=e(arguments[5]),this.impl.texImage2D.apply(this.impl,arguments)},texSubImage2D:function(){arguments[6]=e(arguments[6]),this.impl.texSubImage2D.apply(this.impl,arguments)}});var h=/WebKit/.test(navigator.userAgent)?{drawingBufferHeight:null,drawingBufferWidth:null}:{};d(g,b,h),a.wrappers.WebGLRenderingContext=b}}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.registerWrapper,d=a.unwrap,e=a.unwrapIfNeeded,f=a.wrap,g=window.Range;b.prototype={get startContainer(){return f(this.impl.startContainer)},get endContainer(){return f(this.impl.endContainer)},get commonAncestorContainer(){return f(this.impl.commonAncestorContainer)},setStart:function(a,b){this.impl.setStart(e(a),b)},setEnd:function(a,b){this.impl.setEnd(e(a),b)},setStartBefore:function(a){this.impl.setStartBefore(e(a))},setStartAfter:function(a){this.impl.setStartAfter(e(a))},setEndBefore:function(a){this.impl.setEndBefore(e(a))},setEndAfter:function(a){this.impl.setEndAfter(e(a))},selectNode:function(a){this.impl.selectNode(e(a))},selectNodeContents:function(a){this.impl.selectNodeContents(e(a))},compareBoundaryPoints:function(a,b){return this.impl.compareBoundaryPoints(a,d(b))},extractContents:function(){return f(this.impl.extractContents())},cloneContents:function(){return f(this.impl.cloneContents())},insertNode:function(a){this.impl.insertNode(e(a))},surroundContents:function(a){this.impl.surroundContents(e(a))},cloneRange:function(){return f(this.impl.cloneRange())},isPointInRange:function(a,b){return this.impl.isPointInRange(e(a),b)},comparePoint:function(a,b){return this.impl.comparePoint(e(a),b)},intersectsNode:function(a){return this.impl.intersectsNode(e(a))},toString:function(){return this.impl.toString()}},g.prototype.createContextualFragment&&(b.prototype.createContextualFragment=function(a){return f(this.impl.createContextualFragment(a))}),c(window.Range,b,document.createRange()),a.wrappers.Range=b}(window.ShadowDOMPolyfill),function(a){"use strict";var b=a.GetElementsByInterface,c=a.ParentNodeInterface,d=a.SelectorsInterface,e=a.mixin,f=a.registerObject,g=f(document.createDocumentFragment());e(g.prototype,c),e(g.prototype,d),e(g.prototype,b);var h=f(document.createComment(""));a.wrappers.Comment=h,a.wrappers.DocumentFragment=g}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=i(a.impl.ownerDocument.createDocumentFragment());c.call(this,b),g(b,this);var d=a.shadowRoot;k.set(this,d),j.set(this,a)}var c=a.wrappers.DocumentFragment,d=a.elementFromPoint,e=a.getInnerHTML,f=a.mixin,g=a.rewrap,h=a.setInnerHTML,i=a.unwrap,j=new WeakMap,k=new WeakMap,l=/[ \t\n\r\f]/;b.prototype=Object.create(c.prototype),f(b.prototype,{get innerHTML(){return e(this)},set innerHTML(a){h(this,a),this.invalidateShadowRenderer()},get olderShadowRoot(){return k.get(this)||null},get host(){return j.get(this)||null},invalidateShadowRenderer:function(){return j.get(this).invalidateShadowRenderer()},elementFromPoint:function(a,b){return d(this,this.ownerDocument,a,b)},getElementById:function(a){return l.test(a)?null:this.querySelector('[id="'+a+'"]')}}),a.wrappers.ShadowRoot=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){a.previousSibling_=a.previousSibling,a.nextSibling_=a.nextSibling,a.parentNode_=a.parentNode}function c(a,c,e){var f=F(a),g=F(c),h=e?F(e):null;if(d(c),b(c),e)a.firstChild===e&&(a.firstChild_=e),e.previousSibling_=e.previousSibling;else{a.lastChild_=a.lastChild,a.lastChild===a.firstChild&&(a.firstChild_=a.firstChild);var i=G(f.lastChild);i&&(i.nextSibling_=i.nextSibling)}f.insertBefore(g,h)}function d(a){var c=F(a),d=c.parentNode;if(d){var e=G(d);b(a),a.previousSibling&&(a.previousSibling.nextSibling_=a),a.nextSibling&&(a.nextSibling.previousSibling_=a),e.lastChild===a&&(e.lastChild_=a),e.firstChild===a&&(e.firstChild_=a),d.removeChild(c)}}function e(a,b){g(b).push(a),x(a,b);var c=I.get(a);c||I.set(a,c=[]),c.push(b)}function f(a){H.set(a,[])}function g(a){return H.get(a)}function h(a){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}function i(a,b,c){for(var d=a.firstChild;d;d=d.nextSibling)if(b(d)){if(c(d)===!1)return}else i(d,b,c)}function j(a,b){var c=b.getAttribute("select");if(!c)return!0;if(c=c.trim(),!c)return!0;if(!(a instanceof z))return!1;if("*"===c||c===a.localName)return!0;if(!L.test(c))return!1;if(":"===c[0]&&!M.test(c))return!1;try{return a.matches(c)}catch(d){return!1}}function k(){for(var a=0;ap;p++){var q=G(f[k++]);g.get(q)||d(q)}for(var r=n.addedCount,s=f[k]&&G(f[k]),p=0;r>p;p++){var t=e[j++],u=t.node;c(b,u,s),g.set(u,!0),t.sync(g)}l+=r}for(var m=l;m=0;j--)i=Object.create(i);["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"].forEach(function(a){var b=e[a];b&&(i[a]=function(){z(this)instanceof d||x(this),b.apply(z(this),arguments)})});var k={prototype:i};c.extends&&(k.extends=c.extends),d.prototype=e,d.prototype.constructor=d,a.constructorTable.set(i,d),a.nativePrototypeTable.set(e,i);E.call(y(this),b,k);return d},s([window.HTMLDocument||window.Document],["registerElement"])}s([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"].concat(t)),s([window.HTMLDocument||window.Document],["adoptNode","importNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById","getSelection"]),u(b.prototype,j),u(b.prototype,l),u(b.prototype,n),u(b.prototype,{get implementation(){var a=B.get(this);return a?a:(a=new g(y(this).implementation),B.set(this,a),a)}}),v(window.Document,b,document.implementation.createHTMLDocument("")),window.HTMLDocument&&v(window.HTMLDocument,b),A([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),h(g,"createDocumentType"),h(g,"createDocument"),h(g,"createHTMLDocument"),i(g,"hasFeature"),v(window.DOMImplementation,g),s([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),a.adoptNodeNoRemove=d,a.wrappers.DOMImplementation=g,a.wrappers.Document=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.wrappers.Selection,e=a.mixin,f=a.registerWrapper,g=a.renderAllPending,h=a.unwrap,i=a.unwrapIfNeeded,j=a.wrap,k=window.Window,l=window.getComputedStyle,m=window.getSelection;b.prototype=Object.create(c.prototype),k.prototype.getComputedStyle=function(a,b){return j(this||window).getComputedStyle(i(a),b)},k.prototype.getSelection=function(){return j(this||window).getSelection()},delete window.getComputedStyle,delete window.getSelection,["addEventListener","removeEventListener","dispatchEvent"].forEach(function(a){k.prototype[a]=function(){var b=j(this||window);return b[a].apply(b,arguments)},delete window[a]}),e(b.prototype,{getComputedStyle:function(a,b){return g(),l.call(h(this),i(a),b)},getSelection:function(){return g(),new d(m.call(h(this)))}}),f(k,b),a.wrappers.Window=b}(window.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=c[a],d=window[b];if(d){var e=document.createElement(a),f=e.constructor;window[b]=f}}var c=(a.isWrapperFor,{a:"HTMLAnchorElement",area:"HTMLAreaElement",br:"HTMLBRElement",base:"HTMLBaseElement",body:"HTMLBodyElement",button:"HTMLButtonElement",dl:"HTMLDListElement",datalist:"HTMLDataListElement",data:"HTMLDataElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",hr:"HTMLHRElement",head:"HTMLHeadElement",h1:"HTMLHeadingElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",input:"HTMLInputElement",li:"HTMLLIElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",link:"HTMLLinkElement",map:"HTMLMapElement",marquee:"HTMLMarqueeElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",del:"HTMLModElement",ol:"HTMLOListElement",object:"HTMLObjectElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",time:"HTMLTimeElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",table:"HTMLTableElement",tr:"HTMLTableRowElement",thead:"HTMLTableSectionElement",tbody:"HTMLTableSectionElement",textarea:"HTMLTextAreaElement",track:"HTMLTrackElement",title:"HTMLTitleElement",ul:"HTMLUListElement",video:"HTMLVideoElement"});Object.keys(c).forEach(b),Object.getOwnPropertyNames(a.wrappers).forEach(function(b){window[b]=a.wrappers[b]}),a.knownElements=c}(window.ShadowDOMPolyfill),function(){window.wrap=ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=ShadowDOMPolyfill.unwrapIfNeeded,Object.defineProperty(Element.prototype,"webkitShadowRoot",Object.getOwnPropertyDescriptor(Element.prototype,"shadowRoot"));var a=Element.prototype.createShadowRoot;Element.prototype.createShadowRoot=function(){var b=a.call(this);return CustomElements.watchShadow(this),b},Element.prototype.webkitCreateShadowRoot=Element.prototype.createShadowRoot}(),function(a){function b(a,b){var c="";return Array.prototype.forEach.call(a,function(a){c+=a.textContent+"\n\n"}),b||(c=c.replace(h,"")),c}function c(a){var b=document.createElement("style");return b.textContent=a,b}function d(a){var b=c(a);document.head.appendChild(b);var d=b.sheet.cssRules;return b.parentNode.removeChild(b),d}function e(a){a&&f().appendChild(document.createTextNode(a))}function f(){return o||(o=document.createElement("style"),o.setAttribute(q,""),o[q]=!0),o}var g={strictStyling:!1,registry:{},shimStyling:function(a,b,d){var f=this.isTypeExtension(d),g=this.registerDefinition(a,b,d);this.strictStyling&&this.applyScopeToContent(a,b);var h=this.stylesToShimmedCssText(g.rootStyles,g.scopeStyles,b,f);g.shimmedStyle=c(h),a&&(a.shimmedStyle=g.shimmedStyle);for(var i,j=0,k=g.rootStyles.length;k>j&&(i=g.rootStyles[j]);j++)i.parentNode.removeChild(i);e(h)},stylesToShimmedCssText:function(a,b,c,d){c=c||"",this.insertPolyfillDirectives(a),this.insertPolyfillRules(a);var e=this.shimScoping(b,c,d);return e+=this.extractPolyfillUnscopedRules(a),e.trim()},registerDefinition:function(a,b,c){var d=this.registry[b]={root:a,name:b,extendsName:c},e=a?a.querySelectorAll("style"):[];e=e?Array.prototype.slice.call(e,0):[],d.rootStyles=e,d.scopeStyles=d.rootStyles;var f=this.registry[d.extendsName];return!f||a&&!a.querySelector("shadow")||(d.scopeStyles=f.scopeStyles.concat(d.scopeStyles)),d},isTypeExtension:function(a){return a&&a.indexOf("-")<0},applyScopeToContent:function(a,b){a&&(Array.prototype.forEach.call(a.querySelectorAll("*"),function(a){a.setAttribute(b,"")}),Array.prototype.forEach.call(a.querySelectorAll("template"),function(a){this.applyScopeToContent(a.content,b)},this))},insertPolyfillDirectives:function(a){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.insertPolyfillDirectivesInCssText(a.textContent)},this)},insertPolyfillDirectivesInCssText:function(a){return a.replace(i,function(a,b){return b.slice(0,-2)+"{"})},insertPolyfillRules:function(a){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.insertPolyfillRulesInCssText(a.textContent)},this)},insertPolyfillRulesInCssText:function(a){return a.replace(j,function(a,b){return b.slice(0,-1)})},extractPolyfillUnscopedRules:function(a){var b="";return a&&Array.prototype.forEach.call(a,function(a){b+=this.extractPolyfillUnscopedRulesFromCssText(a.textContent)+"\n\n"},this),b},extractPolyfillUnscopedRulesFromCssText:function(a){for(var b,c="";b=k.exec(a);)c+=b[1].slice(0,-1)+"\n\n";return c},shimScoping:function(a,b,c){return a?this.convertScopedStyles(a,b,c):void 0},convertScopedStyles:function(a,c,e){var f=b(a);if(f=this.insertPolyfillHostInCssText(f),f=this.convertColonHost(f),f=this.convertColonAncestor(f),f=this.convertCombinators(f),c){var g=d(f);f=this.scopeRules(g,c,e)}return f},convertColonHost:function(a){return this.convertColonRule(a,cssColonHostRe,this.colonHostPartReplacer)},convertColonAncestor:function(a){return this.convertColonRule(a,cssColonAncestorRe,this.colonAncestorPartReplacer)},convertColonRule:function(a,b,c){return a.replace(b,function(a,b,d,e){if(b=polyfillHostNoCombinator,d){for(var f,g=d.split(","),h=[],i=0,j=g.length;j>i&&(f=g[i]);i++)f=f.trim(),h.push(c(b,f,e));return h.join(",")}return b+e})},colonAncestorPartReplacer:function(a,b,c){return b.match(l)?this.colonHostPartReplacer(a,b,c):a+b+c+", "+b+" "+a+c},colonHostPartReplacer:function(a,b,c){return a+b.replace(l,"")+c},convertCombinators:function(a){return a.replace(/\^\^/g," ").replace(/\^/g," ")},scopeRules:function(a,b,c){var d="";return Array.prototype.forEach.call(a,function(a){a.selectorText&&a.style&&a.style.cssText?(d+=this.scopeSelector(a.selectorText,b,c,this.strictStyling)+" {\n ",d+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(d+="@media "+a.media.mediaText+" {\n",d+=this.scopeRules(a.cssRules,b,c),d+="\n}\n\n"):a.cssText&&(d+=a.cssText+"\n\n")},this),d},scopeSelector:function(a,b,c,d){var e=[],f=a.split(",");return f.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b,c)&&(a=d&&!a.match(polyfillHostNoCombinator)?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b,c)),e.push(a)},this),e.join(", ")},selectorNeedsScoping:function(a,b,c){var d=this.makeScopeMatcher(b,c);return!a.match(d)},makeScopeMatcher:function(a,b){var c=b?"\\[is=['\"]?"+a+"['\"]?\\]":a;return new RegExp("^("+c+")"+selectorReSuffix,"m")},applySimpleSelectorScope:function(a,b,c){var d=c?"[is="+b+"]":b;return a.match(polyfillHostRe)?(a=a.replace(polyfillHostNoCombinator,d),a.replace(polyfillHostRe,d+" ")):d+" "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim().replace(polyfillHostRe,"");return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},insertPolyfillHostInCssText:function(a){return a.replace(hostRe,l).replace(colonHostRe,l).replace(colonAncestorRe,m)},propertiesFromRule:function(a){return a.style.content&&!a.style.content.match(/['"]+/)?a.style.cssText.replace(/content:[^;]*;/g,"content: '"+a.style.content+"';"):a.style.cssText}},h=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,i=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,j=/\/\*\s@polyfill-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,k=/\/\*\s@polyfill-unscoped-rule([^*]*\*+([^/*][^*]*\*+)*)\//gim,l="-shadowcsshost",m="-shadowcssancestor",n=")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)";cssColonHostRe=new RegExp("("+l+n,"gim"),cssColonAncestorRe=new RegExp("("+m+n,"gim"),selectorReSuffix="([>\\s~+[.,{:][\\s\\S]*)?$",hostRe=/@host/gim,colonHostRe=/\:host/gim,colonAncestorRe=/\:ancestor/gim,polyfillHostNoCombinator=l+"-no-combinator",polyfillHostRe=new RegExp(l,"gim"),polyfillAncestorRe=new RegExp(m,"gim");var o,p="shim-shadowdom",q="shim-shadowdom-css";if(window.ShadowDOMPolyfill){e("style { display: none !important; }\n");var r=wrap(document),s=r.querySelector("head");s.insertBefore(f(),s.childNodes[0]),document.addEventListener("DOMContentLoaded",function(){var b=a.urlResolver;if(window.HTMLImports&&!HTMLImports.useNative){var c="link[rel=stylesheet]["+p+"]",d="style["+p+"]";HTMLImports.importer.documentPreloadSelectors+=","+c,HTMLImports.importer.importsPreloadSelectors+=","+c,HTMLImports.parser.documentSelectors=[HTMLImports.parser.documentSelectors,c,d].join(",");var e=HTMLImports.parser.parseGeneric;HTMLImports.parser.parseGeneric=function(a){if(!a[q]){var c=a.__importElement||a;if(!c.hasAttribute(p))return void e.call(this,a);a.__resource?(c=a.ownerDocument.createElement("style"),c.textContent=b.resolveCssText(a.__resource,a.href)):b.resolveStyle(c);var d=[c];c.textContent=g.stylesToShimmedCssText(d,d),c.removeAttribute(p,""),c.setAttribute(q,""),c[q]=!0,c.parentNode!==s&&(a.parentNode===s?s.replaceChild(c,a):s.appendChild(c)),c.__importParsed=!0,this.markParsingComplete(a)}};var f=HTMLImports.parser.hasResource;HTMLImports.parser.hasResource=function(a){return"link"===a.localName&&"stylesheet"===a.rel&&a.hasAttribute(p)?a.__resource:f.call(this,a)}}})}a.ShadowCSS=g}(window.Platform)):!function(){window.templateContent=window.templateContent||function(a){return a.content},window.wrap=window.unwrap=function(a){return a};var a=Element.prototype.webkitCreateShadowRoot;Element.prototype.webkitCreateShadowRoot=function(){var b=this.webkitShadowRoot,c=a.call(this);return c.olderShadowRoot=b,c.host=this,CustomElements.watchShadow(this),c},Object.defineProperties(Element.prototype,{shadowRoot:{get:function(){return this.webkitShadowRoot}},createShadowRoot:{value:function(){return this.webkitCreateShadowRoot()}}}),window.templateContent=function(a){if(window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(a),!a.content&&!a._content){for(var b=document.createDocumentFragment();a.firstChild;)b.appendChild(a.firstChild);a._content=b}return a.content||a._content}}(),function(a){"use strict";function b(a){return void 0!==m[a]}function c(){h.call(this),this._isInvalid=!0}function d(a){return""==a&&c.call(this),a.toLowerCase()}function e(a){var b=a.charCodeAt(0);return b>32&&127>b&&-1==[34,35,60,62,63,96].indexOf(b)?a:encodeURIComponent(a)}function f(a){var b=a.charCodeAt(0);return b>32&&127>b&&-1==[34,35,60,62,96].indexOf(b)?a:encodeURIComponent(a)}function g(a,g,h){function i(a){t.push(a)}var j=g||"scheme start",k=0,l="",r=!1,s=!1,t=[];a:for(;(a[k-1]!=o||0==k)&&!this._isInvalid;){var u=a[k];switch(j){case"scheme start":if(!u||!p.test(u)){if(g){i("Invalid scheme.");break a}l="",j="no scheme";continue}l+=u.toLowerCase(),j="scheme";break;case"scheme":if(u&&q.test(u))l+=u.toLowerCase();else{if(":"!=u){if(g){if(o==u)break a;i("Code point not allowed in scheme: "+u);break a}l="",k=0,j="no scheme";continue}if(this._scheme=l,l="",g)break a;b(this._scheme)&&(this._isRelative=!0),j="file"==this._scheme?"relative":this._isRelative&&h&&h._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==u?(query="?",j="query"):"#"==u?(this._fragment="#",j="fragment"):o!=u&&" "!=u&&"\n"!=u&&"\r"!=u&&(this._schemeData+=e(u));break;case"no scheme":if(h&&b(h._scheme)){j="relative";continue}i("Missing scheme."),c.call(this);break;case"relative or authority":if("/"!=u||"/"!=a[k+1]){i("Expected /, got: "+u),j="relative";continue}j="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=h._scheme),o==u){this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query=h._query;break a}if("/"==u||"\\"==u)"\\"==u&&i("\\ is an invalid code point."),j="relative slash";else if("?"==u)this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query="?",j="query";else{if("#"!=u){var v=a[k+1],w=a[k+2];("file"!=this._scheme||!p.test(u)||":"!=v&&"|"!=v||o!=w&&"/"!=w&&"\\"!=w&&"?"!=w&&"#"!=w)&&(this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._path.pop()),j="relative path";continue}this._host=h._host,this._port=h._port,this._path=h._path.slice(),this._query=h._query,this._fragment="#",j="fragment"}break;case"relative slash":if("/"!=u&&"\\"!=u){"file"!=this._scheme&&(this._host=h._host,this._port=h._port),j="relative path";continue}"\\"==u&&i("\\ is an invalid code point."),j="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=u){i("Expected '/', got: "+u),j="authority ignore slashes";continue}j="authority second slash";break;case"authority second slash":if(j="authority ignore slashes","/"!=u){i("Expected '/', got: "+u);continue}break;case"authority ignore slashes":if("/"!=u&&"\\"!=u){j="authority";continue}i("Expected authority, got: "+u);break;case"authority":if("@"==u){r&&(i("@ already seen."),l+="%40"),r=!0;for(var x=0;x')})}),a.createDOM=b}(window.Platform),window.templateContent=window.templateContent||function(a){return a.content},function(a){a=a||(window.Inspector={});var b;window.sinspect=function(a,d){b||(b=window.open("","ShadowDOM Inspector",null,!0),b.document.write(c),b.api={shadowize:shadowize}),f(a||wrap(document.body),d)};var c=["",""," "," ShadowDOM Inspector"," "," "," ",'
    ',"
",'
'," ",""].join("\n"),d=[],e=function(){var a=b.document,c=a.querySelector("#crumbs");c.textContent="";for(var e,g=0;e=d[g];g++){var h=a.createElement("a");h.href="#",h.textContent=e.localName,h.idx=g,h.onclick=function(a){for(var b;d.length>this.idx;)b=d.pop();f(b.shadow||b,b),a.preventDefault()},c.appendChild(a.createElement("li")).appendChild(h)}},f=function(a,c){var f=b.document;k=[];var g=c||a;d.push(g),e(),f.body.querySelector("#tree").innerHTML="
"+j(a,a.childNodes)+"
"},g=Array.prototype.forEach.call.bind(Array.prototype.forEach),h={STYLE:1,SCRIPT:1,"#comment":1,TEMPLATE:1},i=function(a){return h[a.nodeName]},j=function(a,b,c){if(i(a))return"";var d=c||"";if(a.localName||11==a.nodeType){var e=a.localName||"shadow-root",f=d+l(a);"content"==e&&(b=a.getDistributedNodes()),f+="
";var h=d+"  ";g(b,function(a){f+=j(a,a.childNodes,h)}),f+=d,{br:1}[e]||(f+="</"+e+">",f+="
")}else{var k=a.textContent.trim();f=k?d+'"'+k+'"
':""}return f},k=[],l=function(a){var b="<",c=a.localName||"shadow-root";return a.webkitShadowRoot||a.shadowRoot?(b+=' ",k.push(a)):b+=c||"shadow-root",a.attributes&&g(a.attributes,function(a){b+=" "+a.name+(a.value?'="'+a.value+'"':"")}),b+=">"};shadowize=function(){var a=Number(this.attributes.idx.value),b=k[a];b?f(b.webkitShadowRoot||b.shadowRoot,b):(console.log("bad shadowize node"),console.dir(this))},a.output=j}(window.Inspector),function(){var a=document.createElement("style");a.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; } \n";var b=document.querySelector("head");b.insertBefore(a,b.firstChild)}(Platform),function(a){function b(a,b){return b=b||[],b.map||(b=[b]),a.apply(this,b.map(d))}function c(a,c,d){var e;switch(arguments.length){case 0:return;case 1:e=null;break;case 2:e=c.apply(this);break;default:e=b(d,c)}f[a]=e}function d(a){return f[a]}function e(a,c){HTMLImports.whenImportsReady(function(){b(c,a)})}var f={};a.marshal=d,a.module=c,a.using=e}(window),function(a){function b(a){f.textContent=d++,e.push(a)}function c(){for(;e.length;)e.shift()()}var d=0,e=[],f=document.createTextNode("");new(window.MutationObserver||JsMutationObserver)(c).observe(f,{characterData:!0}),a.endOfMicrotask=b}(Platform),function(a){function b(a,b,d){return a.replace(d,function(a,d,e,f){var g=e.replace(/["']/g,"");return g=c(b,g),d+"'"+g+"'"+f})}function c(a,b){var c=new URL(b,a);return d(c.href)}function d(a){var b=document.baseURI,c=new URL(a,b);return c.host===b.host&&c.port===b.port&&c.protocol===b.protocol?e(b.pathname,c.pathname):a}function e(a,b){for(var c=a.split("/"),d=b.split("/");c.length&&c[0]===d[0];)c.shift(),d.shift();for(var e=0,f=c.length-1;f>e;e++)d.unshift("..");return d.join("/")}var f={resolveDom:function(a,b){b=b||a.ownerDocument.baseURI,this.resolveAttributes(a,b),this.resolveStyles(a,b);var c=a.querySelectorAll("template");if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)d.content&&this.resolveDom(d.content,b)},resolveStyles:function(a,b){var c=a.querySelectorAll("style");if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveStyle(d,b)},resolveStyle:function(a,b){b=b||a.ownerDocument.baseURI,a.textContent=this.resolveCssText(a.textContent,b)},resolveCssText:function(a,c){return a=b(a,c,g),b(a,c,h)},resolveAttributes:function(a,b){a.hasAttributes&&a.hasAttributes()&&this.resolveElementAttributes(a,b);var c=a&&a.querySelectorAll(j);if(c)for(var d,e=0,f=c.length;f>e&&(d=c[e]);e++)this.resolveElementAttributes(d,b)},resolveElementAttributes:function(a,b){b=b||a.ownerDocument.baseURI,i.forEach(function(d){var e=a.attributes[d];if(e&&e.value&&e.value.search(k)<0){var f=c(b,e.value);e.value=f}})}},g=/(url\()([^)]*)(\))/g,h=/(@import[\s]+(?!url\())([^;]*)(;)/g,i=["href","src","action"],j="["+i.join("],[")+"]",k="{{.*}}";a.urlResolver=f}(Platform),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a -}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e0){var e=c[d-1],f=n(e,a);if(f)return void(c[d-1]=f)}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;cc&&(b=a[c]);c++)this.require(b);this.checkDone()},addNode:function(a){this.inflight++,this.require(a),this.checkDone()},require:function(a){var b=a.src||a.href;a.__nodeUrl=b,this.dedupe(b,a)||this.fetch(b,a)},dedupe:function(a,b){if(this.pending[a])return this.pending[a].push(b),!0;return this.cache[a]?(this.onload(a,b,this.cache[a]),this.tail(),!0):(this.pending[a]=[b],!1)},fetch:function(a,d){c.load&&console.log("fetch",a,d);var e=function(b,c){this.receive(a,d,b,c)}.bind(this);b.load(a,e)},receive:function(a,b,c,d){this.cache[a]=d;for(var e,f=this.pending[a],g=0,h=f.length;h>g&&(e=f[g]);g++)this.onload(a,e,d),this.tail();this.pending[a]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},b=b||{async:!0,ok:function(a){return a.status>=200&&a.status<300||304===a.status||0===a.status},load:function(c,d,e){var f=new XMLHttpRequest;return(a.flags.debug||a.flags.bust)&&(c+="?"+Math.random()),f.open("GET",c,b.async),f.addEventListener("readystatechange",function(){4===f.readyState&&d.call(e,!b.ok(f)&&f,f.response||f.responseText,c)}),f.send(),f},loadDocument:function(a,b,c){this.load(a,b,c).responseType="document"}},a.xhr=b,a.Loader=d}(window.HTMLImports),function(a){function b(a){return"link"===a.localName&&a.rel===d}function c(a){var b=a.ownerDocument.createElement("style");return b.textContent=a.textContent,k.resolveUrlsInStyle(b),b}var d="import",e=a.flags,f=/Trident/.test(navigator.userAgent),g=window.ShadowDOMPolyfill?window.ShadowDOMPolyfill.wrapIfNeeded(document):document,h={documentSelectors:"link[rel="+d+"]",importsSelectors:["link[rel="+d+"]","link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},parseNext:function(){var a=this.nextToParse();a&&this.parse(a)},parse:function(a){if(this.isParsed(a))return void(e.parse&&console.log("[%s] is already parsed",a.localName));var b=this[this.map[a.localName]];b&&(this.markParsing(a),b.call(this,a))},markParsing:function(a){e.parse&&console.log("parsing",a),this.parsingElement=a},markParsingComplete:function(a){a.__importParsed=!0,a.__importElement&&(a.__importElement.__importParsed=!0),this.parsingElement=null,e.parse&&console.log("completed",a),this.parseNext()},parseImport:function(a){if(a.import.__importParsed=!0,HTMLImports.__importsParsingHook&&HTMLImports.__importsParsingHook(a),a.dispatchEvent(a.__resource?new CustomEvent("load",{bubbles:!1}):new CustomEvent("error",{bubbles:!1})),a.__pending)for(var b;a.__pending.length;)b=a.__pending.shift(),b&&b({target:a});this.markParsingComplete(a)},parseLink:function(a){b(a)?this.parseImport(a):(a.href=a.href,this.parseGeneric(a))},parseStyle:function(a){var b=a;a=c(a),a.__importElement=b,this.parseGeneric(a)},parseGeneric:function(a){this.trackElement(a),document.head.appendChild(a)},trackElement:function(a){var b=this,c=function(){b.markParsingComplete(a)};if(a.addEventListener("load",c),a.addEventListener("error",c),f&&"style"===a.localName){var d=!1;if(-1==a.textContent.indexOf("@import"))d=!0;else if(a.sheet){d=!0;for(var e,g=a.sheet.cssRules,h=g?g.length:0,i=0;h>i&&(e=g[i]);i++)e.type===CSSRule.IMPORT_RULE&&(d=d&&Boolean(e.styleSheet))}d&&a.dispatchEvent(new CustomEvent("load",{bubbles:!1}))}},parseScript:function(b){var c=(b.__resource||b.textContent).trim();if(c){var d=b.__nodeUrl;if(!d){d=b.ownerDocument.baseURI;var e="["+Math.floor(1e3*(Math.random()+1))+"]",f=c.match(/Polymer\(['"]([^'"]*)/);e=f&&f[1]||e,d+="/"+e+".js"}c+="\n//# sourceURL="+d+"\n",a.currentScript=b,eval.call(window,c),a.currentScript=null}this.markParsingComplete(b)},nextToParse:function(){return!this.parsingElement&&this.nextToParseInDoc(g)},nextToParseInDoc:function(a,c){for(var d,e=a.querySelectorAll(this.parseSelectorsForNode(a)),f=0,g=e.length;g>f&&(d=e[f]);f++)if(!this.isParsed(d))return this.hasResource(d)?b(d)?this.nextToParseInDoc(d.import,d):d:void 0;return c},parseSelectorsForNode:function(a){var b=a.ownerDocument||a;return b===g?this.documentSelectors:this.importsSelectors},isParsed:function(a){return a.__importParsed},hasResource:function(a){return b(a)&&!a.import?!1:"script"===a.localName&&a.src&&!a.__resource?!1:!0}},i=/(url\()([^)]*)(\))/g,j=/(@import[\s]+(?!url\())([^;]*)(;)/g,k={resolveUrlsInStyle:function(a){var b=a.ownerDocument,c=b.createElement("a");return a.textContent=this.resolveUrlsInCssText(a.textContent,c),a},resolveUrlsInCssText:function(a,b){var c=this.replaceUrls(a,b,i);return c=this.replaceUrls(c,b,j)},replaceUrls:function(a,b,c){return a.replace(c,function(a,c,d,e){var f=d.replace(/["']/g,"");return b.href=f,f=b.href,c+"'"+f+"'"+e})}};a.parser=h,a.path=k,a.isIE=f}(HTMLImports),function(a){function b(a){return c(a,m)}function c(a,b){return"link"===a.localName&&a.getAttribute("rel")===b}function d(a,b){var c=a;c instanceof Document||(c=document.implementation.createHTMLDocument(m)),c._URL=b;var d=c.createElement("base");d.setAttribute("href",b),c.baseURI||(c.baseURI=b);var e=c.createElement("meta");return e.setAttribute("charset","utf-8"),c.head.appendChild(e),c.head.appendChild(d),a instanceof Document||(c.body.innerHTML=a),window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(c),c}function e(a,b){b=b||n,g(function(){h(a,b)},b)}function f(a){return"complete"===a.readyState||a.readyState===u}function g(a,b){if(f(b))a&&a();else{var c=function(){("complete"===b.readyState||b.readyState===u)&&(b.removeEventListener(v,c),g(a,b))};b.addEventListener(v,c)}}function h(a,b){function c(){f==g&&requestAnimationFrame(a)}function d(){f++,c()}var e=b.querySelectorAll("link[rel=import]"),f=0,g=e.length;if(g)for(var h,j=0;g>j&&(h=e[j]);j++)i(h)?d.call(h):(h.addEventListener("load",d),h.addEventListener("error",d));else c()}function i(a){return k?a.import&&"loading"!==a.import.readyState:a.__importParsed}var j="import"in document.createElement("link"),k=j,l=a.flags,m="import",n=window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(document):document;if(k)var o={};else var p=(a.xhr,a.Loader),q=a.parser,o={documents:{},documentPreloadSelectors:"link[rel="+m+"]",importsPreloadSelectors:["link[rel="+m+"]","script[src]:not([type])",'script[src][type="text/javascript"]'].join(","),loadNode:function(a){r.addNode(a)},loadSubtree:function(a){var b=this.marshalNodes(a);r.addNodes(b)},marshalNodes:function(a){return a.querySelectorAll(this.loadSelectorsForNode(a))},loadSelectorsForNode:function(a){var b=a.ownerDocument||a;return b===n?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(a,c,e){if(l.load&&console.log("loaded",a,c),c.__resource=e,b(c)){var f=this.documents[a];f||(f=d(e,a),f.__importLink=c,this.bootDocument(f),this.documents[a]=f),c.import=f}q.parseNext()},bootDocument:function(a){this.loadSubtree(a),this.observe(a),q.parseNext()},loadedAll:function(){q.parseNext()}},r=new p(o.loaded.bind(o),o.loadedAll.bind(o));var s={get:function(){return HTMLImports.currentScript||document.currentScript},configurable:!0};if(Object.defineProperty(document,"_currentScript",s),Object.defineProperty(n,"_currentScript",s),!document.baseURI){var t={get:function(){return window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",t),Object.defineProperty(n,"baseURI",t)}var u=HTMLImports.isIE?"complete":"interactive",v="readystatechange";a.hasNative=j,a.useNative=k,a.importer=o,a.whenImportsReady=e,a.IMPORT_LINK_TYPE=m,a.isImportLoaded=i,a.importLoader=r}(window.HTMLImports),function(a){function b(a){for(var b,d=0,e=a.length;e>d&&(b=a[d]);d++)"childList"===b.type&&b.addedNodes.length&&c(b.addedNodes)}function c(a){for(var b,e=0,g=a.length;g>e&&(b=a[e]);e++)d(b)&&f.loadNode(b),b.children&&b.children.length&&c(b.children)}function d(a){return 1===a.nodeType&&g.call(a,f.loadSelectorsForNode(a))}function e(a){h.observe(a,{childList:!0,subtree:!0})}var f=(a.IMPORT_LINK_TYPE,a.importer),g=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector,h=new MutationObserver(b);a.observe=e,f.observe=e}(HTMLImports),function(){function a(){HTMLImports.importer.bootDocument(b)}"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a,b){var c=document.createEvent("HTMLEvents");return c.initEvent(a,b.bubbles===!1?!1:!0,b.cancelable===!1?!1:!0,b.detail),c});var b=window.ShadowDOMPolyfill?window.ShadowDOMPolyfill.wrapIfNeeded(document):document;HTMLImports.whenImportsReady(function(){HTMLImports.ready=!0,HTMLImports.readyTime=(new Date).getTime(),b.dispatchEvent(new CustomEvent("HTMLImportsLoaded",{bubbles:!0}))}),HTMLImports.useNative||("complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?a():document.addEventListener("DOMContentLoaded",a))}(),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:void c(a,d)}),c(a,d)}function e(a){return h(a)?(i(a),!0):void l(a)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return A.dom&&console.group("upgrade:",b.localName),a.upgrade(b),A.dom&&console.groupEnd(),!0}}function i(a){l(a),r(a)&&d(a,function(a){l(a)})}function j(a){if(E.push(a),!D){D=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){D=!1;for(var a,b=E,c=0,d=b.length;d>c&&(a=b[c]);c++)a();E=[]}function l(a){C?j(function(){m(a)}):m(a)}function m(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("inserted:",a.localName),r(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?A.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.attachedCallback&&(A.dom&&console.log("inserted:",a.localName),a.attachedCallback())),A.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){C?j(function(){p(a)}):p(a)}function p(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("removed:",a.localName),r(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?A.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.detachedCallback&&a.detachedCallback()),A.dom&&console.groupEnd())}function q(a){return window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(a):a}function r(a){for(var b=a,c=q(document);b;){if(b==c)return!0;b=b.parentNode||b.host}}function s(a){if(a.shadowRoot&&!a.shadowRoot.__watched){A.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)t(b),b=b.olderShadowRoot}}function t(a){a.__watched||(w(a),a.__watched=!0)}function u(a){if(A.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(G(a.addedNodes,function(a){a.localName&&g(a)}),G(a.removedNodes,function(a){a.localName&&n(a)}))}),A.dom&&console.groupEnd()}function v(){u(F.takeRecords()),k()}function w(a){F.observe(a,{childList:!0,subtree:!0})}function x(a){w(a)}function y(a){A.dom&&console.group("upgradeDocument: ",a.baseURI.split("/").pop()),g(a),A.dom&&console.groupEnd()}function z(a){a=q(a),y(a);for(var b,c=a.querySelectorAll("link[rel="+B+"]"),d=0,e=c.length;e>d&&(b=c[d]);d++)b.import&&b.import.__parsed&&z(b.import)}var A=window.logFlags||{},B=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",C=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=C;var D=!1,E=[],F=new MutationObserver(u),G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.IMPORT_LINK_TYPE=B,a.watchShadow=s,a.upgradeDocumentTree=z,a.upgradeAll=g,a.upgradeSubtree=f,a.insertedNode=i,a.observeDocument=x,a.upgradeDocument=y,a.takeRecords=v}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.registerElement: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.__name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.__name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeDocumentTree(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.__name,c&&(a.is=a.__name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,j(b),a.insertedNode(b),a.upgradeSubtree(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=m(b||a.localName);if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.registerElement),u=!s.register&&t&&!window.ShadowDOMPolyfill;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.upgradeDocumentTree=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.registerElement=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}document.register=document.registerElement,a.hasNative=t,a.useNative=u}(window.CustomElements),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===c}var c=a.IMPORT_LINK_TYPE,d={selectors:["link[rel="+c+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(d.selectors);e(b,function(a){d[d.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(a){b(a)&&this.parseImport(a)},parseImport:function(a){a.import&&d.parse(a.import)}},e=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=d,a.IMPORT_LINK_TYPE=c}(window.CustomElements),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document);var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0})),window.HTMLImports&&(HTMLImports.__importsParsingHook=function(a){CustomElements.parser.parse(a.import)})})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){var a=document.createElement("style");a.textContent="element {display: none !important;} /* injected by platform.js */";var b=document.querySelector("head");if(b.insertBefore(a,b.firstChild),window.ShadowDOMPolyfill){var c=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],d={};c.forEach(function(a){d[a]=CustomElements[a]}),c.forEach(function(a){CustomElements[a]=function(b){return d[a](wrap(b))}})}}(),function(a){function b(a){this.regex=a}var c=a.endOfMicrotask;b.prototype={extractUrls:function(a,b){for(var c,d,e=[];c=this.regex.exec(a);)d=new URL(c[1],b),e.push({matched:c[0],url:d.href});return e},process:function(a,b,c){var d=this.extractUrls(a,b);this.fetch(d,{},c)},fetch:function(a,b,d){var e=a.length;if(!e)return d(b);for(var f,g,h,i=function(){0===--e&&d(b)},j=function(a,c){var d=c.match,e=d.url;if(a)return b[e]="",i();var f=c.response||c.responseText;b[e]=f,this.fetch(this.extractUrls(f,e),b,i)},k=0;e>k;k++)f=a[k],h=f.url,b[h]?c(i):(g=this.xhr(h,j,this),g.match=f,b[h]=g)},xhr:function(a,b,c){var d=new XMLHttpRequest;return d.open("GET",a,!0),d.send(),d.onload=function(){b.call(c,null,d)},d.onerror=function(){b.call(c,d,null)},d}},a.Loader=b}(window.Platform),function(a){function b(){this.loader=new f(this.regex)}function c(a,b){var c=d(a);b&&(c.addEventListener("load",b),c.addEventListener("error",b)),j.appendChild(c)}function d(a,b){b=b||document,b=b.createElement?b:b.ownerDocument;var c=b.createElement("style");return c.textContent=a,c}var e=a.urlResolver,f=a.Loader;b.prototype={regex:/@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g,resolve:function(a,b,c){var d=function(d){c(this.flatten(a,b,d))}.bind(this);this.loader.process(a,b,d)},resolveNode:function(a,b){var c=a.textContent,d=a.ownerDocument.baseURI,e=function(c){a.textContent=c,b(a)};this.resolve(c,d,e)},flatten:function(a,b,c){for(var d,f,g,h=this.loader.extractUrls(a,b),i=0;if&&(d=a[f]);f++)e.push(d.textContent);c(e.join("\n"),b)},xhrStyles:function(a,b){function c(){e++,e===f&&b&&b()}for(var d,e=0,f=a.length,h=0;f>h&&(d=a[h]);h++)g.resolveNode(d,c)}},i=document.createElement("preloader");i.style.display="none";var j=i.createShadowRoot();document.head.appendChild(i),a.loader=h,a.styleResolver=g}(window.Platform),function(a){a=a||{},a.external=a.external||{};var b={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);return this.canTarget(b)?b:void 0},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){if(a){var d,e,f=a.elementFromPoint(b,c);for(e=this.targetingShadow(f);e;){if(d=e.elementFromPoint(b,c)){var g=this.targetingShadow(d);return this.searchRoot(g,b,c)||d}e=this.olderShadow(e)}return f}},owner:function(a){for(var b=a;b.parentNode;)b=b.parentNode;return b.nodeType!=Node.DOCUMENT_NODE&&b.nodeType!=Node.DOCUMENT_FRAGMENT_NODE&&(b=document),b},findTarget:function(a){var b=a.clientX,c=a.clientY,d=this.owner(a.target);return d.elementFromPoint(b,c)||(d=document),this.searchRoot(d,b,c)}};a.targetFinding=b,a.findTarget=b.findTarget.bind(b),window.PointerEventsPolyfill=a}(window.PointerEventsPolyfill),function(){function a(a){return"body ^^ "+b(a)}function b(a){return'[touch-action="'+a+'"]'}function c(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+"; touch-action-delay: none; }"}var d=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]}],e="";d.forEach(function(d){String(d)===d?(e+=b(d)+c(d)+"\n",e+=a(d)+c(d)+"\n"):(e+=d.selectors.map(b)+c(d.rule)+"\n",e+=d.selectors.map(a)+c(d.rule)+"\n")});var f=document.createElement("style");f.textContent=e,document.head.appendChild(f)}(),function(a){function b(a,e){e=e||{};var f;if(e.buttons||d)f=e.buttons;else switch(e.which){case 1:f=1;break;case 2:f=4;break;case 3:f=2;break;default:f=0}var i;if(c)i=new MouseEvent(a,e);else{i=document.createEvent("MouseEvent");for(var j,k={},l=0;l-1?this.values[c]=b:(this.keys.push(a),this.values.push(b))},has:function(a){return this.keys.indexOf(a)>-1},"delete":function(a){var b=this.keys.indexOf(a);b>-1&&(this.keys.splice(b,1),this.values.splice(b,1))},get:function(a){var b=this.keys.indexOf(a);return this.values[b]},clear:function(){this.keys.length=0,this.values.length=0},forEach:function(a,b){this.values.forEach(function(c,d){a.call(b,c,this.keys[d],this)},this)},pointers:function(){return this.keys.length}},a.PointerMap=b}(window.PointerEventsPolyfill),function(a){var b=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","which"],c=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0],d="undefined"!=typeof SVGElementInstance,e={targets:new WeakMap,handledEvents:new WeakMap,pointermap:new a.PointerMap,eventMap:{},eventSources:{},eventSourceList:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},register:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.register.call(b,a)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.unregister.call(b,a)},contains:a.external.contains||function(a,b){return a.contains(b)},down:function(a){a.bubbles=!0,this.fireEvent("pointerdown",a)},move:function(a){a.bubbles=!0,this.fireEvent("pointermove",a)},up:function(a){a.bubbles=!0,this.fireEvent("pointerup",a)},enter:function(a){a.bubbles=!1,this.fireEvent("pointerenter",a)},leave:function(a){a.bubbles=!1,this.fireEvent("pointerleave",a)},over:function(a){a.bubbles=!0,this.fireEvent("pointerover",a)},out:function(a){a.bubbles=!0,this.fireEvent("pointerout",a)},cancel:function(a){a.bubbles=!0,this.fireEvent("pointercancel",a)},leaveOut:function(a){this.out(a),this.contains(a.target,a.relatedTarget)||this.leave(a)},enterOver:function(a){this.over(a),this.contains(a.target,a.relatedTarget)||this.enter(a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b=a.type,c=this.eventMap&&this.eventMap[b];c&&c(a),this.handledEvents.set(a,!0)}},listen:function(a,b){b.forEach(function(b){this.addEvent(a,b)},this)},unlisten:function(a,b){b.forEach(function(b){this.removeEvent(a,b)},this)},addEvent:a.external.addEvent||function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:a.external.removeEvent||function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(a,b){this.captureInfo&&(b.relatedTarget=null);var c=new PointerEvent(a,b);return b.preventDefault&&(c.preventDefault=b.preventDefault),this.targets.set(c,this.targets.get(b)||b.target),c},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){for(var e,f={},g=0;gg&&(b=c[g]);g++){var i=Math.abs(e-b.x),j=Math.abs(f-b.y);if(d>=i&&d>=j)return!0}},prepareEvent:function(a){var c=b.cloneEvent(a),d=c.preventDefault;return c.preventDefault=function(){a.preventDefault(),d()},c.pointerId=this.POINTER_ID,c.isPrimary=!0,c.pointerType=this.POINTER_TYPE,c},mousedown:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.has(this.POINTER_ID);d&&this.cancel(a);var e=this.prepareEvent(a);c.set(this.POINTER_ID,a),b.down(e)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.move(c)}},mouseup:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.get(this.POINTER_ID);if(d&&d.button===a.button){var e=this.prepareEvent(a);b.up(e),this.cleanupMouse()}}},mouseover:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.enterOver(c)}},mouseout:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.leaveOut(c)}},cancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanupMouse()},cleanupMouse:function(){c["delete"](this.POINTER_ID)}};a.mouseEvents=e}(window.PointerEventsPolyfill),function(a){var b,c=a.dispatcher,d=a.findTarget,e=a.targetFinding.allShadows.bind(a.targetFinding),f=c.pointermap,g=Array.prototype.map.call.bind(Array.prototype.map),h=2500,i=200,j="touch-action",k=!1,l={scrollType:new WeakMap,events:["touchstart","touchmove","touchend","touchcancel"],register:function(a){k?c.listen(a,this.events):b.enableOnSubtree(a)},unregister:function(a){k&&c.unlisten(a,this.events)},elementAdded:function(a){var b=a.getAttribute(j),d=this.touchActionToScrollType(b);d&&(this.scrollType.set(a,d),c.listen(a,this.events),e(a).forEach(function(a){this.scrollType.set(a,d),c.listen(a,this.events)},this))},elementRemoved:function(a){this.scrollType["delete"](a),c.unlisten(a,this.events),e(a).forEach(function(a){this.scrollType["delete"](a),c.unlisten(a,this.events)},this)},elementChanged:function(a,b){var c=a.getAttribute(j),d=this.touchActionToScrollType(c),f=this.touchActionToScrollType(b);d&&f?(this.scrollType.set(a,d),e(a).forEach(function(a){this.scrollType.set(a,d)},this)):f?this.elementRemoved(a):d&&this.elementAdded(a)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y",SCROLLER:/^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return"none"===b?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":c.SCROLLER.exec(b)?"XY":void 0},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){(0===f.pointers()||1===f.pointers()&&f.has(1))&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=!1,this.cancelResetClickCount())},removePrimaryPointer:function(a){a.isPrimary&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,i)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},touchToPointer:function(a){var b=c.cloneEvent(a);return b.pointerId=a.identifier+2,b.target=d(b),b.bubbles=!0,b.cancelable=!0,b.detail=this.clickCount,b.button=0,b.buttons=1,b.width=a.webkitRadiusX||a.radiusX||0,b.height=a.webkitRadiusY||a.radiusY||0,b.pressure=a.webkitForce||a.force||.5,b.isPrimary=this.isPrimaryTouch(a),b.pointerType=this.POINTER_TYPE,b},processTouches:function(a,b){var c=a.changedTouches,d=g(c,this.touchToPointer,this);d.forEach(function(b){b.preventDefault=function(){this.scrolling=!1,this.firstXY=null,a.preventDefault()}},this),d.forEach(b,this)},shouldScroll:function(a){if(this.firstXY){var b,c=this.scrollType.get(a.currentTarget);if("none"===c)b=!1;else if("XY"===c)b=!0;else{var d=a.changedTouches[0],e=c,f="Y"===c?"X":"Y",g=Math.abs(d["client"+e]-this.firstXY[e]),h=Math.abs(d["client"+f]-this.firstXY[f]);b=g>=h}return this.firstXY=null,b}},findTouch:function(a,b){for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)if(c.identifier===b)return!0},vacuumTouches:function(a){var b=a.touches;if(f.pointers()>=b.length){var c=[];f.forEach(function(a,d){if(1!==d&&!this.findTouch(b,d-2)){var e=a.out;c.push(this.touchToPointer(e))}},this),c.forEach(this.cancelOut,this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.overDown))},overDown:function(a){f.set(a.pointerId,{target:a.target,out:a,outTarget:a.target});c.over(a),c.enter(a),c.down(a)},touchmove:function(a){this.scrolling||(this.shouldScroll(a)?(this.scrolling=!0,this.touchcancel(a)):(a.preventDefault(),this.processTouches(a,this.moveOverOut)))},moveOverOut:function(a){var b=a,d=f.get(b.pointerId);if(d){var e=d.out,g=d.outTarget;c.move(b),e&&g!==b.target&&(e.relatedTarget=b.target,b.relatedTarget=g,e.target=g,b.target?(c.leaveOut(e),c.enterOver(b)):(b.target=g,b.relatedTarget=null,this.cancelOut(b))),d.out=b,d.outTarget=b.target}},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.upOut)},upOut:function(a){this.scrolling||(c.up(a),c.out(a),c.leave(a)),this.cleanUpPointer(a)},touchcancel:function(a){this.processTouches(a,this.cancelOut)},cancelOut:function(a){c.cancel(a),c.out(a),c.leave(a),this.cleanUpPointer(a)},cleanUpPointer:function(a){f["delete"](a.pointerId),this.removePrimaryPointer(a)},dedupSynthMouse:function(b){var c=a.mouseEvents.lastTouches,d=b.changedTouches[0];if(this.isPrimaryTouch(d)){var e={x:d.clientX,y:d.clientY};c.push(e);var f=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,c,e);setTimeout(f,h)}}};k||(b=new a.Installer(l.elementAdded,l.elementRemoved,l.elementChanged,l)),a.touchEvents=l}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher,c=b.pointermap,d=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,e={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerOut","MSPointerOver","MSPointerCancel","MSGotPointerCapture","MSLostPointerCapture"],register:function(a){b.listen(a,this.events)},unregister:function(a){b.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var c=a;return d&&(c=b.cloneEvent(a),c.pointerType=this.POINTER_TYPES[a.pointerType]),c},cleanup:function(a){c["delete"](a)},MSPointerDown:function(a){c.set(a.pointerId,a);var d=this.prepareEvent(a);b.down(d)},MSPointerMove:function(a){var c=this.prepareEvent(a);b.move(c)},MSPointerUp:function(a){var c=this.prepareEvent(a);b.up(c),this.cleanup(a.pointerId)},MSPointerOut:function(a){var c=this.prepareEvent(a);b.leaveOut(c)},MSPointerOver:function(a){var c=this.prepareEvent(a);b.enterOver(c)},MSPointerCancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanup(a.pointerId)},MSLostPointerCapture:function(a){var c=b.makeEvent("lostpointercapture",a);b.dispatchEvent(c)},MSGotPointerCapture:function(a){var c=b.makeEvent("gotpointercapture",a);b.dispatchEvent(c)}};a.msEvents=e}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher;if(void 0===window.navigator.pointerEnabled){if(Object.defineProperty(window.navigator,"pointerEnabled",{value:!0,enumerable:!0}),window.navigator.msPointerEnabled){var c=window.navigator.msMaxTouchPoints;Object.defineProperty(window.navigator,"maxTouchPoints",{value:c,enumerable:!0}),b.registerSource("ms",a.msEvents)}else b.registerSource("mouse",a.mouseEvents),void 0!==window.ontouchstart&&b.registerSource("touch",a.touchEvents);b.register(document)}}(window.PointerEventsPolyfill),function(a){function b(a){if(!e.pointermap.has(a))throw new Error("InvalidPointerId")}var c,d,e=a.dispatcher,f=window.navigator;f.msPointerEnabled?(c=function(a){b(a),this.msSetPointerCapture(a)},d=function(a){b(a),this.msReleasePointerCapture(a)}):(c=function(a){b(a),e.setCapture(a,this)},d=function(a){b(a),e.releaseCapture(a,this)}),window.Element&&!Element.prototype.setPointerCapture&&Object.defineProperties(Element.prototype,{setPointerCapture:{value:c},releasePointerCapture:{value:d}})}(window.PointerEventsPolyfill),PointerGestureEvent.prototype.preventTap=function(){this.tapPrevented=!0},function(a){a=a||{},a.utils={LCA:{find:function(a,b){if(a===b)return a;if(a.contains){if(a.contains(b))return a;if(b.contains(a))return b}var c=this.depth(a),d=this.depth(b),e=c-d;for(e>0?a=this.walk(a,e):b=this.walk(b,-e);a&&b&&a!==b;)a=this.walk(a,1),b=this.walk(b,1);return a},walk:function(a,b){for(var c=0;b>c;c++)a=a.parentNode;return a},depth:function(a){for(var b=0;a;)b++,a=a.parentNode;return b}}},a.findLCA=function(b,c){return a.utils.LCA.find(b,c)},window.PointerGestures=a}(window.PointerGestures),function(a){function b(){if(c){var a=new Map;return a.pointers=d,a}this.keys=[],this.values=[]}var c=window.Map&&window.Map.prototype.forEach,d=function(){return this.size};b.prototype={set:function(a,b){var c=this.keys.indexOf(a);c>-1?this.values[c]=b:(this.keys.push(a),this.values.push(b))},has:function(a){return this.keys.indexOf(a)>-1},"delete":function(a){var b=this.keys.indexOf(a);b>-1&&(this.keys.splice(b,1),this.values.splice(b,1))},get:function(a){var b=this.keys.indexOf(a);return this.values[b]},clear:function(){this.keys.length=0,this.values.length=0},forEach:function(a,b){this.values.forEach(function(c,d){a.call(b,c,this.keys[d],this)},this)},pointers:function(){return this.keys.length}},a.PointerMap=b}(window.PointerGestures),function(a){var b=["bubbles","cancelable","view","detail","screenX","screenY","clientX","clientY","ctrlKey","altKey","shiftKey","metaKey","button","relatedTarget","buttons","pointerId","width","height","pressure","tiltX","tiltY","pointerType","hwTimestamp","isPrimary","type","target","currentTarget","screenX","screenY","pageX","pageY","tapPrevented"],c=[!1,!1,null,null,0,0,0,0,!1,!1,!1,!1,0,null,0,0,0,0,0,0,0,"",0,!1,"",null,null,0,0,0,0],d={handledEvents:new WeakMap,targets:new WeakMap,handlers:{},recognizers:{},events:{},registerRecognizer:function(a,b){var c=b;this.recognizers[a]=c,c.events.forEach(function(a){if(c[a]){this.events[a]=!0;var b=c[a].bind(c);this.addHandler(a,b)}},this)},addHandler:function(a,b){var c=a;this.handlers[c]||(this.handlers[c]=[]),this.handlers[c].push(b)},registerTarget:function(a){this.listen(Object.keys(this.events),a)},unregisterTarget:function(a){this.unlisten(Object.keys(this.events),a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b=a.type,c=this.handlers[b];c&&this.makeQueue(c,a),this.handledEvents.set(a,!0)}},makeQueue:function(a,b){var c=this.cloneEvent(b);setTimeout(this.runQueue.bind(this,a,c),0)},runQueue:function(a,b){this.currentPointerId=b.pointerId;for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)c(b);this.currentPointerId=0},listen:function(a,b){a.forEach(function(a){this.addEvent(a,this.boundHandler,!1,b)},this)},unlisten:function(a){a.forEach(function(a){this.removeEvent(a,this.boundHandler,!1,inTarget)},this)},addEvent:function(a,b,c,d){d.addEventListener(a,b,c)},removeEvent:function(a,b,c,d){d.removeEventListener(a,b,c)},makeEvent:function(a,b){return new PointerGestureEvent(a,b)},cloneEvent:function(a){for(var d,e={},f=0;fthis.WIGGLE_THRESHOLD&&this.cancel()}},fireHold:function(a,c){var d={pointerType:this.heldPointer.pointerType};c&&(d.holdTime=c);var e=b.makeEvent(a,d);b.dispatchEvent(e,this.target),e.tapPrevented&&b.preventTap(this.heldPointer.pointerId)}};b.registerRecognizer("hold",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],WIGGLE_THRESHOLD:4,clampDir:function(a){return a>0?1:-1},calcPositionDelta:function(a,b){var c=0,d=0;return a&&b&&(c=b.pageX-a.pageX,d=b.pageY-a.pageY),{x:c,y:d}},fireTrack:function(a,c,d){var e=d,f=this.calcPositionDelta(e.downEvent,c),g=this.calcPositionDelta(e.lastMoveEvent,c);g.x&&(e.xDirection=this.clampDir(g.x)),g.y&&(e.yDirection=this.clampDir(g.y));var h={dx:f.x,dy:f.y,ddx:g.x,ddy:g.y,clientX:c.clientX,clientY:c.clientY,pageX:c.pageX,pageY:c.pageY,screenX:c.screenX,screenY:c.screenY,xDirection:e.xDirection,yDirection:e.yDirection,trackInfo:e.trackInfo,relatedTarget:c.target,pointerType:c.pointerType},i=b.makeEvent(a,h);e.lastMoveEvent=c,b.dispatchEvent(i,e.downTarget)},pointerdown:function(a){if(a.isPrimary&&("mouse"===a.pointerType?1===a.buttons:!0)){var b={downEvent:a,downTarget:a.target,trackInfo:{},lastMoveEvent:null,xDirection:0,yDirection:0,tracking:!1};c.set(a.pointerId,b)}},pointermove:function(a){var b=c.get(a.pointerId);if(b)if(b.tracking)this.fireTrack("track",a,b);else{var d=this.calcPositionDelta(b.downEvent,a),e=d.x*d.x+d.y*d.y;e>this.WIGGLE_THRESHOLD&&(b.tracking=!0,this.fireTrack("trackstart",b.downEvent,b),this.fireTrack("track",a,b))}},pointerup:function(a){var b=c.get(a.pointerId);b&&(b.tracking&&this.fireTrack("trackend",a,b),c.delete(a.pointerId))},pointercancel:function(a){this.pointerup(a)}};b.registerRecognizer("track",d)}(window.PointerGestures),function(a){var b=a.dispatcher,c={MIN_VELOCITY:.5,MAX_QUEUE:4,moveQueue:[],target:null,pointerId:null,events:["pointerdown","pointermove","pointerup","pointercancel"],pointerdown:function(a){a.isPrimary&&!this.pointerId&&(this.pointerId=a.pointerId,this.target=a.target,this.addMove(a))},pointermove:function(a){a.pointerId===this.pointerId&&this.addMove(a)},pointerup:function(a){a.pointerId===this.pointerId&&this.fireFlick(a),this.cleanup()},pointercancel:function(){this.cleanup()},cleanup:function(){this.moveQueue=[],this.target=null,this.pointerId=null},addMove:function(a){this.moveQueue.length>=this.MAX_QUEUE&&this.moveQueue.shift(),this.moveQueue.push(a)},fireFlick:function(a){for(var c,d,e,f,g,h,i,j=a,k=this.moveQueue.length,l=0,m=0,n=0,o=0;k>o&&(i=this.moveQueue[o]);o++)c=j.timeStamp-i.timeStamp,d=j.clientX-i.clientX,e=j.clientY-i.clientY,f=d/c,g=e/c,h=Math.sqrt(f*f+g*g),h>n&&(l=f,m=g,n=h);var p=Math.abs(l)>Math.abs(m)?"x":"y",q=this.calcAngle(l,m);if(Math.abs(n)>=this.MIN_VELOCITY){var r=b.makeEvent("flick",{xVelocity:l,yVelocity:m,velocity:n,angle:q,majorAxis:p,pointerType:a.pointerType});b.dispatchEvent(r,this.target)}},calcAngle:function(a,b){return 180*Math.atan2(b,a)/Math.PI}};b.registerRecognizer("flick",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d=180/Math.PI,e={events:["pointerdown","pointermove","pointerup","pointercancel"],reference:{},pointerdown:function(b){if(c.set(b.pointerId,b),2==c.pointers()){var d=this.calcChord(),e=this.calcAngle(d);this.reference={angle:e,diameter:d.diameter,target:a.findLCA(d.a.target,d.b.target)}}},pointerup:function(a){c.delete(a.pointerId)},pointermove:function(a){c.has(a.pointerId)&&(c.set(a.pointerId,a),c.pointers()>1&&this.calcPinchRotate())},pointercancel:function(a){this.pointerup(a)},dispatchPinch:function(a,c){var d=a/this.reference.diameter,e=b.makeEvent("pinch",{scale:d,centerX:c.center.x,centerY:c.center.y});b.dispatchEvent(e,this.reference.target)},dispatchRotate:function(a,c){var d=Math.round((a-this.reference.angle)%360),e=b.makeEvent("rotate",{angle:d,centerX:c.center.x,centerY:c.center.y});b.dispatchEvent(e,this.reference.target)},calcPinchRotate:function(){var a=this.calcChord(),b=a.diameter,c=this.calcAngle(a);b!=this.reference.diameter&&this.dispatchPinch(b,a),c!=this.reference.angle&&this.dispatchRotate(c,a)},calcChord:function(){var a=[];c.forEach(function(b){a.push(b)});for(var b,d,e,f=0,g={},h=0;hf&&(f=e,g={a:i,b:k})}return b=Math.abs(g.a.clientX+g.b.clientX)/2,d=Math.abs(g.a.clientY+g.b.clientY)/2,g.center={x:b,y:d},g.diameter=f,g},calcAngle:function(a){var b=a.a.clientX-a.b.clientX,c=a.a.clientY-a.b.clientY;return(360+Math.atan2(c,b)*d)%360}};b.registerRecognizer("pinch",e)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel","keyup"],pointerdown:function(a){a.isPrimary&&!a.tapPrevented&&c.set(a.pointerId,{target:a.target,x:a.clientX,y:a.clientY})},pointermove:function(a){if(a.isPrimary){var b=c.get(a.pointerId);b&&a.tapPrevented&&c.delete(a.pointerId)}},pointerup:function(d){var e=c.get(d.pointerId);if(e&&!d.tapPrevented){var f=a.findLCA(e.target,d.target);if(f){var g=b.makeEvent("tap",{x:d.clientX,y:d.clientY,detail:d.detail,pointerType:d.pointerType});b.dispatchEvent(g,f)}}c.delete(d.pointerId)},pointercancel:function(a){c.delete(a.pointerId)},keyup:function(a){var c=a.keyCode;if(32===c){var d=a.target;d instanceof HTMLInputElement||d instanceof HTMLTextAreaElement||b.dispatchEvent(b.makeEvent("tap",{x:0,y:0,detail:0,pointerType:"unavailable"}),d)}},preventTap:function(a){c.delete(a)}};b.registerRecognizer("tap",d)}(window.PointerGestures),function(){"use strict";function a(a){for(;a.parentNode;)a=a.parentNode;return"function"==typeof a.getElementById?a:null}function b(a,b){var c=a.bindings;if(!c)return void(a.bindings={});var d=c[b];d&&(d.close(),c[b]=void 0)}function c(a){return null==a?"":a}function d(a,b){a.data=c(b)}function e(a){return function(b){return d(a,b)}}function f(a,b,d,e){return d?void(e?a.setAttribute(b,""):a.removeAttribute(b)):void a.setAttribute(b,c(e))}function g(a,b,c){return function(d){f(a,b,c,d)}}function h(a){switch(a.type){case"checkbox":return s;case"radio":case"select-multiple":case"select-one":return"change";case"range":if(/Trident|MSIE/.test(navigator.userAgent))return"change";default:return"input"}}function i(a,b,d,e){a[b]=(e||c)(d)}function j(a,b,c){return function(d){return i(a,b,d,c)}}function k(){}function l(a,b,c,d){function e(){c.setValue(a[b]),c.discardChanges(),(d||k)(a),Platform.performMicrotaskCheckpoint()}var f=h(a);a.addEventListener(f,e);var g=c.close;c.close=function(){g&&(a.removeEventListener(f,e),c.close=g,c.close(),g=void 0)}}function m(a){return Boolean(a)}function n(b){if(b.form)return r(b.form.elements,function(a){return a!=b&&"INPUT"==a.tagName&&"radio"==a.type&&a.name==b.name});var c=a(b);if(!c)return[];var d=c.querySelectorAll('input[type="radio"][name="'+b.name+'"]');return r(d,function(a){return a!=b&&!a.form})}function o(a){"INPUT"===a.tagName&&"radio"===a.type&&n(a).forEach(function(a){var b=a.bindings.checked;b&&b.setValue(!1)})}function p(a,b){var d,e,f,g=a.parentNode;g instanceof HTMLSelectElement&&g.bindings&&g.bindings.value&&(d=g,e=d.bindings.value,f=d.value),a.value=c(b),d&&d.value!=f&&(e.setValue(d.value),e.discardChanges(),Platform.performMicrotaskCheckpoint())}function q(a){return function(b){p(a,b)}}var r=Array.prototype.filter.call.bind(Array.prototype.filter);"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)}),Node.prototype.bind=function(a,b){console.error("Unhandled binding to Node: ",this,a,b)},Node.prototype.unbind=function(a){b(this,a)},Node.prototype.unbindAll=function(){if(this.bindings){for(var a=Object.keys(this.bindings),b=0;b0;){var e=c[d];I[e.name]&&("template"!==e.name&&b.setAttribute(e.name,e.value),a.removeAttribute(e.name))}return b}function o(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];b.setAttribute(e.name,e.value),a.removeAttribute(e.name)}return a.parentNode.removeChild(a),b}function p(a,b,c){var d=a.content;if(c)return void d.appendChild(b);for(var e;e=b.firstChild;)d.appendChild(e)}function q(a){N?a.__proto__=HTMLTemplateElement.prototype:k(a,HTMLTemplateElement.prototype)}function r(a){a.setModelFn_||(a.setModelFn_=function(){a.setModelFnScheduled_=!1;var b=z(a,a.delegate_&&a.delegate_.prepareBinding);w(a,b,a.model_)}),a.setModelFnScheduled_||(a.setModelFnScheduled_=!0,Observer.runEOM_(a.setModelFn_))}function s(a,b,c,d){if(a&&a.length){for(var e,f=a.length,g=0,h=0,i=0,j=!0;f>h;){var g=a.indexOf("{{",h),k=a.indexOf("[[",h),l=!1,m="}}";if(k>=0&&(0>g||g>k)&&(g=k,l=!0,m="]]"),i=0>g?-1:a.indexOf(m,g+2),0>i){if(!e)return;e.push(a.slice(h));break}e=e||[],e.push(a.slice(h,g));var n=a.slice(g+2,i).trim();e.push(l),j=j&&l,e.push(Path.get(n));var o=d&&d(n,b,c);e.push(o),h=i+2}return h===f&&e.push(""),e.hasOnePath=5===e.length,e.isSimplePath=e.hasOnePath&&""==e[0]&&""==e[4],e.onlyOneTime=j,e.combinator=function(a){for(var b=e[0],c=1;cc?(this.keys.push(a),this.values.push(b)):this.values[c]=b},get:function(a){var b=this.keys.indexOf(a);if(!(0>b))return this.values[b]},"delete":function(a){var b=this.keys.indexOf(a);return 0>b?!1:(this.keys.splice(b,1),this.values.splice(b,1),!0)},forEach:function(a,b){for(var c=0;cb;)this.reportInstanceMoved(b),b++},closeInstanceBindings:function(a){for(var b=0;b=48&&57>=a}function d(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&" ᠎              ".indexOf(String.fromCharCode(a))>0}function e(a){return 10===a||13===a||8232===a||8233===a}function f(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a}function g(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a}function h(a){return"this"===a}function i(){for(;Y>X&&d(W.charCodeAt(X));)++X}function j(){var a,b;for(a=X++;Y>X&&(b=W.charCodeAt(X),g(b));)++X;return W.slice(a,X)}function k(){var a,b,c;return a=X,b=j(),c=1===b.length?S.Identifier:h(b)?S.Keyword:"null"===b?S.NullLiteral:"true"===b||"false"===b?S.BooleanLiteral:S.Identifier,{type:c,value:b,range:[a,X]}}function l(){var a,b,c=X,d=W.charCodeAt(X),e=W[X];switch(d){case 46:case 40:case 41:case 59:case 44:case 123:case 125:case 91:case 93:case 58:case 63:return++X,{type:S.Punctuator,value:String.fromCharCode(d),range:[c,X]};default:if(a=W.charCodeAt(X+1),61===a)switch(d){case 37:case 38:case 42:case 43:case 45:case 47:case 60:case 62:case 124:return X+=2,{type:S.Punctuator,value:String.fromCharCode(d)+String.fromCharCode(a),range:[c,X]};case 33:case 61:return X+=2,61===W.charCodeAt(X)&&++X,{type:S.Punctuator,value:W.slice(c,X),range:[c,X]}}}return b=W[X+1],e===b&&"&|".indexOf(e)>=0?(X+=2,{type:S.Punctuator,value:e+b,range:[c,X]}):"<>=!+-*%&|^/".indexOf(e)>=0?(++X,{type:S.Punctuator,value:e,range:[c,X]}):void s({},V.UnexpectedToken,"ILLEGAL")}function m(){var a,d,e;if(e=W[X],b(c(e.charCodeAt(0))||"."===e,"Numeric literal must start with a decimal digit or a decimal point"),d=X,a="","."!==e){for(a=W[X++],e=W[X],"0"===a&&e&&c(e.charCodeAt(0))&&s({},V.UnexpectedToken,"ILLEGAL");c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("."===e){for(a+=W[X++];c(W.charCodeAt(X));)a+=W[X++];e=W[X]}if("e"===e||"E"===e)if(a+=W[X++],e=W[X],("+"===e||"-"===e)&&(a+=W[X++]),c(W.charCodeAt(X)))for(;c(W.charCodeAt(X));)a+=W[X++];else s({},V.UnexpectedToken,"ILLEGAL");return f(W.charCodeAt(X))&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.NumericLiteral,value:parseFloat(a),range:[d,X]}}function n(){var a,c,d,f="",g=!1;for(a=W[X],b("'"===a||'"'===a,"String literal must starts with a quote"),c=X,++X;Y>X;){if(d=W[X++],d===a){a="";break}if("\\"===d)if(d=W[X++],d&&e(d.charCodeAt(0)))"\r"===d&&"\n"===W[X]&&++X;else switch(d){case"n":f+="\n";break;case"r":f+="\r";break;case"t":f+=" ";break;case"b":f+="\b";break;case"f":f+="\f";break;case"v":f+=" ";break;default:f+=d}else{if(e(d.charCodeAt(0)))break;f+=d}}return""!==a&&s({},V.UnexpectedToken,"ILLEGAL"),{type:S.StringLiteral,value:f,octal:g,range:[c,X]}}function o(a){return a.type===S.Identifier||a.type===S.Keyword||a.type===S.BooleanLiteral||a.type===S.NullLiteral}function p(){var a;return i(),X>=Y?{type:S.EOF,range:[X,X]}:(a=W.charCodeAt(X),40===a||41===a||58===a?l():39===a||34===a?n():f(a)?k():46===a?c(W.charCodeAt(X+1))?m():l():c(a)?m():l())}function q(){var a;return a=$,X=a.range[1],$=p(),X=a.range[1],a}function r(){var a;a=X,$=p(),X=a}function s(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(cX&&(a.push(bb()),!v(")"));)u(",");return u(")"),a}function E(){var a;return a=q(),o(a)||t(a),Z.createIdentifier(a.value)}function F(){return u("."),E()}function G(){var a;return u("["),a=bb(),u("]"),a}function H(){var a,b;for(a=C();v(".")||v("[");)v("[")?(b=G(),a=Z.createMemberExpression("[",a,b)):(b=F(),a=Z.createMemberExpression(".",a,b));return a}function I(){var a,b;return $.type!==S.Punctuator&&$.type!==S.Keyword?b=ab():v("+")||v("-")||v("!")?(a=q(),b=I(),b=Z.createUnaryExpression(a.value,b)):w("delete")||w("void")||w("typeof")?s({},V.UnexpectedToken):b=ab(),b}function J(a){var b=0;if(a.type!==S.Punctuator&&a.type!==S.Keyword)return 0;switch(a.value){case"||":b=1;break;case"&&":b=2;break;case"==":case"!=":case"===":case"!==":b=6;break;case"<":case">":case"<=":case">=":case"instanceof":b=7;break;case"in":b=7;break;case"+":case"-":b=9;break;case"*":case"/":case"%":b=11}return b}function K(){var a,b,c,d,e,f,g,h;if(g=I(),b=$,c=J(b),0===c)return g;for(b.prec=c,q(),e=I(),d=[g,b,e];(c=J($))>0;){for(;d.length>2&&c<=d[d.length-2].prec;)e=d.pop(),f=d.pop().value,g=d.pop(),a=Z.createBinaryExpression(f,g,e),d.push(a);b=q(),b.prec=c,d.push(b),a=I(),d.push(a)}for(h=d.length-1,a=d[h];h>1;)a=Z.createBinaryExpression(d[h-1].value,d[h-2],a),h-=2;return a}function L(){var a,b,c;return a=K(),v("?")&&(q(),b=L(),u(":"),c=L(),a=Z.createConditionalExpression(a,b,c)),a}function M(){var a,b;return a=q(),a.type!==S.Identifier&&t(a),b=v("(")?D():[],Z.createFilter(a.value,b)}function N(){for(;v("|");)q(),M()}function O(){i(),r();var a=bb();a&&(","===$.value||"in"==$.value&&a.type===U.Identifier?Q(a):(N(),"as"===$.value?P(a):Z.createTopLevel(a))),$.type!==S.EOF&&t($)}function P(a){q();var b=q().value;Z.createAsExpression(a,b)}function Q(a){var b;","===$.value&&(q(),$.type!==S.Identifier&&t($),b=q().value),q();var c=bb();N(),Z.createInExpression(a.name,b,c)}function R(a,b){return Z=b,W=a,X=0,Y=W.length,$=null,_={labelSet:{}},O()}var S,T,U,V,W,X,Y,Z,$,_;S={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},T={},T[S.BooleanLiteral]="Boolean",T[S.EOF]="",T[S.Identifier]="Identifier",T[S.Keyword]="Keyword",T[S.NullLiteral]="Null",T[S.NumericLiteral]="Numeric",T[S.Punctuator]="Punctuator",T[S.StringLiteral]="String",U={ArrayExpression:"ArrayExpression",BinaryExpression:"BinaryExpression",CallExpression:"CallExpression",ConditionalExpression:"ConditionalExpression",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",Identifier:"Identifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ThisExpression:"ThisExpression",UnaryExpression:"UnaryExpression"},V={UnexpectedToken:"Unexpected token %0",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared"};var ab=H,bb=L;a.esprima={parse:R}}(this),function(a){"use strict";function b(a,b,d,e){var f;try{if(f=c(a),f.scopeIdent&&(d.nodeType!==Node.ELEMENT_NODE||"TEMPLATE"!==d.tagName||"bind"!==b&&"repeat"!==b))throw Error("as and in can only be used within