UNPKG

@angular/platform-server

Version:

Angular - library for using Angular in Node.js

145 lines (144 loc) 20.3 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { ApplicationRef, InjectionToken, Renderer2, ɵannotateForHydration as annotateForHydration, ɵENABLED_SSR_FEATURES as ENABLED_SSR_FEATURES, ɵIS_HYDRATION_DOM_REUSE_ENABLED as IS_HYDRATION_DOM_REUSE_ENABLED } from '@angular/core'; import { first } from 'rxjs/operators'; import { PlatformState } from './platform_state'; import { platformServer } from './server'; import { BEFORE_APP_SERIALIZED, INITIAL_CONFIG } from './tokens'; /** * Creates an instance of a server platform (with or without JIT compiler support * depending on the `ngJitMode` global const value), using provided options. */ function createServerPlatform(options) { const extraProviders = options.platformProviders ?? []; return platformServer([ { provide: INITIAL_CONFIG, useValue: { document: options.document, url: options.url } }, extraProviders ]); } /** * Adds the `ng-server-context` attribute to host elements of all bootstrapped components * within a given application. */ function appendServerContextInfo(applicationRef) { const injector = applicationRef.injector; let serverContext = sanitizeServerContext(injector.get(SERVER_CONTEXT, DEFAULT_SERVER_CONTEXT)); const features = injector.get(ENABLED_SSR_FEATURES); if (features.size > 0) { // Append features information into the server context value. serverContext += `|${Array.from(features).join(',')}`; } applicationRef.components.forEach(componentRef => { const renderer = componentRef.injector.get(Renderer2); const element = componentRef.location.nativeElement; if (element) { renderer.setAttribute(element, 'ng-server-context', serverContext); } }); } async function _render(platformRef, applicationRef) { const environmentInjector = applicationRef.injector; // Block until application is stable. await applicationRef.isStable.pipe((first((isStable) => isStable))).toPromise(); const platformState = platformRef.injector.get(PlatformState); if (applicationRef.injector.get(IS_HYDRATION_DOM_REUSE_ENABLED, false)) { annotateForHydration(applicationRef, platformState.getDocument()); } // Run any BEFORE_APP_SERIALIZED callbacks just before rendering to string. const callbacks = environmentInjector.get(BEFORE_APP_SERIALIZED, null); if (callbacks) { const asyncCallbacks = []; for (const callback of callbacks) { try { const callbackResult = callback(); if (callbackResult) { asyncCallbacks.push(callbackResult); } } catch (e) { // Ignore exceptions. console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); } } if (asyncCallbacks.length) { for (const result of await Promise.allSettled(asyncCallbacks)) { if (result.status === 'rejected') { console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', result.reason); } } } } appendServerContextInfo(applicationRef); const output = platformState.renderToString(); platformRef.destroy(); return output; } /** * Specifies the value that should be used if no server context value has been provided. */ const DEFAULT_SERVER_CONTEXT = 'other'; /** * An internal token that allows providing extra information about the server context * (e.g. whether SSR or SSG was used). The value is a string and characters other * than [a-zA-Z0-9\-] are removed. See the default value in `DEFAULT_SERVER_CONTEXT` const. */ export const SERVER_CONTEXT = new InjectionToken('SERVER_CONTEXT'); /** * Sanitizes provided server context: * - removes all characters other than a-z, A-Z, 0-9 and `-` * - returns `other` if nothing is provided or the string is empty after sanitization */ function sanitizeServerContext(serverContext) { const context = serverContext.replace(/[^a-zA-Z0-9\-]/g, ''); return context.length > 0 ? context : DEFAULT_SERVER_CONTEXT; } /** * Bootstraps an application using provided NgModule and serializes the page content to string. * * @param moduleType A reference to an NgModule that should be used for bootstrap. * @param options Additional configuration for the render operation: * - `document` - the document of the page to render, either as an HTML string or * as a reference to the `document` instance. * - `url` - the URL for the current render request. * - `extraProviders` - set of platform level providers for the current render request. * * @publicApi */ export async function renderModule(moduleType, options) { const { document, url, extraProviders: platformProviders } = options; const platformRef = createServerPlatform({ document, url, platformProviders }); const moduleRef = await platformRef.bootstrapModule(moduleType); const applicationRef = moduleRef.injector.get(ApplicationRef); return _render(platformRef, applicationRef); } /** * Bootstraps an instance of an Angular application and renders it to a string. * ```typescript * const bootstrap = () => bootstrapApplication(RootComponent, appConfig); * const output: string = await renderApplication(bootstrap); * ``` * * @param bootstrap A method that when invoked returns a promise that returns an `ApplicationRef` * instance once resolved. * @param options Additional configuration for the render operation: * - `document` - the document of the page to render, either as an HTML string or * as a reference to the `document` instance. * - `url` - the URL for the current render request. * - `platformProviders` - the platform level providers for the current render request. * * @returns A Promise, that returns serialized (to a string) rendered page, once resolved. * * @publicApi * @developerPreview */ export async function renderApplication(bootstrap, options) { const platformRef = createServerPlatform(options); const applicationRef = await bootstrap(); return _render(platformRef, applicationRef); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9wbGF0Zm9ybS1zZXJ2ZXIvc3JjL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxjQUFjLEVBQUUsY0FBYyxFQUF5QixTQUFTLEVBQXdCLHFCQUFxQixJQUFJLG9CQUFvQixFQUFFLHFCQUFxQixJQUFJLG9CQUFvQixFQUEyRCwrQkFBK0IsSUFBSSw4QkFBOEIsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUMvVSxPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFFckMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGtCQUFrQixDQUFDO0FBQy9DLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDeEMsT0FBTyxFQUFDLHFCQUFxQixFQUFFLGNBQWMsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQVEvRDs7O0dBR0c7QUFDSCxTQUFTLG9CQUFvQixDQUFDLE9BQXdCO0lBQ3BELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsSUFBSSxFQUFFLENBQUM7SUFDdkQsT0FBTyxjQUFjLENBQUM7UUFDcEIsRUFBQyxPQUFPLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSxFQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFDLEVBQUM7UUFDbkYsY0FBYztLQUNmLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLHVCQUF1QixDQUFDLGNBQThCO0lBQzdELE1BQU0sUUFBUSxHQUFHLGNBQWMsQ0FBQyxRQUFRLENBQUM7SUFDekMsSUFBSSxhQUFhLEdBQUcscUJBQXFCLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsc0JBQXNCLENBQUMsQ0FBQyxDQUFDO0lB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U0FBUyxxQkFBcUIsQ0FBQyxhQUFxQjtJQUNsRCxNQUFNLE9BQU8sR0FBRyxhQUFhLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzdELE9BQU8sT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUM7QUFDL0QsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxZQUFZLENBQUksVUFBbUIsRUFBRSxPQUkxRDtJQUNDLE1BQU0sRUFBQyxRQUFRLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxpQkFBaUIsRUFBQyxHQUFHLE9BQU8sQ0FBQztJQUNuRSxNQUFNLFdBQVcsR0FBRyxvQkFBb0IsQ0FBQyxFQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsaUJBQWlCLEVBQUMsQ0FBQyxDQUFDO0lBQzdFLE1BQU0sU0FBUyxHQUFHLE1BQU0sV0FBVyxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNoRSxNQUFNLGNBQWMsR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM5RCxPQUFPLE9BQU8sQ0FBQyxXQUFXLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsaUJBQWlCLENBQUksU0FBd0MsRUFBRSxPQUlwRjtJQUNDLE1BQU0sV0FBVyxHQUFHLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2xELE1BQU0sY0FBYyxHQUFHLE1BQU0sU0FBUyxFQUFFLENBQUM7SUFDekMsT0FBTyxPQUFPLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0FBQzlDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHtBcHBsaWNhdGlvblJlZiwgSW5qZWN0aW9uVG9rZW4sIFBsYXRmb3JtUmVmLCBQcm92aWRlciwgUmVuZGVyZXIyLCBTdGF0aWNQcm92aWRlciwgVHlwZSwgybVhbm5vdGF0ZUZvckh5ZHJhdGlvbiBhcyBhbm5vdGF0ZUZvckh5ZHJhdGlvbiwgybVFTkFCTEVEX1NTUl9GRUFUVVJFUyBhcyBFTkFCTEVEX1NTUl9GRUFUVVJFUywgybVJbml0aWFsUmVuZGVyUGVuZGluZ1Rhc2tzIGFzIEluaXRpYWxSZW5kZXJQZW5kaW5nVGFza3MsIMm1SVNfSFlEUkFUSU9OX0RPTV9SRVVTRV9FTkFCTEVEIGFzIElTX0hZRFJBVElPTl9ET01fUkVVU0VfRU5BQkxFRH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge2ZpcnN0fSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7UGxhdGZvcm1TdGF0ZX0gZnJvbSAnLi9wbGF0Zm9ybV9zdGF0ZSc7XG5pbXBvcnQge3BsYXRmb3JtU2VydmVyfSBmcm9tICcuL3NlcnZlcic7XG5pbXBvcnQge0JFRk9SRV9BUFBfU0VSSUFMSVpFRCwgSU5JVElBTF9DT05GSUd9IGZyb20gJy4vdG9rZW5zJztcblxuaW50ZXJmYWNlIFBsYXRmb3JtT3B0aW9ucyB7XG4gIGRvY3VtZW50Pzogc3RyaW5nfERvY3VtZW50O1xuICB1cmw/OiBzdHJpbmc7XG4gIHBsYXRmb3JtUHJvdmlkZXJzPzogUHJvdmlkZXJbXTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIGEgc2VydmVyIHBsYXRmb3JtICh3aXRoIG9yIHdpdGhvdXQgSklUIGNvbXBpbGVyIHN1cHBvcnRcbiAqIGRlcGVuZGluZyBvbiB0aGUgYG5nSml0TW9kZWAgZ2xvYmFsIGNvbnN0IHZhbHVlKSwgdXNpbmcgcHJvdmlkZWQgb3B0aW9ucy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlU2VydmVyUGxhdGZvcm0ob3B0aW9uczogUGxhdGZvcm1PcHRpb25zKTogUGxhdGZvcm1SZWYge1xuICBjb25zdCBleHRyYVByb3ZpZGVycyA9IG9wdGlvbnMucGxhdGZvcm1Qcm92aWRlcnMgPz8gW107XG4gIHJldHVybiBwbGF0Zm9ybVNlcnZlcihbXG4gICAge3Byb3ZpZGU6IElOSVRJQUxfQ09ORklHLCB1c2VWYWx1ZToge2RvY3VtZW50OiBvcHRpb25zLmRvY3VtZW50LCB1cmw6IG9wdGlvbnMudXJsfX0sXG4gICAgZXh0cmFQcm92aWRlcnNcbiAgXSk7XG59XG5cbi8qKlxuICogQWRkcyB0aGUgYG5nLXNlcnZlci1jb250ZXh0YCBhdHRyaWJ1dGUgdG8gaG9zdCBlbGVtZW50cyBvZiBhbGwgYm9vdHN0cmFwcGVkIGNvbXBvbmVudHNcbiAqIHdpdGhpbiBhIGdpdmVuIGFwcGxpY2F0aW9uLlxuICovXG5mdW5jdGlvbiBhcHBlbmRTZXJ2ZXJDb250ZXh0SW5mbyhhcHBsaWNhdGlvblJlZjogQXBwbGljYXRpb25SZWYpIHtcbiAgY29uc3QgaW5qZWN0b3IgPSBhcHBsaWNhdGlvblJlZi5pbmplY3RvcjtcbiAgbGV0IHNlcnZlckNvbnRleHQgPSBzYW5pdGl6ZVNlcnZlckNvbnRleHQoaW5qZWN0b3IuZ2V0KFNFUlZFUl9DT05URVhULCBERUZBVUxUX1NFUlZFUl9DT05URVhUKSk7XG4gIGNvbnN0IGZlYXR1cmVzID0gaW5qZWN0b3IuZ2V0KEVOQUJMRURfU1NSX0ZFQVRVUkVTKTtcbiAgaWYgKGZlYXR1cmVzLnNpemUgPiAwKSB7XG4gICAgLy8gQXBwZW5kIGZlYXR1cmVzIGluZm9ybWF0aW9uIGludG8gdGhlIHNlcnZlciBjb250ZXh0IHZhbHVlLlxuICAgIHNlcnZlckNvbnRleHQgKz0gYHwke0FycmF5LmZyb20oZmVhdHVyZXMpLmpvaW4oJywnKX1gO1xuICB9XG4gIGFwcGxpY2F0aW9uUmVmLmNvbXBvbmVudHMuZm9yRWFjaChjb21wb25lbnRSZWYgPT4ge1xuICAgIGNvbnN0IHJlbmRlcmVyID0gY29tcG9uZW50UmVmLmluamVjdG9yLmdldChSZW5kZXJlcjIpO1xuICAgIGNvbnN0IGVsZW1lbnQgPSBjb21wb25lbnRSZWYubG9jYXRpb24ubmF0aXZlRWxlbWVudDtcbiAgICBpZiAoZWxlbWVudCkge1xuICAgICAgcmVuZGVyZXIuc2V0QXR0cmlidXRlKGVsZW1lbnQsICduZy1zZXJ2ZXItY29udGV4dCcsIHNlcnZlckNvbnRleHQpO1xuICAgIH1cbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIF9yZW5kZXIocGxhdGZvcm1SZWY6IFBsYXRmb3JtUmVmLCBhcHBsaWNhdGlvblJlZjogQXBwbGljYXRpb25SZWYpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBlbnZpcm9ubWVudEluamVjdG9yID0gYXBwbGljYXRpb25SZWYuaW5qZWN0b3I7XG5cbiAgLy8gQmxvY2sgdW50aWwgYXBwbGljYXRpb24gaXMgc3RhYmxlLlxuICBhd2FpdCBhcHBsaWNhdGlvblJlZi5pc1N0YWJsZS5waXBlKChmaXJzdCgoaXNTdGFibGU6IGJvb2xlYW4pID0+IGlzU3RhYmxlKSkpLnRvUHJvbWlzZSgpO1xuXG4gIGNvbnN0IHBsYXRmb3JtU3RhdGUgPSBwbGF0Zm9ybVJlZi5pbmplY3Rvci5nZXQoUGxhdGZvcm1TdGF0ZSk7XG4gIGlmIChhcHBsaWNhdGlvblJlZi5pbmplY3Rvci5nZXQoSVNfSFlEUkFUSU9OX0RPTV9SRVVTRV9FTkFCTEVELCBmYWxzZSkpIHtcbiAgICBhbm5vdGF0ZUZvckh5ZHJhdGlvbihhcHBsaWNhdGlvblJlZiwgcGxhdGZvcm1TdGF0ZS5nZXREb2N1bWVudCgpKTtcbiAgfVxuXG4gIC8vIFJ1biBhbnkgQkVGT1JFX0FQUF9TRVJJQUxJWkVEIGNhbGxiYWNrcyBqdXN0IGJlZm9yZSByZW5kZXJpbmcgdG8gc3RyaW5nLlxuICBjb25zdCBjYWxsYmFja3MgPSBlbnZpcm9ubWVudEluamVjdG9yLmdldChCRUZPUkVfQVBQX1NFUklBTElaRUQsIG51bGwpO1xuICBpZiAoY2FsbGJhY2tzKSB7XG4gICAgY29uc3QgYXN5bmNDYWxsYmFja3M6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuICAgIGZvciAoY29uc3QgY2FsbGJhY2sgb2YgY2FsbGJhY2tzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjYWxsYmFja1Jlc3VsdCA9IGNhbGxiYWNrKCk7XG4gICAgICAgIGlmIChjYWxsYmFja1Jlc3VsdCkge1xuICAgICAgICAgIGFzeW5jQ2FsbGJhY2tzLnB1c2goY2FsbGJhY2tSZXN1bHQpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIElnbm9yZSBleGNlcHRpb25zLlxuICAgICAgICBjb25zb2xlLndhcm4oJ0lnbm9yaW5nIEJFRk9SRV9BUFBfU0VSSUFMSVpFRCBFeGNlcHRpb246ICcsIGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChhc3luY0NhbGxiYWNrcy5sZW5ndGgpIHtcbiAgICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChhc3luY0NhbGxiYWNrcykpIHtcbiAgICAgICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09ICdyZWplY3RlZCcpIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oJ0lnbm9yaW5nIEJFRk9SRV9BUFBfU0VSSUFMSVpFRCBFeGNlcHRpb246ICcsIHJlc3VsdC5yZWFzb24pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYXBwZW5kU2VydmVyQ29udGV4dEluZm8oYXBwbGljYXRpb25SZWYpO1xuICBjb25zdCBvdXRwdXQgPSBwbGF0Zm9ybVN0YXRlLnJlbmRlclRvU3RyaW5nKCk7XG4gIHBsYXRmb3JtUmVmLmRlc3Ryb3koKTtcblxuICByZXR1cm4gb3V0cHV0O1xufVxuXG4vKipcbiAqIFNwZWNpZmllcyB0aGUgdmFsdWUgdGhhdCBzaG91bGQgYmUgdXNlZCBpZiBubyBzZXJ2ZXIgY29udGV4dCB2YWx1ZSBoYXMgYmVlbiBwcm92aWRlZC5cbiAqL1xuY29uc3QgREVGQVVMVF9TRVJWRVJfQ09OVEVYVCA9ICdvdGhlcic7XG5cbi8qKlxuICogQW4gaW50ZXJuYWwgdG9rZW4gdGhhdCBhbGxvd3MgcHJvdmlkaW5nIGV4dHJhIGluZm9ybWF0aW9uIGFib3V0IHRoZSBzZXJ2ZXIgY29udGV4dFxuICogKGUuZy4gd2hldGhlciBTU1Igb3IgU1NHIHdhcyB1c2VkKS4gVGhlIHZhbHVlIGlzIGEgc3RyaW5nIGFuZCBjaGFyYWN0ZXJzIG90aGVyXG4gKiB0aGFuIFthLXpBLVowLTlcXC1dIGFyZSByZW1vdmVkLiBTZWUgdGhlIGRlZmF1bHQgdmFsdWUgaW4gYERFRkFVTFRfU0VSVkVSX0NPTlRFWFRgIGNvbnN0LlxuICovXG5leHBvcnQgY29uc3QgU0VSVkVSX0NPTlRFWFQgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nPignU0VSVkVSX0NPTlRFWFQnKTtcblxuLyoqXG4gKiBTYW5pdGl6ZXMgcHJvdmlkZWQgc2VydmVyIGNvbnRleHQ6XG4gKiAtIHJlbW92ZXMgYWxsIGNoYXJhY3RlcnMgb3RoZXIgdGhhbiBhLXosIEEtWiwgMC05IGFuZCBgLWBcbiAqIC0gcmV0dXJucyBgb3RoZXJgIGlmIG5vdGhpbmcgaXMgcHJvdmlkZWQgb3IgdGhlIHN0cmluZyBpcyBlbXB0eSBhZnRlciBzYW5pdGl6YXRpb25cbiAqL1xuZnVuY3Rpb24gc2FuaXRpemVTZXJ2ZXJDb250ZXh0KHNlcnZlckNvbnRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGNvbnRleHQgPSBzZXJ2ZXJDb250ZXh0LnJlcGxhY2UoL1teYS16QS1aMC05XFwtXS9nLCAnJyk7XG4gIHJldHVybiBjb250ZXh0Lmxlbmd0aCA+IDAgPyBjb250ZXh0IDogREVGQVVMVF9TRVJWRVJfQ09OVEVYVDtcbn1cblxuLyoqXG4gKiBCb290c3RyYXBzIGFuIGFwcGxpY2F0aW9uIHVzaW5nIHByb3ZpZGVkIE5nTW9kdWxlIGFuZCBzZXJpYWxpemVzIHRoZSBwYWdlIGNvbnRlbnQgdG8gc3RyaW5nLlxuICpcbiAqIEBwYXJhbSBtb2R1bGVUeXBlIEEgcmVmZXJlbmNlIHRvIGFuIE5nTW9kdWxlIHRoYXQgc2hvdWxkIGJlIHVzZWQgZm9yIGJvb3RzdHJhcC5cbiAqIEBwYXJhbSBvcHRpb25zIEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIHJlbmRlciBvcGVyYXRpb246XG4gKiAgLSBgZG9jdW1lbnRgIC0gdGhlIGRvY3VtZW50IG9mIHRoZSBwYWdlIHRvIHJlbmRlciwgZWl0aGVyIGFzIGFuIEhUTUwgc3RyaW5nIG9yXG4gKiAgICAgICAgICAgICAgICAgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGBkb2N1bWVudGAgaW5zdGFuY2UuXG4gKiAgLSBgdXJsYCAtIHRoZSBVUkwgZm9yIHRoZSBjdXJyZW50IHJlbmRlciByZXF1ZXN0LlxuICogIC0gYGV4dHJhUHJvdmlkZXJzYCAtIHNldCBvZiBwbGF0Zm9ybSBsZXZlbCBwcm92aWRlcnMgZm9yIHRoZSBjdXJyZW50IHJlbmRlciByZXF1ZXN0LlxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlbmRlck1vZHVsZTxUPihtb2R1bGVUeXBlOiBUeXBlPFQ+LCBvcHRpb25zOiB7XG4gIGRvY3VtZW50Pzogc3RyaW5nfERvY3VtZW50LFxuICB1cmw/OiBzdHJpbmcsXG4gIGV4dHJhUHJvdmlkZXJzPzogU3RhdGljUHJvdmlkZXJbXSxcbn0pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB7ZG9jdW1lbnQsIHVybCwgZXh0cmFQcm92aWRlcnM6IHBsYXRmb3JtUHJvdmlkZXJzfSA9IG9wdGlvbnM7XG4gIGNvbnN0IHBsYXRmb3JtUmVmID0gY3JlYXRlU2VydmVyUGxhdGZvcm0oe2RvY3VtZW50LCB1cmwsIHBsYXRmb3JtUHJvdmlkZXJzfSk7XG4gIGNvbnN0IG1vZHVsZVJlZiA9IGF3YWl0IHBsYXRmb3JtUmVmLmJvb3RzdHJhcE1vZHVsZShtb2R1bGVUeXBlKTtcbiAgY29uc3QgYXBwbGljYXRpb25SZWYgPSBtb2R1bGVSZWYuaW5qZWN0b3IuZ2V0KEFwcGxpY2F0aW9uUmVmKTtcbiAgcmV0dXJuIF9yZW5kZXIocGxhdGZvcm1SZWYsIGFwcGxpY2F0aW9uUmVmKTtcbn1cblxuLyoqXG4gKiBCb290c3RyYXBzIGFuIGluc3RhbmNlIG9mIGFuIEFuZ3VsYXIgYXBwbGljYXRpb24gYW5kIHJlbmRlcnMgaXQgdG8gYSBzdHJpbmcuXG5cbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGJvb3RzdHJhcCA9ICgpID0+IGJvb3RzdHJhcEFwcGxpY2F0aW9uKFJvb3RDb21wb25lbnQsIGFwcENvbmZpZyk7XG4gKiBjb25zdCBvdXRwdXQ6IHN0cmluZyA9IGF3YWl0IHJlbmRlckFwcGxpY2F0aW9uKGJvb3RzdHJhcCk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gYm9vdHN0cmFwIEEgbWV0aG9kIHRoYXQgd2hlbiBpbnZva2VkIHJldHVybnMgYSBwcm9taXNlIHRoYXQgcmV0dXJucyBhbiBgQXBwbGljYXRpb25SZWZgXG4gKiAgICAgaW5zdGFuY2Ugb25jZSByZXNvbHZlZC5cbiAqIEBwYXJhbSBvcHRpb25zIEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIHJlbmRlciBvcGVyYXRpb246XG4gKiAgLSBgZG9jdW1lbnRgIC0gdGhlIGRvY3VtZW50IG9mIHRoZSBwYWdlIHRvIHJlbmRlciwgZWl0aGVyIGFzIGFuIEhUTUwgc3RyaW5nIG9yXG4gKiAgICAgICAgICAgICAgICAgYXMgYSByZWZlcmVuY2UgdG8gdGhlIGBkb2N1bWVudGAgaW5zdGFuY2UuXG4gKiAgLSBgdXJsYCAtIHRoZSBVUkwgZm9yIHRoZSBjdXJyZW50IHJlbmRlciByZXF1ZXN0LlxuICogIC0gYHBsYXRmb3JtUHJvdmlkZXJzYCAtIHRoZSBwbGF0Zm9ybSBsZXZlbCBwcm92aWRlcnMgZm9yIHRoZSBjdXJyZW50IHJlbmRlciByZXF1ZXN0LlxuICpcbiAqIEByZXR1cm5zIEEgUHJvbWlzZSwgdGhhdCByZXR1cm5zIHNlcmlhbGl6ZWQgKHRvIGEgc3RyaW5nKSByZW5kZXJlZCBwYWdlLCBvbmNlIHJlc29sdmVkLlxuICpcbiAqIEBwdWJsaWNBcGlcbiAqIEBkZXZlbG9wZXJQcmV2aWV3XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZW5kZXJBcHBsaWNhdGlvbjxUPihib290c3RyYXA6ICgpID0+IFByb21pc2U8QXBwbGljYXRpb25SZWY+LCBvcHRpb25zOiB7XG4gIGRvY3VtZW50Pzogc3RyaW5nfERvY3VtZW50LFxuICB1cmw/OiBzdHJpbmcsXG4gIHBsYXRmb3JtUHJvdmlkZXJzPzogUHJvdmlkZXJbXSxcbn0pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBwbGF0Zm9ybVJlZiA9IGNyZWF0ZVNlcnZlclBsYXRmb3JtKG9wdGlvbnMpO1xuICBjb25zdCBhcHBsaWNhdGlvblJlZiA9IGF3YWl0IGJvb3RzdHJhcCgpO1xuICByZXR1cm4gX3JlbmRlcihwbGF0Zm9ybVJlZiwgYXBwbGljYXRpb25SZWYpO1xufVxuIl19