UNPKG

14.2 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google LLC All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8/**
9 * @fileoverview
10 * A module to facilitate use of a Trusted Types policy within the JIT
11 * compiler. It lazily constructs the Trusted Types policy, providing helper
12 * utilities for promoting strings to Trusted Types. When Trusted Types are not
13 * available, strings are used as a fallback.
14 * @security All use of this module is security-sensitive and should go through
15 * security review.
16 */
17import { global } from '../util';
18/**
19 * The Trusted Types policy, or null if Trusted Types are not
20 * enabled/supported, or undefined if the policy has not been created yet.
21 */
22let policy;
23/**
24 * Returns the Trusted Types policy, or null if Trusted Types are not
25 * enabled/supported. The first call to this function will create the policy.
26 */
27function getPolicy() {
28 if (policy === undefined) {
29 policy = null;
30 if (global.trustedTypes) {
31 try {
32 policy =
33 global.trustedTypes.createPolicy('angular#unsafe-jit', {
34 createScript: (s) => s,
35 });
36 }
37 catch {
38 // trustedTypes.createPolicy throws if called with a name that is
39 // already registered, even in report-only mode. Until the API changes,
40 // catch the error not to break the applications functionally. In such
41 // cases, the code will fall back to using strings.
42 }
43 }
44 }
45 return policy;
46}
47/**
48 * Unsafely promote a string to a TrustedScript, falling back to strings when
49 * Trusted Types are not available.
50 * @security In particular, it must be assured that the provided string will
51 * never cause an XSS vulnerability if used in a context that will be
52 * interpreted and executed as a script by a browser, e.g. when calling eval.
53 */
54function trustedScriptFromString(script) {
55 return getPolicy()?.createScript(script) || script;
56}
57/**
58 * Unsafely call the Function constructor with the given string arguments.
59 * @security This is a security-sensitive function; any use of this function
60 * must go through security review. In particular, it must be assured that it
61 * is only called from the JIT compiler, as use in other code can lead to XSS
62 * vulnerabilities.
63 */
64export function newTrustedFunctionForJIT(...args) {
65 if (!global.trustedTypes) {
66 // In environments that don't support Trusted Types, fall back to the most
67 // straightforward implementation:
68 return new Function(...args);
69 }
70 // Chrome currently does not support passing TrustedScript to the Function
71 // constructor. The following implements the workaround proposed on the page
72 // below, where the Chromium bug is also referenced:
73 // https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
74 const fnArgs = args.slice(0, -1).join(',');
75 const fnBody = args[args.length - 1];
76 const body = `(function anonymous(${fnArgs}
77) { ${fnBody}
78})`;
79 // Using eval directly confuses the compiler and prevents this module from
80 // being stripped out of JS binaries even if not used. The global['eval']
81 // indirection fixes that.
82 const fn = global['eval'](trustedScriptFromString(body));
83 if (fn.bind === undefined) {
84 // Workaround for a browser bug that only exists in Chrome 83, where passing
85 // a TrustedScript to eval just returns the TrustedScript back without
86 // evaluating it. In that case, fall back to the most straightforward
87 // implementation:
88 return new Function(...args);
89 }
90 // To completely mimic the behavior of calling "new Function", two more
91 // things need to happen:
92 // 1. Stringifying the resulting function should return its source code
93 fn.toString = () => body;
94 // 2. When calling the resulting function, `this` should refer to `global`
95 return fn.bind(global);
96 // When Trusted Types support in Function constructors is widely available,
97 // the implementation of this function can be simplified to:
98 // return new Function(...args.map(a => trustedScriptFromString(a)));
99}
100//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0X2ppdF90cnVzdGVkX3R5cGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tcGlsZXIvc3JjL291dHB1dC9vdXRwdXRfaml0X3RydXN0ZWRfdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUg7Ozs7Ozs7O0dBUUc7QUFFSCxPQUFPLEVBQUMsTUFBTSxFQUFDLE1BQU0sU0FBUyxDQUFDO0FBbUMvQjs7O0dBR0c7QUFDSCxJQUFJLE1BQXdDLENBQUM7QUFFN0M7OztHQUdHO0FBQ0gsU0FBUyxTQUFTO0lBQ2hCLElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRTtRQUN4QixNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ2QsSUFBSSxNQUFNLENBQUMsWUFBWSxFQUFFO1lBQ3ZCLElBQUk7Z0JBQ0YsTUFBTTtvQkFDRCxNQUFNLENBQUMsWUFBeUMsQ0FBQyxZQUFZLENBQUMsb0JBQW9CLEVBQUU7d0JBQ25GLFlBQVksRUFBRSxDQUFDLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQztxQkFDL0IsQ0FBQyxDQUFDO2FBQ1I7WUFBQyxNQUFNO2dCQUNOLGlFQUFpRTtnQkFDakUsdUVBQXVFO2dCQUN2RSxzRUFBc0U7Z0JBQ3RFLG1EQUFtRDthQUNwRDtTQUNGO0tBQ0Y7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBUyx1QkFBdUIsQ0FBQyxNQUFjO0lBQzdDLE9BQU8sU0FBUyxFQUFFLEVBQUUsWUFBWSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQztBQUNyRCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QixDQUFDLEdBQUcsSUFBYztJQUN4RCxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRTtRQUN4QiwwRUFBMEU7UUFDMUUsa0NBQWtDO1FBQ2xDLE9BQU8sSUFBSSxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztLQUM5QjtJQUVELDBFQUEwRTtJQUMxRSw0RUFBNEU7SUFDNUUsb0RBQW9EO0lBQ3BELDZGQUE2RjtJQUM3RixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMzQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNyQyxNQUFNLElBQUksR0FBRyx1QkFBdUIsTUFBTTtNQUN0QyxNQUFNO0dBQ1QsQ0FBQztJQUVGLDBFQUEwRTtJQUMxRSx5RUFBeUU7SUFDekUsMEJBQTBCO0lBQzFCLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQVcsQ0FBYSxDQUFDO0lBQy9FLElBQUksRUFBRSxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUU7UUFDekIsNEVBQTRFO1FBQzVFLHNFQUFzRTtRQUN0RSxxRUFBcUU7UUFDckUsa0JBQWtCO1FBQ2xCLE9BQU8sSUFBSSxRQUFRLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztLQUM5QjtJQUVELHVFQUF1RTtJQUN2RSx5QkFBeUI7SUFDekIsdUVBQXVFO0lBQ3ZFLEVBQUUsQ0FBQyxRQUFRLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDO0lBQ3pCLDBFQUEwRTtJQUMxRSxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFdkIsMkVBQTJFO0lBQzNFLDREQUE0RDtJQUM1RCxxRUFBcUU7QUFDdkUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG4vKipcbiAqIEBmaWxlb3ZlcnZpZXdcbiAqIEEgbW9kdWxlIHRvIGZhY2lsaXRhdGUgdXNlIG9mIGEgVHJ1c3RlZCBUeXBlcyBwb2xpY3kgd2l0aGluIHRoZSBKSVRcbiAqIGNvbXBpbGVyLiBJdCBsYXppbHkgY29uc3RydWN0cyB0aGUgVHJ1c3RlZCBUeXBlcyBwb2xpY3ksIHByb3ZpZGluZyBoZWxwZXJcbiAqIHV0aWxpdGllcyBmb3IgcHJvbW90aW5nIHN0cmluZ3MgdG8gVHJ1c3RlZCBUeXBlcy4gV2hlbiBUcnVzdGVkIFR5cGVzIGFyZSBub3RcbiAqIGF2YWlsYWJsZSwgc3RyaW5ncyBhcmUgdXNlZCBhcyBhIGZhbGxiYWNrLlxuICogQHNlY3VyaXR5IEFsbCB1c2Ugb2YgdGhpcyBtb2R1bGUgaXMgc2VjdXJpdHktc2Vuc2l0aXZlIGFuZCBzaG91bGQgZ28gdGhyb3VnaFxuICogc2VjdXJpdHkgcmV2aWV3LlxuICovXG5cbmltcG9ydCB7Z2xvYmFsfSBmcm9tICcuLi91dGlsJztcblxuLyoqXG4gKiBXaGlsZSBBbmd1bGFyIG9ubHkgdXNlcyBUcnVzdGVkIFR5cGVzIGludGVybmFsbHkgZm9yIHRoZSB0aW1lIGJlaW5nLFxuICogcmVmZXJlbmNlcyB0byBUcnVzdGVkIFR5cGVzIGNvdWxkIGxlYWsgaW50byBvdXIgY29yZS5kLnRzLCB3aGljaCB3b3VsZCBmb3JjZVxuICogYW55b25lIGNvbXBpbGluZyBhZ2FpbnN0IEBhbmd1bGFyL2NvcmUgdG8gcHJvdmlkZSB0aGUgQHR5cGVzL3RydXN0ZWQtdHlwZXNcbiAqIHBhY2thZ2UgaW4gdGhlaXIgY29tcGlsYXRpb24gdW5pdC5cbiAqXG4gKiBVbnRpbCBodHRwczovL2dpdGh1Yi5jb20vbWljcm9zb2Z0L1R5cGVTY3JpcHQvaXNzdWVzLzMwMDI0IGlzIHJlc29sdmVkLCB3ZVxuICogd2lsbCBrZWVwIEFuZ3VsYXIncyBwdWJsaWMgQVBJIHN1cmZhY2UgZnJlZSBvZiByZWZlcmVuY2VzIHRvIFRydXN0ZWQgVHlwZXMuXG4gKiBGb3IgaW50ZXJuYWwgYW5kIHNlbWktcHJpdmF0ZSBBUElzIHRoYXQgbmVlZCB0byByZWZlcmVuY2UgVHJ1c3RlZCBUeXBlcywgdGhlXG4gKiBtaW5pbWFsIHR5cGUgZGVmaW5pdGlvbnMgZm9yIHRoZSBUcnVzdGVkIFR5cGVzIEFQSSBwcm92aWRlZCBieSB0aGlzIG1vZHVsZVxuICogc2hvdWxkIGJlIHVzZWQgaW5zdGVhZC4gVGhleSBhcmUgbWFya2VkIGFzIFwiZGVjbGFyZVwiIHRvIHByZXZlbnQgdGhlbSBmcm9tXG4gKiBiZWluZyByZW5hbWVkIGJ5IGNvbXBpbGVyIG9wdGltaXphdGlvbi5cbiAqXG4gKiBBZGFwdGVkIGZyb21cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9EZWZpbml0ZWx5VHlwZWQvRGVmaW5pdGVseVR5cGVkL2Jsb2IvbWFzdGVyL3R5cGVzL3RydXN0ZWQtdHlwZXMvaW5kZXguZC50c1xuICogYnV0IHJlc3RyaWN0ZWQgdG8gdGhlIEFQSSBzdXJmYWNlIHVzZWQgd2l0aGluIEFuZ3VsYXIuXG4gKi9cblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIFRydXN0ZWRTY3JpcHQge1xuICBfX2JyYW5kX186ICdUcnVzdGVkU2NyaXB0Jztcbn1cblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIFRydXN0ZWRUeXBlUG9saWN5RmFjdG9yeSB7XG4gIGNyZWF0ZVBvbGljeShwb2xpY3lOYW1lOiBzdHJpbmcsIHBvbGljeU9wdGlvbnM6IHtcbiAgICBjcmVhdGVTY3JpcHQ/OiAoaW5wdXQ6IHN0cmluZykgPT4gc3RyaW5nLFxuICB9KTogVHJ1c3RlZFR5cGVQb2xpY3k7XG59XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBUcnVzdGVkVHlwZVBvbGljeSB7XG4gIGNyZWF0ZVNjcmlwdChpbnB1dDogc3RyaW5nKTogVHJ1c3RlZFNjcmlwdDtcbn1cblxuXG4vKipcbiAqIFRoZSBUcnVzdGVkIFR5cGVzIHBvbGljeSwgb3IgbnVsbCBpZiBUcnVzdGVkIFR5cGVzIGFyZSBub3RcbiAqIGVuYWJsZWQvc3VwcG9ydGVkLCBvciB1bmRlZmluZWQgaWYgdGhlIHBvbGljeSBoYXMgbm90IGJlZW4gY3JlYXRlZCB5ZXQuXG4gKi9cbmxldCBwb2xpY3k6IFRydXN0ZWRUeXBlUG9saWN5fG51bGx8dW5kZWZpbmVkO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIFRydXN0ZWQgVHlwZXMgcG9saWN5LCBvciBudWxsIGlmIFRydXN0ZWQgVHlwZXMgYXJlIG5vdFxuICogZW5hYmxlZC9zdXBwb3J0ZWQuIFRoZSBmaXJzdCBjYWxsIHRvIHRoaXMgZnVuY3Rpb24gd2lsbCBjcmVhdGUgdGhlIHBvbGljeS5cbiAqL1xuZnVuY3Rpb24gZ2V0UG9saWN5KCk6IFRydXN0ZWRUeXBlUG9saWN5fG51bGwge1xuICBpZiAocG9saWN5ID09PSB1bmRlZmluZWQpIHtcbiAgICBwb2xpY3kgPSBudWxsO1xuICAgIGlmIChnbG9iYWwudHJ1c3RlZFR5cGVzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBwb2xpY3kgPVxuICAgICAgICAgICAgKGdsb2JhbC50cnVzdGVkVHlwZXMgYXMgVHJ1c3RlZFR5cGVQb2xpY3lGYWN0b3J5KS5jcmVhdGVQb2xpY3koJ2FuZ3VsYXIjdW5zYWZlLWppdCcsIHtcbiAgICAgICAgICAgICAgY3JlYXRlU2NyaXB0OiAoczogc3RyaW5nKSA9PiBzLFxuICAgICAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gdHJ1c3RlZFR5cGVzLmNyZWF0ZVBvbGljeSB0aHJvd3MgaWYgY2FsbGVkIHdpdGggYSBuYW1lIHRoYXQgaXNcbiAgICAgICAgLy8gYWxyZWFkeSByZWdpc3RlcmVkLCBldmVuIGluIHJlcG9ydC1vbmx5IG1vZGUuIFVudGlsIHRoZSBBUEkgY2hhbmdlcyxcbiAgICAgICAgLy8gY2F0Y2ggdGhlIGVycm9yIG5vdCB0byBicmVhayB0aGUgYXBwbGljYXRpb25zIGZ1bmN0aW9uYWxseS4gSW4gc3VjaFxuICAgICAgICAvLyBjYXNlcywgdGhlIGNvZGUgd2lsbCBmYWxsIGJhY2sgdG8gdXNpbmcgc3RyaW5ncy5cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHBvbGljeTtcbn1cblxuLyoqXG4gKiBVbnNhZmVseSBwcm9tb3RlIGEgc3RyaW5nIHRvIGEgVHJ1c3RlZFNjcmlwdCwgZmFsbGluZyBiYWNrIHRvIHN0cmluZ3Mgd2hlblxuICogVHJ1c3RlZCBUeXBlcyBhcmUgbm90IGF2YWlsYWJsZS5cbiAqIEBzZWN1cml0eSBJbiBwYXJ0aWN1bGFyLCBpdCBtdXN0IGJlIGFzc3VyZWQgdGhhdCB0aGUgcHJvdmlkZWQgc3RyaW5nIHdpbGxcbiAqIG5ldmVyIGNhdXNlIGFuIFhTUyB2dWxuZXJhYmlsaXR5IGlmIHVzZWQgaW4gYSBjb250ZXh0IHRoYXQgd2lsbCBiZVxuICogaW50ZXJwcmV0ZWQgYW5kIGV4ZWN1dGVkIGFzIGEgc2NyaXB0IGJ5IGEgYnJvd3NlciwgZS5nLiB3aGVuIGNhbGxpbmcgZXZhbC5cbiAqL1xuZnVuY3Rpb24gdHJ1c3RlZFNjcmlwdEZyb21TdHJpbmcoc2NyaXB0OiBzdHJpbmcpOiBUcnVzdGVkU2NyaXB0fHN0cmluZyB7XG4gIHJldHVybiBnZXRQb2xpY3koKT8uY3JlYXRlU2NyaXB0KHNjcmlwdCkgfHwgc2NyaXB0O1xufVxuXG4vKipcbiAqIFVuc2FmZWx5IGNhbGwgdGhlIEZ1bmN0aW9uIGNvbnN0cnVjdG9yIHdpdGggdGhlIGdpdmVuIHN0cmluZyBhcmd1bWVudHMuXG4gKiBAc2VjdXJpdHkgVGhpcyBpcyBhIHNlY3VyaXR5LXNlbnNpdGl2ZSBmdW5jdGlvbjsgYW55IHVzZSBvZiB0aGlzIGZ1bmN0aW9uXG4gKiBtdXN0IGdvIHRocm91Z2ggc2VjdXJpdHkgcmV2aWV3LiBJbiBwYXJ0aWN1bGFyLCBpdCBtdXN0IGJlIGFzc3VyZWQgdGhhdCBpdFxuICogaXMgb25seSBjYWxsZWQgZnJvbSB0aGUgSklUIGNvbXBpbGVyLCBhcyB1c2UgaW4gb3RoZXIgY29kZSBjYW4gbGVhZCB0byBYU1NcbiAqIHZ1bG5lcmFiaWxpdGllcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5ld1RydXN0ZWRGdW5jdGlvbkZvckpJVCguLi5hcmdzOiBzdHJpbmdbXSk6IEZ1bmN0aW9uIHtcbiAgaWYgKCFnbG9iYWwudHJ1c3RlZFR5cGVzKSB7XG4gICAgLy8gSW4gZW52aXJvbm1lbnRzIHRoYXQgZG9uJ3Qgc3VwcG9ydCBUcnVzdGVkIFR5cGVzLCBmYWxsIGJhY2sgdG8gdGhlIG1vc3RcbiAgICAvLyBzdHJhaWdodGZvcndhcmQgaW1wbGVtZW50YXRpb246XG4gICAgcmV0dXJuIG5ldyBGdW5jdGlvbiguLi5hcmdzKTtcbiAgfVxuXG4gIC8vIENocm9tZSBjdXJyZW50bHkgZG9lcyBub3Qgc3VwcG9ydCBwYXNzaW5nIFRydXN0ZWRTY3JpcHQgdG8gdGhlIEZ1bmN0aW9uXG4gIC8vIGNvbnN0cnVjdG9yLiBUaGUgZm9sbG93aW5nIGltcGxlbWVudHMgdGhlIHdvcmthcm91bmQgcHJvcG9zZWQgb24gdGhlIHBhZ2VcbiAgLy8gYmVsb3csIHdoZXJlIHRoZSBDaHJvbWl1bSBidWcgaXMgYWxzbyByZWZlcmVuY2VkOlxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vdzNjL3dlYmFwcHNlYy10cnVzdGVkLXR5cGVzL3dpa2kvVHJ1c3RlZC1UeXBlcy1mb3ItZnVuY3Rpb24tY29uc3RydWN0b3JcbiAgY29uc3QgZm5BcmdzID0gYXJncy5zbGljZSgwLCAtMSkuam9pbignLCcpO1xuICBjb25zdCBmbkJvZHkgPSBhcmdzW2FyZ3MubGVuZ3RoIC0gMV07XG4gIGNvbnN0IGJvZHkgPSBgKGZ1bmN0aW9uIGFub255bW91cygke2ZuQXJnc31cbikgeyAke2ZuQm9keX1cbn0pYDtcblxuICAvLyBVc2luZyBldmFsIGRpcmVjdGx5IGNvbmZ1c2VzIHRoZSBjb21waWxlciBhbmQgcHJldmVudHMgdGhpcyBtb2R1bGUgZnJvbVxuICAvLyBiZWluZyBzdHJpcHBlZCBvdXQgb2YgSlMgYmluYXJpZXMgZXZlbiBpZiBub3QgdXNlZC4gVGhlIGdsb2JhbFsnZXZhbCddXG4gIC8vIGluZGlyZWN0aW9uIGZpeGVzIHRoYXQuXG4gIGNvbnN0IGZuID0gZ2xvYmFsWydldmFsJ10odHJ1c3RlZFNjcmlwdEZyb21TdHJpbmcoYm9keSkgYXMgc3RyaW5nKSBhcyBGdW5jdGlvbjtcbiAgaWYgKGZuLmJpbmQgPT09IHVuZGVmaW5lZCkge1xuICAgIC8vIFdvcmthcm91bmQgZm9yIGEgYnJvd3NlciBidWcgdGhhdCBvbmx5IGV4aXN0cyBpbiBDaHJvbWUgODMsIHdoZXJlIHBhc3NpbmdcbiAgICAvLyBhIFRydXN0ZWRTY3JpcHQgdG8gZXZhbCBqdXN0IHJldHVybnMgdGhlIFRydXN0ZWRTY3JpcHQgYmFjayB3aXRob3V0XG4gICAgLy8gZXZhbHVhdGluZyBpdC4gSW4gdGhhdCBjYXNlLCBmYWxsIGJhY2sgdG8gdGhlIG1vc3Qgc3RyYWlnaHRmb3J3YXJkXG4gICAgLy8gaW1wbGVtZW50YXRpb246XG4gICAgcmV0dXJuIG5ldyBGdW5jdGlvbiguLi5hcmdzKTtcbiAgfVxuXG4gIC8vIFRvIGNvbXBsZXRlbHkgbWltaWMgdGhlIGJlaGF2aW9yIG9mIGNhbGxpbmcgXCJuZXcgRnVuY3Rpb25cIiwgdHdvIG1vcmVcbiAgLy8gdGhpbmdzIG5lZWQgdG8gaGFwcGVuOlxuICAvLyAxLiBTdHJpbmdpZnlpbmcgdGhlIHJlc3VsdGluZyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGl0cyBzb3VyY2UgY29kZVxuICBmbi50b1N0cmluZyA9ICgpID0+IGJvZHk7XG4gIC8vIDIuIFdoZW4gY2FsbGluZyB0aGUgcmVzdWx0aW5nIGZ1bmN0aW9uLCBgdGhpc2Agc2hvdWxkIHJlZmVyIHRvIGBnbG9iYWxgXG4gIHJldHVybiBmbi5iaW5kKGdsb2JhbCk7XG5cbiAgLy8gV2hlbiBUcnVzdGVkIFR5cGVzIHN1cHBvcnQgaW4gRnVuY3Rpb24gY29uc3RydWN0b3JzIGlzIHdpZGVseSBhdmFpbGFibGUsXG4gIC8vIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiB0aGlzIGZ1bmN0aW9uIGNhbiBiZSBzaW1wbGlmaWVkIHRvOlxuICAvLyByZXR1cm4gbmV3IEZ1bmN0aW9uKC4uLmFyZ3MubWFwKGEgPT4gdHJ1c3RlZFNjcmlwdEZyb21TdHJpbmcoYSkpKTtcbn1cbiJdfQ==
\No newline at end of file