1(function() {
2    "use strict";
3    var idCounter = 0;
4    let testharness_context = null;
5
6    function getInViewCenterPoint(rect) {
7        var left = Math.max(0, rect.left);
8        var right = Math.min(window.innerWidth, rect.right);
9        var top = Math.max(0, rect.top);
10        var bottom = Math.min(window.innerHeight, rect.bottom);
11
12        var x = 0.5 * (left + right);
13        var y = 0.5 * (top + bottom);
14
15        return [x, y];
16    }
17
18    function getPointerInteractablePaintTree(element) {
19        let elementDocument = element.ownerDocument;
20        if (!elementDocument.contains(element)) {
21            return [];
22        }
23
24        var rectangles = element.getClientRects();
25
26        if (rectangles.length === 0) {
27            return [];
28        }
29
30        var centerPoint = getInViewCenterPoint(rectangles[0]);
31
32        if ("elementsFromPoint" in elementDocument) {
33            return elementDocument.elementsFromPoint(centerPoint[0], centerPoint[1]);
34        } else if ("msElementsFromPoint" in elementDocument) {
35            var rv = elementDocument.msElementsFromPoint(centerPoint[0], centerPoint[1]);
36            return Array.prototype.slice.call(rv ? rv : []);
37        } else {
38            throw new Error("document.elementsFromPoint unsupported");
39        }
40    }
41
42    function inView(element) {
43        var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
44        return pointerInteractablePaintTree.indexOf(element) !== -1;
45    }
46
47
48    /**
49     * @namespace {test_driver}
50     */
51    window.test_driver = {
52        /**
53         * Set the context in which testharness.js is loaded
54         *
55         * @param {WindowProxy} context - the window containing testharness.js
56         **/
57        set_test_context: function(context) {
58          if (window.test_driver_internal.set_test_context) {
59            window.test_driver_internal.set_test_context(context);
60          }
61          testharness_context = context;
62        },
63
64        /**
65         * postMessage to the context containing testharness.js
66         *
67         * @param {Object} msg - the data to POST
68         **/
69        message_test: function(msg) {
70            let target = testharness_context;
71            if (testharness_context === null) {
72                target = window;
73            }
74            target.postMessage(msg, "*");
75        },
76
77        /**
78         * Trigger user interaction in order to grant additional privileges to
79         * a provided function.
80         *
81         * See `triggered by user activation
82         * <https://html.spec.whatwg.org/#triggered-by-user-activation>`_.
83         *
84         * @example
85         * var mediaElement = document.createElement('video');
86         *
87         * test_driver.bless('initiate media playback', function () {
88         *   mediaElement.play();
89         * });
90         *
91         * @param {String} intent - a description of the action which must be
92         *                          triggered by user interaction
93         * @param {Function} action - code requiring escalated privileges
94         * @param {WindowProxy} context - Browsing context in which
95         *                                to run the call, or null for the current
96         *                                browsing context.
97         *
98         * @returns {Promise} fulfilled following user interaction and
99         *                    execution of the provided `action` function;
100         *                    rejected if interaction fails or the provided
101         *                    function throws an error
102         */
103        bless: function(intent, action, context=null) {
104            let contextDocument = context ? context.document : document;
105            var button = contextDocument.createElement("button");
106            button.innerHTML = "This test requires user interaction.<br />" +
107                "Please click here to allow " + intent + ".";
108            button.id = "wpt-test-driver-bless-" + (idCounter += 1);
109            const elem = contextDocument.body || contextDocument.documentElement;
110            elem.appendChild(button);
111
112            let wait_click = new Promise(resolve => button.addEventListener("click", resolve));
113
114            return test_driver.click(button)
115                .then(wait_click)
116                .then(function() {
117                    button.remove();
118
119                    if (typeof action === "function") {
120                        return action();
121                    }
122                    return null;
123                });
124        },
125
126        /**
127         * Triggers a user-initiated click
128         *
129         * If ``element`` isn't inside the
130         * viewport, it will be scrolled into view before the click
131         * occurs.
132         *
133         * If ``element`` is from a different browsing context, the
134         * command will be run in that context.
135         *
136         * Matches the behaviour of the `Element Click
137         * <https://w3c.github.io/webdriver/#element-click>`_
138         * WebDriver command.
139         *
140         * **Note:** If the element to be clicked does not have a
141         * unique ID, the document must not have any DOM mutations
142         * made between the function being called and the promise
143         * settling.
144         *
145         * @param {Element} element - element to be clicked
146         * @returns {Promise} fulfilled after click occurs, or rejected in
147         *                    the cases the WebDriver command errors
148         */
149        click: function(element) {
150            if (!inView(element)) {
151                element.scrollIntoView({behavior: "instant",
152                                        block: "end",
153                                        inline: "nearest"});
154            }
155
156            var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
157            if (pointerInteractablePaintTree.length === 0 ||
158                !element.contains(pointerInteractablePaintTree[0])) {
159                return Promise.reject(new Error("element click intercepted error"));
160            }
161
162            var rect = element.getClientRects()[0];
163            var centerPoint = getInViewCenterPoint(rect);
164            return window.test_driver_internal.click(element,
165                                                     {x: centerPoint[0],
166                                                      y: centerPoint[1]});
167        },
168
169        /**
170         * Deletes all cookies.
171         *
172         * Matches the behaviour of the `Delete All Cookies
173         * <https://w3c.github.io/webdriver/#delete-all-cookies>`_
174         * WebDriver command.
175         *
176         * @param {WindowProxy} context - Browsing context in which
177         *                                to run the call, or null for the current
178         *                                browsing context.
179         *
180         * @returns {Promise} fulfilled after cookies are deleted, or rejected in
181         *                    the cases the WebDriver command errors
182         */
183        delete_all_cookies: function(context=null) {
184            return window.test_driver_internal.delete_all_cookies(context);
185        },
186
187        /**
188         * Send keys to an element.
189         *
190         * If ``element`` isn't inside the
191         * viewport, it will be scrolled into view before the click
192         * occurs.
193         *
194         * If ``element`` is from a different browsing context, the
195         * command will be run in that context.
196         *
197         * To send special keys, send the respective key's codepoint,
198         * as defined by `WebDriver
199         * <https://w3c.github.io/webdriver/#keyboard-actions>`_.  For
200         * example, the "tab" key is represented as "``\uE004``".
201         *
202         * **Note:** these special-key codepoints are not necessarily
203         * what you would expect. For example, <kbd>Esc</kbd> is the
204         * invalid Unicode character ``\uE00C``, not the ``\u001B`` Escape
205         * character from ASCII.
206         *
207         * This matches the behaviour of the
208         * `Send Keys
209         * <https://w3c.github.io/webdriver/#element-send-keys>`_
210         * WebDriver command.
211         *
212         * **Note:** If the element to be clicked does not have a
213         * unique ID, the document must not have any DOM mutations
214         * made between the function being called and the promise
215         * settling.
216         *
217         * @param {Element} element - element to send keys to
218         * @param {String} keys - keys to send to the element
219         * @returns {Promise} fulfilled after keys are sent, or rejected in
220         *                    the cases the WebDriver command errors
221         */
222        send_keys: function(element, keys) {
223            if (!inView(element)) {
224                element.scrollIntoView({behavior: "instant",
225                                        block: "end",
226                                        inline: "nearest"});
227            }
228
229            var pointerInteractablePaintTree = getPointerInteractablePaintTree(element);
230            if (pointerInteractablePaintTree.length === 0 ||
231                !element.contains(pointerInteractablePaintTree[0])) {
232                return Promise.reject(new Error("element send_keys intercepted error"));
233            }
234
235            return window.test_driver_internal.send_keys(element, keys);
236        },
237
238        /**
239         * Freeze the current page
240         *
241         * The freeze function transitions the page from the HIDDEN state to
242         * the FROZEN state as described in `Lifecycle API for Web Pages
243         * <https://github.com/WICG/page-lifecycle/blob/master/README.md>`_.
244         *
245         * @param {WindowProxy} context - Browsing context in which
246         *                                to run the call, or null for the current
247         *                                browsing context.
248         *
249         * @returns {Promise} fulfilled after the freeze request is sent, or rejected
250         *                    in case the WebDriver command errors
251         */
252        freeze: function(context=null) {
253            return window.test_driver_internal.freeze();
254        },
255
256        /**
257         * Minimizes the browser window.
258         *
259         * Matches the the behaviour of the `Minimize
260         * <https://www.w3.org/TR/webdriver/#minimize-window>`_
261         * WebDriver command
262         *
263         * @param {WindowProxy} context - Browsing context in which
264         *                                to run the call, or null for the current
265         *                                browsing context.
266         *
267         * @returns {Promise} fulfilled with the previous {@link
268         *                    https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect}
269         *                      value, after the window is minimized.
270         */
271        minimize_window: function(context=null) {
272            return window.test_driver_internal.minimize_window(context);
273        },
274
275        /**
276         * Restore the window from minimized/maximized state to a given rect.
277         *
278         * Matches the behaviour of the `Set Window Rect
279         * <https://www.w3.org/TR/webdriver/#set-window-rect>`_
280         * WebDriver command
281         *
282         * @param {Object} rect - A {@link
283         *                           https://www.w3.org/TR/webdriver/#dfn-windowrect-object|WindowRect}
284         * @param {WindowProxy} context - Browsing context in which
285         *                                to run the call, or null for the current
286         *                                browsing context.
287         *
288         * @returns {Promise} fulfilled after the window is restored to the given rect.
289         */
290        set_window_rect: function(rect, context=null) {
291            return window.test_driver_internal.set_window_rect(rect, context);
292        },
293
294        /**
295         * Send a sequence of actions
296         *
297         * This function sends a sequence of actions to perform.
298         *
299         * Matches the behaviour of the `Actions
300         * <https://w3c.github.io/webdriver/#actions>`_ feature in
301         * WebDriver.
302         *
303         * Authors are encouraged to use the
304         * :js:class:`test_driver.Actions` builder rather than
305         * invoking this API directly.
306         *
307         * @param {Array} actions - an array of actions. The format is
308         *                          the same as the actions property
309         *                          of the `Perform Actions
310         *                          <https://w3c.github.io/webdriver/#perform-actions>`_
311         *                          WebDriver command. Each element is
312         *                          an object representing an input
313         *                          source and each input source
314         *                          itself has an actions property
315         *                          detailing the behaviour of that
316         *                          source at each timestep (or
317         *                          tick). Authors are not expected to
318         *                          construct the actions sequence by
319         *                          hand, but to use the builder api
320         *                          provided in testdriver-actions.js
321         * @param {WindowProxy} context - Browsing context in which
322         *                                to run the call, or null for the current
323         *                                browsing context.
324         *
325         * @returns {Promise} fulfilled after the actions are performed, or rejected in
326         *                    the cases the WebDriver command errors
327         */
328        action_sequence: function(actions, context=null) {
329            return window.test_driver_internal.action_sequence(actions, context);
330        },
331
332        /**
333         * Generates a test report on the current page
334         *
335         * The generate_test_report function generates a report (to be
336         * observed by ReportingObserver) for testing purposes.
337         *
338         * Matches the `Generate Test Report
339         * <https://w3c.github.io/reporting/#generate-test-report-command>`_
340         * WebDriver command.
341         *
342         * @param {WindowProxy} context - Browsing context in which
343         *                                to run the call, or null for the current
344         *                                browsing context.
345         *
346         * @returns {Promise} fulfilled after the report is generated, or
347         *                    rejected if the report generation fails
348         */
349        generate_test_report: function(message, context=null) {
350            return window.test_driver_internal.generate_test_report(message, context);
351        },
352
353        /**
354         * Sets the state of a permission
355         *
356         * This function simulates a user setting a permission into a
357         * particular state.
358         *
359         * Matches the `Set Permission
360         * <https://w3c.github.io/permissions/#set-permission-command>`_
361         * WebDriver command.
362         *
363         * @example
364         * await test_driver.set_permission({ name: "background-fetch" }, "denied");
365         * await test_driver.set_permission({ name: "push", userVisibleOnly: true }, "granted", true);
366         *
367         * @param {Object} descriptor - a `PermissionDescriptor
368         *                              <https://w3c.github.io/permissions/#dictdef-permissiondescriptor>`_
369         *                              object
370         * @param {String} state - the state of the permission
371         * @param {boolean} one_realm - Optional. Whether the permission applies to only one realm
372         * @param {WindowProxy} context - Browsing context in which
373         *                                to run the call, or null for the current
374         *                                browsing context.
375         * @returns {Promise} fulfilled after the permission is set, or rejected if setting the
376         *                    permission fails
377         */
378        set_permission: function(descriptor, state, one_realm=false, context=null) {
379            let permission_params = {
380              descriptor,
381              state,
382              oneRealm: one_realm,
383            };
384            return window.test_driver_internal.set_permission(permission_params, context);
385        },
386
387        /**
388         * Creates a virtual authenticator
389         *
390         * This function creates a virtual authenticator for use with
391         * the U2F and WebAuthn APIs.
392         *
393         * Matches the `Add Virtual Authenticator
394         * <https://w3c.github.io/webauthn/#sctn-automation-add-virtual-authenticator>`_
395         * WebDriver command.
396         *
397         * @param {Object} config - an `Authenticator Configuration
398         *                          <https://w3c.github.io/webauthn/#authenticator-configuration>`_
399         *                          object
400         * @param {WindowProxy} context - Browsing context in which
401         *                                to run the call, or null for the current
402         *                                browsing context.
403         *
404         * @returns {Promise} fulfilled after the authenticator is added, or
405         *                    rejected in the cases the WebDriver command
406         *                    errors. Returns the ID of the authenticator
407         */
408        add_virtual_authenticator: function(config, context=null) {
409            return window.test_driver_internal.add_virtual_authenticator(config, context);
410        },
411
412        /**
413         * Removes a virtual authenticator
414         *
415         * This function removes a virtual authenticator that has been
416         * created by :js:func:`add_virtual_authenticator`.
417         *
418         * Matches the `Remove Virtual Authenticator
419         * <https://w3c.github.io/webauthn/#sctn-automation-remove-virtual-authenticator>`_
420         * WebDriver command.
421         *
422         * @param {String} authenticator_id - the ID of the authenticator to be
423         *                                    removed.
424         * @param {WindowProxy} context - Browsing context in which
425         *                                to run the call, or null for the current
426         *                                browsing context.
427         *
428         * @returns {Promise} fulfilled after the authenticator is removed, or
429         *                    rejected in the cases the WebDriver command
430         *                    errors
431         */
432        remove_virtual_authenticator: function(authenticator_id, context=null) {
433            return window.test_driver_internal.remove_virtual_authenticator(authenticator_id, context);
434        },
435
436        /**
437         * Adds a credential to a virtual authenticator
438         *
439         * Matches the `Add Credential
440         * <https://w3c.github.io/webauthn/#sctn-automation-add-credential>`_
441         * WebDriver command.
442         *
443         * @param {String} authenticator_id - the ID of the authenticator
444         * @param {Object} credential - A `Credential Parameters
445         *                              <https://w3c.github.io/webauthn/#credential-parameters>`_
446         *                              object
447         * @param {WindowProxy} context - Browsing context in which
448         *                                to run the call, or null for the current
449         *                                browsing context.
450         *
451         * @returns {Promise} fulfilled after the credential is added, or
452         *                    rejected in the cases the WebDriver command
453         *                    errors
454         */
455        add_credential: function(authenticator_id, credential, context=null) {
456            return window.test_driver_internal.add_credential(authenticator_id, credential, context);
457        },
458
459        /**
460         * Gets all the credentials stored in an authenticator
461         *
462         * This function retrieves all the credentials (added via the U2F API,
463         * WebAuthn, or the add_credential function) stored in a virtual
464         * authenticator
465         *
466         * Matches the `Get Credentials
467         * <https://w3c.github.io/webauthn/#sctn-automation-get-credentials>`_
468         * WebDriver command.
469         *
470         * @param {String} authenticator_id - the ID of the authenticator
471         * @param {WindowProxy} context - Browsing context in which
472         *                                to run the call, or null for the current
473         *                                browsing context.
474         *
475         * @returns {Promise} fulfilled after the credentials are
476         *                    returned, or rejected in the cases the
477         *                    WebDriver command errors. Returns an
478         *                    array of `Credential Parameters
479         *                    <https://w3c.github.io/webauthn/#credential-parameters>`_
480         */
481        get_credentials: function(authenticator_id, context=null) {
482            return window.test_driver_internal.get_credentials(authenticator_id, context=null);
483        },
484
485        /**
486         * Remove a credential stored in an authenticator
487         *
488         * Matches the `Remove Credential
489         * <https://w3c.github.io/webauthn/#sctn-automation-remove-credential>`_
490         * WebDriver command.
491         *
492         * @param {String} authenticator_id - the ID of the authenticator
493         * @param {String} credential_id - the ID of the credential
494         * @param {WindowProxy} context - Browsing context in which
495         *                                to run the call, or null for the current
496         *                                browsing context.
497         *
498         * @returns {Promise} fulfilled after the credential is removed, or
499         *                    rejected in the cases the WebDriver command
500         *                    errors.
501         */
502        remove_credential: function(authenticator_id, credential_id, context=null) {
503            return window.test_driver_internal.remove_credential(authenticator_id, credential_id, context);
504        },
505
506        /**
507         * Removes all the credentials stored in a virtual authenticator
508         *
509         * Matches the `Remove All Credentials
510         * <https://w3c.github.io/webauthn/#sctn-automation-remove-all-credentials>`_
511         * WebDriver command.
512         *
513         * @param {String} authenticator_id - the ID of the authenticator
514         * @param {WindowProxy} context - Browsing context in which
515         *                                to run the call, or null for the current
516         *                                browsing context.
517         *
518         * @returns {Promise} fulfilled after the credentials are removed, or
519         *                    rejected in the cases the WebDriver command
520         *                    errors.
521         */
522        remove_all_credentials: function(authenticator_id, context=null) {
523            return window.test_driver_internal.remove_all_credentials(authenticator_id, context);
524        },
525
526        /**
527         * Sets the User Verified flag on an authenticator
528         *
529         * Sets whether requests requiring user verification will succeed or
530         * fail on a given virtual authenticator
531         *
532         * Matches the `Set User Verified
533         * <https://w3c.github.io/webauthn/#sctn-automation-set-user-verified>`_
534         * WebDriver command.
535         *
536         * @param {String} authenticator_id - the ID of the authenticator
537         * @param {boolean} uv - the User Verified flag
538         * @param {WindowProxy} context - Browsing context in which
539         *                                to run the call, or null for the current
540         *                                browsing context.
541         */
542        set_user_verified: function(authenticator_id, uv, context=null) {
543            return window.test_driver_internal.set_user_verified(authenticator_id, uv, context);
544        },
545
546        /**
547         * Sets the storage access rule for an origin when embedded
548         * in a third-party context.
549         *
550         * Matches the `Set Storage Access
551         * <https://privacycg.github.io/storage-access/#set-storage-access-command>`_
552         * WebDriver command.
553         *
554         * @param {String} origin - A third-party origin to block or allow.
555         *                          May be "*" to indicate all origins.
556         * @param {String} embedding_origin - an embedding (first-party) origin
557         *                                    on which {origin}'s access should
558         *                                    be blocked or allowed.
559         *                                    May be "*" to indicate all origins.
560         * @param {String} state - The storage access setting.
561         *                         Must be either "allowed" or "blocked".
562         * @param {WindowProxy} context - Browsing context in which
563         *                                to run the call, or null for the current
564         *                                browsing context.
565         *
566         * @returns {Promise} Fulfilled after the storage access rule has been
567         *                    set, or rejected if setting the rule fails.
568         */
569        set_storage_access: function(origin, embedding_origin, state, context=null) {
570            if (state !== "allowed" && state !== "blocked") {
571                throw new Error("storage access status must be 'allowed' or 'blocked'");
572            }
573            const blocked = state === "blocked";
574            return window.test_driver_internal.set_storage_access(origin, embedding_origin, blocked, context);
575        },
576
577        /**
578         * Sets the current transaction automation mode for Secure Payment
579         * Confirmation.
580         *
581         * This function places `Secure Payment
582         * Confirmation <https://w3c.github.io/secure-payment-confirmation>`_ into
583         * an automated 'autoaccept' or 'autoreject' mode, to allow testing
584         * without user interaction with the transaction UX prompt.
585         *
586         * Matches the `Set SPC Transaction Mode
587         * <https://w3c.github.io/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode>`_
588         * WebDriver command.
589         *
590         * @example
591         * await test_driver.set_spc_transaction_mode("autoaccept");
592         * test.add_cleanup(() => {
593         *   return test_driver.set_spc_transaction_mode("none");
594         * });
595         *
596         * // Assumption: `request` is a PaymentRequest with a secure-payment-confirmation
597         * // payment method.
598         * const response = await request.show();
599         *
600         * @param {String} mode - The `transaction mode
601         *                        <https://w3c.github.io/secure-payment-confirmation/#enumdef-transactionautomationmode>`_
602         *                        to set. Must be one of "``none``",
603         *                        "``autoaccept``", or
604         *                        "``autoreject``".
605         * @param {WindowProxy} context - Browsing context in which
606         *                                to run the call, or null for the current
607         *                                browsing context.
608         *
609         * @returns {Promise} Fulfilled after the transaction mode has been set,
610         *                    or rejected if setting the mode fails.
611         */
612        set_spc_transaction_mode: function(mode, context=null) {
613          return window.test_driver_internal.set_spc_transaction_mode(mode, context);
614        },
615    };
616
617    window.test_driver_internal = {
618        /**
619         * This flag should be set to `true` by any code which implements the
620         * internal methods defined below for automation purposes. Doing so
621         * allows the library to signal failure immediately when an automated
622         * implementation of one of the methods is not available.
623         */
624        in_automation: false,
625
626        click: function(element, coords) {
627            if (this.in_automation) {
628                return Promise.reject(new Error('Not implemented'));
629            }
630
631            return new Promise(function(resolve, reject) {
632                element.addEventListener("click", resolve);
633            });
634        },
635
636        delete_all_cookies: function(context=null) {
637            return Promise.reject(new Error("unimplemented"));
638        },
639
640        send_keys: function(element, keys) {
641            if (this.in_automation) {
642                return Promise.reject(new Error('Not implemented'));
643            }
644
645            return new Promise(function(resolve, reject) {
646                var seen = "";
647
648                function remove() {
649                    element.removeEventListener("keydown", onKeyDown);
650                }
651
652                function onKeyDown(event) {
653                    if (event.key.length > 1) {
654                        return;
655                    }
656
657                    seen += event.key;
658
659                    if (keys.indexOf(seen) !== 0) {
660                        reject(new Error("Unexpected key sequence: " + seen));
661                        remove();
662                    } else if (seen === keys) {
663                        resolve();
664                        remove();
665                    }
666                }
667
668                element.addEventListener("keydown", onKeyDown);
669            });
670        },
671
672        freeze: function(context=null) {
673            return Promise.reject(new Error("unimplemented"));
674        },
675
676        minimize_window: function(context=null) {
677            return Promise.reject(new Error("unimplemented"));
678        },
679
680        set_window_rect: function(rect, context=null) {
681            return Promise.reject(new Error("unimplemented"));
682        },
683
684        action_sequence: function(actions, context=null) {
685            return Promise.reject(new Error("unimplemented"));
686        },
687
688        generate_test_report: function(message, context=null) {
689            return Promise.reject(new Error("unimplemented"));
690        },
691
692
693        set_permission: function(permission_params, context=null) {
694            return Promise.reject(new Error("unimplemented"));
695        },
696
697        add_virtual_authenticator: function(config, context=null) {
698            return Promise.reject(new Error("unimplemented"));
699        },
700
701        remove_virtual_authenticator: function(authenticator_id, context=null) {
702            return Promise.reject(new Error("unimplemented"));
703        },
704
705        add_credential: function(authenticator_id, credential, context=null) {
706            return Promise.reject(new Error("unimplemented"));
707        },
708
709        get_credentials: function(authenticator_id, context=null) {
710            return Promise.reject(new Error("unimplemented"));
711        },
712
713        remove_credential: function(authenticator_id, credential_id, context=null) {
714            return Promise.reject(new Error("unimplemented"));
715        },
716
717        remove_all_credentials: function(authenticator_id, context=null) {
718            return Promise.reject(new Error("unimplemented"));
719        },
720
721        set_user_verified: function(authenticator_id, uv, context=null) {
722            return Promise.reject(new Error("unimplemented"));
723        },
724
725        set_storage_access: function(origin, embedding_origin, blocked, context=null) {
726            return Promise.reject(new Error("unimplemented"));
727        },
728
729        set_spc_transaction_mode: function(mode, context=null) {
730            return Promise.reject(new Error("unimplemented"));
731        },
732
733    };
734})();
735