UNPKG

@codegena/oapi3ts

Version:

Codegeneration from OAS3 to TypeScript

486 lines 76 kB
import _ from 'lodash'; import * as jsonPointer from 'json-pointer'; import { Generic as SchemaGeneric } from '@codegena/definitions/json-schema'; import { Oas3ParameterTarget, } from '@codegena/definitions/oas3'; import { defaultConfig } from './config'; import { ParsingError, ParsingProblems } from './parsing-problems'; const jsonPathRegex = /([\w:\/\\\.]+)?#(\/?[\w+\/?]+)/; /** * @param pieces * @return * JSON-Path according to [RFC-6901](https://tools.ietf.org/html/rfc6901) * TODO refactor: move to common helper */ function makeJsonPath(...pieces) { return jsonPointer.compile(pieces); } /** * Rethrow {@link ParsingError} if original error already handled at inner level * @param {ParsingError | any} error */ function rethrowParsingError(error) { if (error instanceof ParsingError) { throw error; } } /** * Базовый класс загрузчика. */ export class BaseConvertor { constructor(config = defaultConfig) { this.config = config; } loadOAPI3Structure(structure) { if (!structure || !_.isObjectLike(structure)) { throw new ParsingError([ `Expected structure to be object but got:`, JSON.stringify(structure, null, ' ') ].join('\n')); } this._operationsMeta = []; this._structure = structure; } setForeignSchemeFn(fn) { if (!_.isFunction(fn)) { throw new ParsingError('Error in `setForeignSchemeFn`: argument has to be function!'); } this._foreignSchemaFn = (jsonPath) => { try { return fn(jsonPath); } catch (e) { throw new ParsingError('Error when trying to resolve schema!', { jsonPath }); } }; } getApiMeta() { return this._operationsMeta; } /** * Getting of "entry-points" from structure in {@link _structure} early * loaded by {@link loadOAPI3Structure}. * * Entrypoints are: * * - Parameters * - Requests * - Responses * * ### Why it needed? * * Entrypoints is needed to use [Convertor.renderRecursive]{@link Convertor.renderRecursive}. * It's like a pulling on thread where entrypoints are outstanding trheads. * * @param ApiMetaInfo metaInfo * Mutable object where meta-information accumulates during * API-info extracting. */ getOAPI3EntryPoints(context = {}, metaInfo = []) { const alreadyConverted = []; // parameters const methodsSchemes = this.getMethodsSchemes(metaInfo); const dataTypeContainers = _.map(methodsSchemes, (schema, modelName) => { const container = this.convert(schema, context, modelName); // TODO Crutch. This class should never know about assignedTypes // in GenericDescriptor if (schema instanceof SchemaGeneric) { _.each(container, (description) => { if (description['assignedTypes']) { description['assignedTypes'] = ['TCode', 'TContentType', 'T1', 'T2']; } }); } // Исключение дубликатов. // Дубликаты появляются, когда типы данные, которые // ссылаются ($ref) без изменения на другие, подменяются // моделями из `schema`. return _.map(container, (descr) => { // Excluding of elements having common `originalSchemaPath` // and simultaneously already related with. if (descr.originalSchemaPath) { if (_.findIndex(alreadyConverted, v => v === descr.originalSchemaPath) !== -1) { return null; } alreadyConverted.push(descr.originalSchemaPath); } return descr; }); }); const dataTypeContainer = _.flattenDepth(dataTypeContainers); return _.compact(dataTypeContainer); } /** * Получить дескриптор типа по JSON Path: * возвращает уже созданный ранее, или создает * новый при первом упоминании. * * @param path * @param context */ findTypeByPath(path, context) { const alreadyFound = _.find(_.values(context), (v) => v.originalSchemaPath === path); return alreadyFound ? [alreadyFound] : this._processSchema(path, context); } /** * @deprecated will be renamed to `getSchemaByRef` * @param ref * @param pathWhereReferred * @return */ getSchemaByPath(ref, pathWhereReferred) { const pathMatches = ref.match(jsonPathRegex); if (pathMatches) { const filePath = pathMatches[1]; const schemaPath = pathMatches[2]; const src = filePath ? this._getForeignSchema(filePath) : this._structure; const result = _.get(src, _.trim(schemaPath, '#/\\').replace(/[\\\/]/g, '.'), undefined); if (result === undefined) { ParsingProblems.parsingWarning(`Cant resolve ${ref}!`, { oasStructure: this._structure, relatedRef: ref, jsonPath: pathWhereReferred ? makeJsonPath(...pathWhereReferred) : undefined }); } return result; } else { throw new ParsingError(`JSON Path error: ${ref} is not valid JSON path!`, { oasStructure: this._structure, relatedRef: ref, jsonPath: pathWhereReferred ? makeJsonPath(...pathWhereReferred) : undefined }); } } /** * Извлечени схем из параметров, ответов и тел запросов для API. * @param metaInfo * Place for storing meta-info of API-method. */ getMethodsSchemes(metaInfo) { const struct = this._structure; if (!struct) { throw new ParsingError([ 'There is no structure loaded!', 'Please, call method `loadOAPI3Structure` before!' ].join(' ')); } const result = {}; const paths = struct.paths; if (!paths) { throw new ParsingError('No paths presented in OAS structure!', { oasStructure: struct }); } for (const path in paths) { // skip proto's properties if (!paths.hasOwnProperty(path)) { continue; } const jsonPathToPath = ['paths', path]; if (!path) { ParsingProblems.parsingWarning('Path key cant be empty. Skipped.', { oasStructure: struct, jsonPath: makeJsonPath(...jsonPathToPath) }); continue; } const pathItem = struct.paths[path]; if (!_.isObjectLike(pathItem)) { ParsingProblems.parsingWarning('Item of "paths" should be object like. Skipped.', { oasStructure: struct, jsonPath: makeJsonPath(...jsonPathToPath) }); continue; } const methods = [ 'delete', 'get', 'head', 'options', 'patch', 'post', 'put', 'trace', ]; for (const methodName of methods) { // skip proto's properties if (!pathItem.hasOwnProperty(methodName)) { continue; } const apiOperation = pathItem[methodName]; const jsonPathToOperation = [...jsonPathToPath, methodName]; if (!_.isObjectLike(apiOperation)) { ParsingProblems.parsingWarning('Operation should be object like. Skipped.', { oasStructure: struct, jsonPath: makeJsonPath(...jsonPathToOperation) }); continue; } const baseTypeName = this._getOperationBaseName(apiOperation, methodName, path, jsonPathToOperation); const servers = this._getOperationServers(apiOperation, jsonPathToOperation); const metaInfoItem = { apiSchemaFile: 'domain-api-schema', baseTypeName, headersSchema: null, headersModelName: null, method: methodName.toUpperCase(), mockData: {}, paramsModelName: null, paramsSchema: null, path, queryParams: [], requestIsRequired: false, requestModelName: null, requestSchema: null, responseModelName: null, responseSchema: null, servers, // default noname typingsDependencies: [], typingsDirectory: 'typings', }; let jsonSubPathToOperation; try { jsonSubPathToOperation = [...jsonPathToOperation, 'parameters']; // pick Parameters schema _.assign(result, this._pickApiMethodParameters(metaInfoItem, apiOperation.parameters, jsonSubPathToOperation)); } catch (error) { rethrowParsingError(error); throw new ParsingError('An error occurred at method parameters fetching', { oasStructure: struct, jsonPath: makeJsonPath(...jsonSubPathToOperation), originalError: error }); } try { jsonSubPathToOperation = [...jsonPathToOperation, 'responses']; // pick Responses schema _.assign(result, this._pickApiMethodResponses(metaInfoItem, apiOperation.responses || {}, jsonSubPathToOperation)); } catch (error) { rethrowParsingError(error); throw new ParsingError('An error occurred at method responses fetching', { oasStructure: struct, jsonPath: makeJsonPath(...jsonSubPathToOperation), originalError: error }); } try { jsonSubPathToOperation = [...jsonPathToOperation, 'requestBody']; // pick Request Body schema _.assign(result, this._pickApiMethodRequest(apiOperation, metaInfoItem, [...jsonSubPathToOperation])); } catch (error) { rethrowParsingError(error); throw new ParsingError('An error occurred at method request body fetching', { oasStructure: struct, jsonPath: makeJsonPath(...jsonSubPathToOperation), originalError: error }); } metaInfo.push(metaInfoItem); this._operationsMeta.push({ operationJsonPath: jsonPathToOperation, apiMeta: metaInfoItem, }); } } return result; } /** * Get parameters from the `parameters` section * in method into {@link ApiMetaInfo}-object */ _pickApiMethodParameters(metaInfoItem, parameters, jsonPathToOperation) { const result = {}; const paramsModelName = this.config.parametersModelName(metaInfoItem.baseTypeName); const paramsSchema = { properties: {}, required: [], type: 'object' }; // process parameters _.each(parameters || [], (parameter, index) => { if (parameter.$ref) { parameter = _.merge(_.omit(parameter, ['$ref']), this.getSchemaByPath(parameter.$ref, [...jsonPathToOperation, String(index)])); } if (parameter.schema) { paramsSchema.properties[parameter.name] = parameter.schema; if (parameter.description) { parameter.schema.description = parameter.description; } if (parameter.readOnly) { paramsSchema.properties[parameter.name].readOnly = true; } if (parameter.required) { paramsSchema.required.push(parameter.name); } if (Number(index) === 0) { // metaInfoItem.typingsDependencies.push(paramsModelName); metaInfoItem.paramsModelName = paramsModelName; metaInfoItem.paramsSchema = paramsSchema; } if (parameter.in === Oas3ParameterTarget.Query) { metaInfoItem.queryParams.push(parameter.name); } if (!paramsSchema.description) { paramsSchema.description = `Model of parameters for API \`${metaInfoItem.path}\``; } result[paramsModelName] = paramsSchema; } }); if (result[paramsModelName]) { metaInfoItem.typingsDependencies.push(paramsModelName); } return result; } _pickApiMethodResponses(metaInfoItem, responses, jsonPathToOperation) { const result = {}; _.each(responses, (response, code) => { // todo do tests when $ref to schema.responses if (response.$ref) { response = _.merge(_.omit(response, ['$ref']), this.getSchemaByPath(response.$ref, [...jsonPathToOperation, String(code)])); } const mediaTypes = response.content || response.schema // Case for OAS2 || {}; // Fallback // if content set, but empty if (_.keys(mediaTypes).length === 0) { mediaTypes['application/json'] = null; } // todo пока обрабатываются только контент и заголовки _.each(mediaTypes || {}, (mediaContent, contentTypeKey) => { // todo do fallback if no `schema property` const schema = _.get(mediaContent, 'schema') || { description: 'Empty response', type: 'null', }; // by default if (!metaInfoItem.responseSchema) { metaInfoItem.responseSchema = {}; } // add description if it's set if (response.description) { schema.description = response.description; } _.set(metaInfoItem.responseSchema, [code, contentTypeKey], schema); }); if (response.headers) { // TODO has to be tested const modelName = this.config.headersModelName(metaInfoItem.baseTypeName, code); result[modelName] = { properties: response.headers, type: 'object' }; } }); if (metaInfoItem.responseSchema) { const modelName = this.config.responseModelName(metaInfoItem.baseTypeName, '', ''); metaInfoItem.responseModelName = modelName; metaInfoItem.typingsDependencies.push(modelName); result[modelName] = new SchemaGeneric(_.mapValues(metaInfoItem.responseSchema, subSchema => new SchemaGeneric(subSchema))); } return result; } _pickApiMethodRequest(apiOperation, metaInfoItem, jsonPathToOperation) { const { requestBody } = apiOperation; let responses; if (!requestBody) { return null; } else { metaInfoItem.requestIsRequired = !!requestBody.required; if (!requestBody.content) { return null; } const modelName = this.config.requestModelName(metaInfoItem.baseTypeName); responses = _(requestBody.content) .mapValues((mediaContent, mediaTypeName) => { const mapResult = mediaContent.schema ? Object.assign({}, mediaContent.schema) : null; if (apiOperation.requestBody.description && !mapResult.description) { mapResult.description = apiOperation.requestBody.description; } return mapResult; }) .value(); metaInfoItem.requestModelName = modelName; metaInfoItem.requestSchema = responses; metaInfoItem.typingsDependencies.push(modelName); return _.zipObject([modelName], [new SchemaGeneric(responses)]); } } /** * Получение нового дескриптора на основе JSON Path * из текущей структуры. * * @param path * @param context */ _processSchema(path, context) { const schema = this.getSchemaByPath(path); const modelName = (_.trim(path, '/\\').match(/(\w+)$/) || [])[1]; if (!schema) { throw new Error(`Error: can't find schema with path: ${path}!`); } const results = this.convert(schema, context, modelName, null, path); _.each(results, (result) => { context[result.originalSchemaPath || result.modelName] = result; }); return results; } _getForeignSchema(ref) { if (this._foreignSchemaFn) { return this._foreignSchemaFn(ref); } else { throw new ParsingError([ 'Function for getting foreign scheme not set.', `Use setForeignSchemeFn(). Path: ${ref}.` ].join('\n'), { oasStructure: this._structure, relatedRef: ref }); } } _getOperationBaseName(apiOperation, methodName, path, jsonPathToOperation) { if (!apiOperation.operationId || !_.isString(apiOperation.operationId)) { const baseNameFallback = _.upperFirst(_.camelCase(jsonPathToOperation.join('-').replace(/[^\-\w]/g, ''))); ParsingProblems.parsingWarning([ `Wrong operation id "${apiOperation.operationId}".`, `Fallback basename is: "${baseNameFallback}".` ].join('\n'), { oasStructure: this._structure, jsonPath: makeJsonPath(...jsonPathToOperation, 'operationId') }); return baseNameFallback; } const operationId = _.camelCase(apiOperation.operationId.trim().replace(/[^\w+]/g, '_')); return _.upperFirst(operationId) || [ _.capitalize(methodName), _.upperFirst(_.camelCase(path)) ].join(''); } _getOperationServers(apiOperation, jsonPathToOperation) { let servers = apiOperation.servers || this._structure.servers; if (servers !== undefined && !_.isArray(servers)) { ParsingProblems.parsingWarning('Servers should be array. Skipped.', { oasStructure: this._structure, jsonPath: makeJsonPath(...jsonPathToOperation, 'servers') }); servers = []; } if (!servers || servers.length < 1) { servers = defaultConfig.defaultServerInfo; } return servers; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVydG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy9vYXBpM3RzL3NyYy9sZWdhY3kvY29yZS9jb252ZXJ0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBQ3ZCLE9BQU8sS0FBSyxXQUFXLE1BQU0sY0FBYyxDQUFDO0FBRzVDLE9BQU8sRUFDSCxPQUFPLElBQUksYUFBYSxFQUczQixNQUFNLG1DQUFtQyxDQUFDO0FBQzNDLE9BQU8sRUFJSCxtQkFBbUIsR0FNdEIsTUFBTSw0QkFBNEIsQ0FBQztBQUVwQyxPQUFPLEVBQW1CLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBUW5FLE1BQU0sYUFBYSxHQUFHLGdDQUFnQyxDQUFDO0FBRXZEOzs7OztHQUtHO0FBQ0gsU0FBUyxZQUFZLENBQUMsR0FBRyxNQUE4QjtJQUNuRCxPQUFPLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDdkMsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsbUJBQW1CLENBQUMsS0FBeUI7SUFDbEQsSUFBSSxLQUFLLFlBQVksWUFBWSxFQUFFO1FBQy9CLE1BQU0sS0FBSyxDQUFDO0tBQ2Y7QUFDTCxDQUFDO0FBT0Q7O0dBRUc7QUFDSCxNQUFNLE9BQWdCLGFBQWE7SUFNL0IsWUFDYyxTQUEwQixhQUFhO1FBQXZDLFdBQU0sR0FBTixNQUFNLENBQWlDO0lBQ2xELENBQUM7SUFFRyxrQkFBa0IsQ0FBQyxTQUE0QjtRQUNsRCxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUMxQyxNQUFNLElBQUksWUFBWSxDQUFDO2dCQUNuQiwwQ0FBMEM7Z0JBQzFDLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxHQUFHLENBQUM7YUFDdkMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztTQUNqQjtRQUVELElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDO1FBQzFCLElBQUksQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDO0lBQ2hDLENBQUM7SUFFTSxrQkFBa0IsQ0FBQyxFQUFnQztRQUN0RCxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsRUFBRTtZQUNuQixNQUFNLElBQUksWUFBWSxDQUFDLDZEQUE2RCxDQUFDLENBQUM7U0FDekY7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUNqQyxJQUFJO2dCQUNBLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2FBQ3ZCO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1IsTUFBTSxJQUFJLFlBQVksQ0FDbEIsc0NBQXNDLEVBQ3RDLEVBQUUsUUFBUSxFQUFFLENBQ2YsQ0FBQzthQUNMO1FBQ0wsQ0FBQyxDQUFDO0lBQ04sQ0FBQztJQUVNLFVBQVU7UUFDYixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUM7SUFDaEMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FrQkc7SUFDSSxtQkFBbUIsQ0FDdEIsT0FBTyxHQUFHLEVBQUUsRUFDWixXQUEwQixFQUFFO1FBRTVCLE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBQzVCLGFBQWE7UUFDYixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDeEQsTUFBTSxrQkFBa0IsR0FBd0IsQ0FBQyxDQUFDLEdBQUcsQ0FDakQsY0FBYyxFQUNkLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxFQUFFO1lBQ2xCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQzFCLE1BQU0sRUFDTixPQUFPLEVBQ1AsU0FBUyxDQUNaLENBQUM7WUFFRixnRUFBZ0U7WUFDaEUsdUJBQXVCO1lBQ3ZCLElBQUksTUFBTSxZQUFZLGFBQWEsRUFBRTtnQkFDakMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxXQUErQixFQUFFLEVBQUU7b0JBQ2xELElBQUksV0FBVyxDQUFDLGVBQWUsQ0FBQyxFQUFFO3dCQUM5QixXQUFXLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztxQkFDeEU7Z0JBQ0wsQ0FBQyxDQUFDLENBQUM7YUFDTjtZQUVELHlCQUF5QjtZQUN6QixtREFBbUQ7WUFDbkQsd0RBQXdEO1lBQ3hELHdCQUF3QjtZQUN4QixPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLENBQUMsS0FBeUIsRUFBRSxFQUFFO2dCQUNsRCwyREFBMkQ7Z0JBQzNELDJDQUEyQztnQkFDM0MsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEVBQUU7b0JBRTFCLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FDWCxnQkFBZ0IsRUFDaEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssS0FBSyxDQUFDLGtCQUFrQixDQUN0QyxLQUFLLENBQUMsQ0FBQyxFQUFFO3dCQUNOLE9BQU8sSUFBSSxDQUFDO3FCQUNmO29CQUVELGdCQUFnQixDQUFDLElBQUksQ0FDakIsS0FBSyxDQUFDLGtCQUFrQixDQUMzQixDQUFDO2lCQUNMO2dCQUVELE9BQU8sS0FBSyxDQUFDO1lBQ2pCLENBQUMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUNKLENBQUM7UUFFRixNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxZQUFZLENBQ3BDLGtCQUFrQixDQUNyQixDQUFDO1FBRUYsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDeEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxjQUFjLENBQ2pCLElBQVksRUFDWixPQUEwQjtRQUcxQixNQUFNLFlBQVksR0FBRyxDQUFDLENBQUMsSUFBSSxDQUN2QixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUNqQixDQUFDLENBQXFCLEVBQUUsRUFBRSxDQUN0QixDQUFDLENBQUMsa0JBQWtCLEtBQUssSUFBSSxDQUNwQyxDQUFDO1FBRUYsT0FBTyxZQUFZO1lBQ2YsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1lBQ2hCLENBQUMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxlQUFlLENBQUMsR0FBVyxFQUFFLGlCQUE0QjtRQUM1RCxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRTdDLElBQUksV0FBVyxFQUFFO1lBQ2IsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hDLE1BQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNsQyxNQUFNLEdBQUcsR0FBRyxRQUFRO2dCQUNoQixDQUFDLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQztnQkFDbEMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7WUFFdEIsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FDaEIsR0FBRyxFQUNILENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLEVBQ2xELFNBQVMsQ0FDWixDQUFDO1lBRUYsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFO2dCQUN0QixlQUFlLENBQUMsY0FBYyxDQUMxQixnQkFBZ0IsR0FBRyxHQUFHLEVBQ3RCO29CQUNJLFlBQVksRUFBRSxJQUFJLENBQUMsVUFBVTtvQkFDN0IsVUFBVSxFQUFFLEdBQUc7b0JBQ2YsUUFBUSxFQUFFLGlCQUFpQjt3QkFDdkIsQ0FBQyxDQUFDLFlBQVksQ0FBQyxHQUFHLGlCQUFpQixDQUFDO3dCQUNwQyxDQUFDLENBQUMsU0FBUztpQkFDbEIsQ0FDSixDQUFDO2FBQ0w7WUFFRCxPQUFPLE1BQU0sQ0FBQztTQUVqQjthQUFNO1lBQ0gsTUFBTSxJQUFJLFlBQVksQ0FDbEIsb0JBQW9CLEdBQUcsMEJBQTBCLEVBQ2pEO2dCQUNJLFlBQVksRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDN0IsVUFBVSxFQUFFLEdBQUc7Z0JBQ2YsUUFBUSxFQUFFLGlCQUFpQjtvQkFDdkIsQ0FBQyxDQUFDLFlBQVksQ0FBQyxHQUFHLGlCQUFpQixDQUFDO29CQUNwQyxDQUFDLENBQUMsU0FBUzthQUNsQixDQUNKLENBQUM7U0FDTDtJQUNMLENBQUM7SUFxQ0Q7Ozs7T0FJRztJQUNJLGlCQUFpQixDQUNwQixRQUF1QjtRQUV2QixNQUFNLE1BQU0sR0FBc0IsSUFBSSxDQUFDLFVBQVUsQ0FBQztRQUVsRCxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1QsTUFBTSxJQUFJLFlBQVksQ0FBQztnQkFDbkIsK0JBQStCO2dCQUMvQixrREFBa0Q7YUFDckQsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUNoQjtRQUVELE1BQU0sTUFBTSxHQUFrQyxFQUFFLENBQUM7UUFDakQsTUFBTSxLQUFLLEdBQWMsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUV0QyxJQUFJLENBQUMsS0FBSyxFQUFFO1lBQ1IsTUFBTSxJQUFJLFlBQVksQ0FDbEIsc0NBQXNDLEVBQ3RDLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxDQUMzQixDQUFDO1NBQ0w7UUFFRCxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRTtZQUN0QiwwQkFBMEI7WUFDMUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQzdCLFNBQVM7YUFDWjtZQUVELE1BQU0sY0FBYyxHQUFHLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBRXZDLElBQUksQ0FBQyxJQUFJLEVBQUU7Z0JBQ1AsZUFBZSxDQUFDLGNBQWMsQ0FDMUIsa0NBQWtDLEVBQ2xDO29CQUNJLFlBQVksRUFBRSxNQUFNO29CQUNwQixRQUFRLEVBQUUsWUFBWSxDQUFDLEdBQUcsY0FBYyxDQUFDO2lCQUM1QyxDQUNKLENBQUM7Z0JBRUYsU0FBUzthQUNaO1lBRUQsTUFBTSxRQUFRLEdBQWlCLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFbEQsSUFBSSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUU7Z0JBQzNCLGVBQWUsQ0FBQyxjQUFjLENBQzFCLGlEQUFpRCxFQUNqRDtvQkFDSSxZQUFZLEVBQUUsTUFBTTtvQkFDcEIsUUFBUSxFQUFFLFlBQVksQ0FBQyxHQUFHLGNBQWMsQ0FBQztpQkFDNUMsQ0FDSixDQUFDO2dCQUVGLFNBQVM7YUFDWjtZQUVELE1BQU0sT0FBTyxHQUFHO2dCQUNaLFFBQVE7Z0JBQ1IsS0FBSztnQkFDTCxNQUFNO2dCQUNOLFNBQVM7Z0JBQ1QsT0FBTztnQkFDUCxNQUFNO2dCQUNOLEtBQUs7Z0JBQ0wsT0FBTzthQUNWLENBQUM7WUFFRixLQUFLLE1BQU0sVUFBVSxJQUFJLE9BQU8sRUFBRTtnQkFDOUIsMEJBQTBCO2dCQUMxQixJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsRUFBRTtvQkFDdEMsU0FBUztpQkFDWjtnQkFFRCxNQUFNLFlBQVksR0FBa0IsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN6RCxNQUFNLG1CQUFtQixHQUFHLENBQUMsR0FBRyxjQUFjLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBRTVELElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxFQUFFO29CQUMvQixlQUFlLENBQUMsY0FBYyxDQUMxQiwyQ0FBMkMsRUFDM0M7d0JBQ0ksWUFBWSxFQUFFLE1BQU07d0JBQ3BCLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxtQkFBbUIsQ0FBQztxQkFDakQsQ0FDSixDQUFDO29CQUVGLFNBQVM7aUJBQ1o7Z0JBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUMzQyxZQUFZLEVBQ1osVUFBVSxFQUNWLElBQUksRUFDSixtQkFBbUIsQ0FDdEIsQ0FBQztnQkFFRixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQ3JDLFlBQVksRUFDWixtQkFBbUIsQ0FDdEIsQ0FBQztnQkFFRixNQUFNLFlBQVksR0FBZ0I7b0JBQzlCLGFBQWEsRUFBRSxtQkFBbUI7b0JBQ2xDLFlBQVk7b0JBQ1osYUFBYSxFQUFFLElBQUk7b0JBQ25CLGdCQUFnQixFQUFFLElBQUk7b0JBQ3RCLE1BQU0sRUFBRSxVQUFVLENBQUMsV0FBVyxFQUFTO29CQUN2QyxRQUFRLEVBQUUsRUFBRTtvQkFDWixlQUFlLEVBQUUsSUFBSTtvQkFDckIsWUFBWSxFQUFFLElBQUk7b0JBQ2xCLElBQUk7b0JBQ0osV0FBVyxFQUFFLEVBQUU7b0JBQ2YsaUJBQWlCLEVBQUUsS0FBSztvQkFDeEIsZ0JBQWdCLEVBQUUsSUFBSTtvQkFDdEIsYUFBYSxFQUFFLElBQUk7b0JBQ25CLGlCQUFpQixFQUFFLElBQUk7b0JBQ3ZCLGNBQWMsRUFBRSxJQUFJO29CQUNwQixPQUFPO29CQUNQLGlCQUFpQjtvQkFDakIsbUJBQW1CLEVBQUUsRUFBRTtvQkFDdkIsZ0JBQWdCLEVBQUUsU0FBUztpQkFDOUIsQ0FBQztnQkFFRixJQUFJLHNCQUFnQyxDQUFDO2dCQUVyQyxJQUFHO29CQUNDLHNCQUFzQixHQUFHLENBQUMsR0FBRyxtQkFBbUIsRUFBRSxZQUFZLENBQUMsQ0FBQztvQkFDaEUseUJBQXlCO29CQUN6QixDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFDWCxJQUFJLENBQUMsd0JBQXdCLENBQ3pCLFlBQVksRUFDWixZQUFZLENBQUMsVUFBVSxFQUN2QixzQkFBc0IsQ0FDekIsQ0FDSixDQUFDO2lCQUNMO2dCQUFDLE9BQU0sS0FBSyxFQUFFO29CQUNYLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUUzQixNQUFNLElBQUksWUFBWSxDQUNsQixpREFBaUQsRUFDakQ7d0JBQ0ksWUFBWSxFQUFFLE1BQU07d0JBQ3BCLFFBQVEsRUFBRSxZQUFZLENBQUMsR0FBRyxzQkFBc0IsQ0FBQzt3QkFDakQsYUFBYSxFQUFFLEtBQUs7cUJBQ3ZCLENBQ0osQ0FBQztpQkFDTDtnQkFFRCxJQUFJO29CQUNBLHNCQUFzQixHQUFHLENBQUMsR0FBRyxtQkFBbUIsRUFBRSxXQUFXLENBQUMsQ0FBQztvQkFDL0Qsd0JBQXdCO29CQUN4QixDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFDWCxJQUFJLENBQUMsdUJBQXVCLENBQ3hCLFlBQVksRUFDWixZQUFZLENBQUMsU0FBUyxJQUFJLEVBQVMsRUFDbkMsc0JBQXNCLENBQ3pCLENBQ0osQ0FBQztpQkFDTDtnQkFBQyxPQUFNLEtBQUssRUFBRTtvQkFDWCxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFFM0IsTUFBTSxJQUFJLFlBQVksQ0FDbEIsZ0RBQWdELEVBQ2hEO3dCQUNJLFlBQVksRUFBRSxNQUFNO3dCQUNwQixRQUFRLEVBQUUsWUFBWSxDQUFDLEdBQUcsc0JBQXNCLENBQUM7d0JBQ2pELGFBQWEsRUFBRSxLQUFLO3FCQUN2QixDQUNKLENBQUM7aUJBQ0w7Z0JBRUQsSUFBSTtvQkFDQSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsbUJBQW1CLEVBQUUsYUFBYSxDQUFDLENBQUM7b0JBQ2pFLDJCQUEyQjtvQkFDM0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQ1gsSUFBSSxDQUFDLHFCQUFxQixDQUN0QixZQUFZLEVBQ1osWUFBWSxFQUNaLENBQUMsR0FBRyxzQkFBc0IsQ0FBQyxDQUM5QixDQUNKLENBQUM7aUJBQ0w7Z0JBQUMsT0FBTSxLQUFLLEVBQUU7b0JBQ1gsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBRTNCLE1BQU0sSUFBSSxZQUFZLENBQ2xCLG1EQUFtRCxFQUNuRDt3QkFDSSxZQUFZLEVBQUUsTUFBTTt3QkFDcEIsUUFBUSxFQUFFLFlBQVksQ0FBQyxHQUFHLHNCQUFzQixDQUFDO3dCQUNqRCxhQUFhLEVBQUUsS0FBSztxQkFDdkIsQ0FDSixDQUFDO2lCQUNMO2dCQUVELFFBQVEsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQzVCLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDO29CQUN0QixpQkFBaUIsRUFBRSxtQkFBbUI7b0JBQ3RDLE9BQU8sRUFBRSxZQUFZO2lCQUN4QixDQUFDLENBQUM7YUFDTjtTQUNKO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQztJQUVEOzs7T0FHRztJQUNPLHdCQUF3QixDQUM5QixZQUF5QixFQUN6QixVQUEyQixFQUMzQixtQkFBNkI7UUFHN0IsTUFBTSxNQUFNLEdBQTRCLEVBQUUsQ0FBQztRQUMzQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFtQixDQUNuRCxZQUFZLENBQUMsWUFBWSxDQUM1QixDQUFDO1FBRUYsTUFBTSxZQUFZLEdBQWlCO1lBQy9CLFVBQVUsRUFBRSxFQUFFO1lBQ2QsUUFBUSxFQUFFLEVBQUU7WUFDWixJQUFJLEVBQUUsUUFBUTtTQUNqQixDQUFDO1FBRUYscUJBQXFCO1FBQ3JCLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLEVBQUUsRUFBRSxDQUFDLFNBQXdCLEVBQUUsS0FBSyxFQUFFLEVBQUU7WUFDekQsSUFBSSxTQUFTLENBQUMsSUFBSSxFQUFFO2dCQUNoQixTQUFTLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FDZixDQUFDLENBQUMsSUFBSSxDQUFnQixTQUFTLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUMxQyxJQUFJLENBQUMsZUFBZSxDQUNoQixTQUFTLENBQUMsSUFBSSxFQUNkLENBQUMsR0FBRyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FDMUMsQ0FDYSxDQUFDO2FBQ3RCO1lBRUQsSUFBSSxTQUFTLENBQUMsTUFBTSxFQUFFO2dCQUNsQixZQUFZLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUFDO2dCQUUzRCxJQUFJLFNBQVMsQ0FBQyxXQUFXLEVBQUU7b0JBQ3ZCLFNBQVMsQ0FBQyxNQUFNLENBQUMsV0FBVyxHQUFHLFNBQVMsQ0FBQyxXQUFXLENBQUM7aUJBQ3hEO2dCQUVELElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRTtvQkFDcEIsWUFBWSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztpQkFDM0Q7Z0JBRUQsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFO29CQUNwQixZQUFZLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQzlDO2dCQUVELElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDckIsMERBQTBEO29CQUMxRCxZQUFZLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztvQkFDL0MsWUFBWSxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7aUJBQzVDO2dCQUVELElBQUksU0FBUyxDQUFDLEVBQUUsS0FBSyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUU7b0JBQzVDLFlBQVksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDakQ7Z0JBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUU7b0JBQzNCLFlBQVksQ0FBQyxXQUFXO3dCQUNwQixpQ0FBaUMsWUFBWSxDQUFDLElBQUksSUFBSSxDQUFDO2lCQUM5RDtnQkFFRCxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQUcsWUFBWSxDQUFDO2FBQzFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLE1BQU0sQ0FBQyxlQUFlLENBQUMsRUFBRTtZQUN6QixZQUFZLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1NBQzFEO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQztJQUVTLHVCQUF1QixDQUM3QixZQUF5QixFQUN6QixTQUFxQyxFQUNyQyxtQkFBNkI7UUFHN0IsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBRWxCLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQ2QsUUFBc0IsRUFDdEIsSUFBcUIsRUFDdkIsRUFBRTtZQUVBLDhDQUE4QztZQUM5QyxJQUFJLFFBQVEsQ0FBQyxJQUFJLEVBQUU7Z0JBQ2YsUUFBUSxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQ2QsQ0FBQyxDQUFDLElBQUksQ0FBZSxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUN4QyxJQUFJLENBQUMsZUFBZSxDQUNoQixRQUFRLENBQUMsSUFBSSxFQUNiLENBQUMsR0FBRyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FDekMsQ0FDWSxDQUFDO2FBQ3JCO1lBRUQsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLE9BQU87bUJBQ3hCLFFBQVEsQ0FBQyxNQUFNLENBQUUsZ0JBQWdCO21CQUNqQyxFQUFFLENBQUMsQ0FBYyxXQUFXO1lBRXZDLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDakMsVUFBVSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsSUFBSSxDQUFDO2FBQ3pDO1lBRUQsc0RBQXNEO1lBQ3RELENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLEVBQUUsRUFBRSxDQUNyQixZQUE4QixFQUM5QixjQUFzQixFQUN4QixFQUFFO2dCQUNBLDJDQUEyQztnQkFDM0MsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsUUFBUSxDQUFDO3VCQUNyQzt3QkFDQyxXQUFXLEVBQUUsZ0JBQWdCO3dCQUM3QixJQUFJLEVBQUUsTUFBTTtxQkFDZixDQUFDLENBQUcsYUFBYTtnQkFFdEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUU7b0JBQzlCLFlBQVksQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO2lCQUNwQztnQkFFRCw4QkFBOEI7Z0JBQzlCLElBQUksUUFBUSxDQUFDLFdBQVcsRUFBRTtvQkFDdEIsTUFBTSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDO2lCQUM3QztnQkFFRCxDQUFDLENBQUMsR0FBRyxDQUNELFlBQVksQ0FBQyxjQUFjLEVBQzNCLENBQUMsSUFBSSxFQUFFLGNBQWMsQ0FBQyxFQUN0QixNQUFNLENBQ1QsQ0FBQztZQUNOLENBQUMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxRQUFRLENBQUMsT0FBTyxFQUFFO2dCQUNsQix3QkFBd0I7Z0JBQ3hCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQzFDLFlBQVksQ0FBQyxZQUFZLEVBQ3pCLElBQUksQ0FDUCxDQUFDO2dCQUVGLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRztvQkFDaEIsVUFBVSxFQUFFLFFBQVEsQ0FBQyxPQUFPO29CQUM1QixJQUFJLEVBQUUsUUFBUTtpQkFDakIsQ0FBQzthQUNMO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLFlBQVksQ0FBQyxjQUFjLEVBQUU7WUFDN0IsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsQ0FDM0MsWUFBWSxDQUFDLFlBQVksRUFDekIsRUFBRSxFQUNGLEVBQUUsQ0FDTCxDQUFDO1lBRUYsWUFBWSxDQUFDLGlCQUFpQixHQUFHLFNBQVMsQ0FBQztZQUMzQyxZQUFZLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRWpELE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxJQUFJLGFBQWEsQ0FDakMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsY0FBYyxFQUFFLFNBQVMsQ0FBQyxFQUFFLENBQ2pELElBQUksYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUMvQixDQUNKLENBQUM7U0FDTDtRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFFUyxxQkFBcUIsQ0FDM0IsWUFBMkIsRUFDM0IsWUFBeUIsRUFDekIsbUJBQTZCO1FBSzdCLE1BQU0sRUFBRSxXQUFXLEVBQUUsR0FBRyxZQUFZLENBQUM7UUFDckMsSUFBSSxTQUF3QyxDQUFDO1FBRTdDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDZCxPQUFPLElBQUksQ0FBQztTQUNmO2FBQU07WUFDSCxZQUFZLENBQUMsaUJBQWlCLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUM7WUFFeEQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUU7Z0JBQ3RCLE9BQU8sSUFBSSxDQUFDO2FBQ2Y7WUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUMxQyxZQUFZLENBQUMsWUFBWSxDQUM1QixDQUFDO1lBRUYsU0FBUyxHQUFHLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDO2lCQUM3QixTQUFTLENBQUMsQ0FBQyxZQUE4QixFQUFFLGFBQWEsRUFBRSxFQUFFO2dCQUN6RCxNQUFNLFNBQVMsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsbUJBQUssWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDO2dCQUN4RSxJQUFJLFlBQVksQ0FBQyxXQUFXLENBQUMsV0FBVyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRTtvQkFDaEUsU0FBUyxDQUFDLFdBQVcsR0FBRyxZQUFZLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQztpQkFDaEU7Z0JBRUQsT0FBTyxTQUFTLENBQUM7WUFDckIsQ0FBQyxDQUFDO2lCQUNELEtBQUssRUFBRSxDQUFDO1lBRWIsWUFBWSxDQUFDLGdCQUFnQixHQUFHLFNBQVMsQ0FBQztZQUMxQyxZQUFZLENBQUMsYUFBYSxHQUFHLFNBQVMsQ0FBQztZQUN2QyxZQUFZLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRWpELE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsSUFBSSxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ25FO0lBQ0wsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNPLGNBQWMsQ0FDcEIsSUFBWSxFQUNaLE9BQTBCO1FBRzFCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFakUsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNULE1BQU0sSUFBSSxLQUFLLENBQ1gsdUNBQXVDLElBQUksR0FBRyxDQUNqRCxDQUFDO1NBQ0w7UUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUN4QixNQUFNLEVBQ04sT0FBTyxFQUNQLFNBQVMsRUFDVCxJQUFJLEVBQ0osSUFBSSxDQUNQLENBQUM7UUFFRixDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQTBCLEVBQUUsRUFBRTtZQUMzQyxPQUFPLENBQUMsTUFBTSxDQUFDLGtCQUFrQixJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxNQUFNLENBQUM7UUFDcEUsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLE9BQU8sQ0FBQztJQUNuQixDQUFDO0lBRVMsaUJBQWlCLENBQUMsR0FBVztRQUNuQyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRTtZQUN2QixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNyQzthQUFNO1lBQ0gsTUFBTSxJQUFJLFlBQVksQ0FDbEI7Z0JBQ0ksOENBQThDO2dCQUM5QyxtQ0FBbUMsR0FBRyxHQUFHO2FBQzVDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUNaO2dCQUNJLFlBQVksRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDN0IsVUFBVSxFQUFFLEdBQUc7YUFDbEIsQ0FDSixDQUFDO1NBQ0w7SUFDTCxDQUFDO0lBRU8scUJBQXFCLENBQ3pCLFlBQTJCLEVBQzNCLFVBQWtCLEVBQ2xCLElBQVksRUFDWixtQkFBNkI7UUFFN0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsRUFBRTtZQUNwRSxNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FDN0MsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQ3hELENBQUMsQ0FBQztZQUVILGVBQWUsQ0FBQyxjQUFjLENBQzFCO2dCQUNJLHVCQUF1QixZQUFZLENBQUMsV0FBVyxJQUFJO2dCQUNuRCwwQkFBMEIsZ0JBQWdCLElBQUk7YUFDakQsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQ1o7Z0JBQ0ksWUFBWSxFQUFFLElBQUksQ0FBQyxVQUFVO2dCQUM3QixRQUFRLEVBQUUsWUFBWSxDQUFDLEdBQUcsbUJBQW1CLEVBQUUsYUFBYSxDQUFDO2FBQ2hFLENBQ0osQ0FBQztZQUVGLE9BQU8sZ0JBQWdCLENBQUM7U0FDM0I7UUFFRCxNQUFNLFdBQVcsR0FBRyxDQUFDLENBQUMsU0FBUyxDQUMzQixZQUFZLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQzFELENBQUM7UUFFRixPQUFPLENBQUMsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUk7WUFDaEMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7WUFDeEIsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ2xDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ2YsQ0FBQztJQUVPLG9CQUFvQixDQUN4QixZQUEyQixFQUMzQixtQkFBNkI7UUFFN0IsSUFBSSxPQUFPLEdBQUcsWUFBWSxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQztRQUU5RCxJQUFJLE9BQU8sS0FBSyxTQUFTLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQzlDLGVBQWUsQ0FBQyxjQUFjLENBQUMsbUNBQW1DLEVBQUU7Z0JBQ2hFLFlBQVksRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDN0IsUUFBUSxFQUFFLFlBQVksQ0FBQyxHQUFHLG1CQUFtQixFQUFFLFNBQVMsQ0FBQzthQUM1RCxDQUFDLENBQUM7WUFFSCxPQUFPLEdBQUcsRUFBRSxDQUFDO1NBQ2hCO1FBRUQsSUFBSSxDQUFDLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUNoQyxPQUFPLEdBQUcsYUFBYSxDQUFDLGlCQUFpQixDQUFDO1NBQzdDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCAqIGFzIGpzb25Qb2ludGVyIGZyb20gJ2pzb24tcG9pbnRlcic7XG5cbmltcG9ydCB7IEhhc1Jlc3BvbnNlcywgSGFzQ29udGVudFR5cGUgfSBmcm9tICdAY29kZWdlbmEvZGVmaW5pdGlvbnMvYXNwZWN0cyc7XG5pbXBvcnQge1xuICAgIEdlbmVyaWMgYXMgU2NoZW1hR2VuZXJpYyxcbiAgICBTY2hlbWEsXG4gICAgU2NoZW1hT2JqZWN0XG59IGZyb20gJ0Bjb2RlZ2VuYS9kZWZpbml0aW9ucy9qc29uLXNjaGVtYSc7XG5pbXBvcnQge1xuICAgIE9hczNNZWRpYUNvbnRlbnQsXG4gICAgT2FzM09wZXJhdGlvbixcbiAgICBPYXMzUGFyYW1ldGVyLFxuICAgIE9hczNQYXJhbWV0ZXJUYXJnZXQsXG4gICAgT2FzM1BhdGhJdGVtLFxuICAgIE9hczNQYXRocyxcbiAgICBPYXMzUmVzcG9uc2UsXG4gICAgT2FzM1NwZWNpZmljYXRpb24sXG4gICAgT2FzM1NlcnZlcixcbn0gZnJvbSAnQGNvZGVnZW5hL2RlZmluaXRpb25zL29hczMnO1xuXG5pbXBvcnQgeyBDb252ZXJ0b3JDb25maWcsIGRlZmF1bHRDb25maWcgfSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBQYXJzaW5nRXJyb3IsIFBhcnNpbmdQcm9ibGVtcyB9IGZyb20gJy4vcGFyc2luZy1wcm9ibGVtcyc7XG5pbXBvcnQge1xuICAgIEFwaU1ldGFJbmZvLFxuICAgIERhdGFUeXBlQ29udGFpbmVyLFxuICAgIERhdGFUeXBlRGVzY3JpcHRvcixcbiAgICBEZXNjcmlwdG9yQ29udGV4dFxufSBmcm9tICcuL2luZGV4JztcblxuY29uc3QganNvblBhdGhSZWdleCA9IC8oW1xcdzpcXC9cXFxcXFwuXSspPyMoXFwvP1tcXHcrXFwvP10rKS87XG5cbi8qKlxuICogQHBhcmFtIHBpZWNlc1xuICogQHJldHVyblxuICogSlNPTi1QYXRoIGFjY29yZGluZyB0byBbUkZDLTY5MDFdKGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM2OTAxKVxuICogVE9ETyByZWZhY3RvcjogbW92ZSB0byBjb21tb24gaGVscGVyXG4gKi9cbmZ1bmN0aW9uIG1ha2VKc29uUGF0aCguLi5waWVjZXM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pOiBzdHJpbmcge1xuICAgIHJldHVybiBqc29uUG9pbnRlci5jb21waWxlKHBpZWNlcyk7XG59XG5cbi8qKlxuICogUmV0aHJvdyB7QGxpbmsgUGFyc2luZ0Vycm9yfSBpZiBvcmlnaW5hbCBlcnJvciBhbHJlYWR5IGhhbmRsZWQgYXQgaW5uZXIgbGV2ZWxcbiAqIEBwYXJhbSB7UGFyc2luZ0Vycm9yIHwgYW55fSBlcnJvclxuICovXG5mdW5jdGlvbiByZXRocm93UGFyc2luZ0Vycm9yKGVycm9yOiBQYXJzaW5nRXJyb3IgfCBhbnkpOiB2b2lkIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBQYXJzaW5nRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxufVxuXG5pbnRlcmZhY2UgT3BlcmF0aW9uTWV0YSB7XG4gICAgb3BlcmF0aW9uSnNvblBhdGg6IHN0cmluZ1tdO1xuICAgIGFwaU1ldGE6IEFwaU1ldGFJbmZvO1xufVxuXG4vKipcbiAqINCR0LDQt9C+0LLRi9C5INC60LvQsNGB0YEg0LfQsNCz0YDRg9C30YfQuNC60LAuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlQ29udmVydG9yIHtcblxuICAgIHByb3RlY3RlZCBfc3RydWN0dXJlOiBPYXMzU3BlY2lmaWNhdGlvbjtcbiAgICBwcm90ZWN0ZWQgX2ZvcmVpZ25TY2hlbWFGbjogKHJlc291cmNlUGF0aDogc3RyaW5nKSA9PiBTY2hlbWE7XG4gICAgcHJvdGVjdGVkIF9vcGVyYXRpb25zTWV0YTogT3BlcmF0aW9uTWV0YVtdO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByb3RlY3RlZCBjb25maWc6IENvbnZlcnRvckNvbmZpZyA9IGRlZmF1bHRDb25maWdcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbG9hZE9BUEkzU3RydWN0dXJlKHN0cnVjdHVyZTogT2FzM1NwZWNpZmljYXRpb24pIHtcbiAgICAgICAgaWYgKCFzdHJ1Y3R1cmUgfHwgIV8uaXNPYmplY3RMaWtlKHN0cnVjdHVyZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzaW5nRXJyb3IoW1xuICAgICAgICAgICAgICAgIGBFeHBlY3RlZCBzdHJ1Y3R1cmUgdG8gYmUgb2JqZWN0IGJ1dCBnb3Q6YCxcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShzdHJ1Y3R1cmUsIG51bGwsICcgJylcbiAgICAgICAgICAgIF0uam9pbignXFxuJykpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fb3BlcmF0aW9uc01ldGEgPSBbXTtcbiAgICAgICAgdGhpcy5fc3RydWN0dXJlID0gc3RydWN0dXJlO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRGb3JlaWduU2NoZW1lRm4oZm46IChqc29uUGF0aDogc3RyaW5nKSA9PiBTY2hlbWEpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFfLmlzRnVuY3Rpb24oZm4pKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2luZ0Vycm9yKCdFcnJvciBpbiBgc2V0Rm9yZWlnblNjaGVtZUZuYDogYXJndW1lbnQgaGFzIHRvIGJlIGZ1bmN0aW9uIScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fZm9yZWlnblNjaGVtYUZuID0gKGpzb25QYXRoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmbihqc29uUGF0aCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNpbmdFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgJ0Vycm9yIHdoZW4gdHJ5aW5nIHRvIHJlc29sdmUgc2NoZW1hIScsXG4gICAgICAgICAgICAgICAgICAgIHsganNvblBhdGggfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGdldEFwaU1ldGEoKTogT3BlcmF0aW9uTWV0YVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX29wZXJhdGlvbnNNZXRhO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHRpbmcgb2YgXCJlbnRyeS1wb2ludHNcIiBmcm9tIHN0cnVjdHVyZSBpbiB7QGxpbmsgX3N0cnVjdHVyZX0gZWFybHlcbiAgICAgKiBsb2FkZWQgYnkge0BsaW5rIGxvYWRPQVBJM1N0cnVjdHVyZX0uXG4gICAgICpcbiAgICAgKiBFbnRyeXBvaW50cyBhcmU6XG4gICAgICpcbiAgICAgKiAtIFBhcmFtZXRlcnNcbiAgICAgKiAtIFJlcXVlc3RzXG4gICAgICogLSBSZXNwb25zZXNcbiAgICAgKlxuICAgICAqICMjIyBXaHkgaXQgbmVlZGVkP1xuICAgICAqXG4gICAgICogRW50cnlwb2ludHMgaXMgbmVlZGVkIHRvIHVzZSBbQ29udmVydG9yLnJlbmRlclJlY3Vyc2l2ZV17QGxpbmsgQ29udmVydG9yLnJlbmRlclJlY3Vyc2l2ZX0uXG4gICAgICogSXQncyBsaWtlIGEgcHVsbGluZyBvbiB0aHJlYWQgd2hlcmUgZW50cnlwb2ludHMgYXJlIG91dHN0YW5kaW5nIHRyaGVhZHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gQXBpTWV0YUluZm8gbWV0YUluZm9cbiAgICAgKiBNdXRhYmxlIG9iamVjdCB3aGVyZSBtZXRhLWluZm9ybWF0aW9uIGFjY3VtdWxhdGVzIGR1cmluZ1xuICAgICAqIEFQSS1pbmZvIGV4dHJhY3RpbmcuXG4gICAgICovXG4gICAgcHVibGljIGdldE9BUEkzRW50cnlQb2ludHMoXG4gICAgICAgIGNvbnRleHQgPSB7fSxcbiAgICAgICAgbWV0YUluZm86IEFwaU1ldGFJbmZvW10gPSBbXVxuICAgICk6IERhdGFUeXBlQ29udGFpbmVyIHtcbiAgICAgICAgY29uc3QgYWxyZWFkeUNvbnZlcnRlZCA9IFtdO1xuICAgICAgICAvLyBwYXJhbWV0ZXJzXG4gICAgICAgIGNvbnN0IG1ldGhvZHNTY2hlbWVzID0gdGhpcy5nZXRNZXRob2RzU2NoZW1lcyhtZXRhSW5mbyk7XG4gICAgICAgIGNvbnN0IGRhdGFUeXBlQ29udGFpbmVyczogRGF0YVR5cGVDb250YWluZXJbXSA9IF8ubWFwKFxuICAgICAgICAgICAgbWV0aG9kc1NjaGVtZXMsXG4gICAgICAgICAgICAoc2NoZW1hLCBtb2RlbE5hbWUpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmNvbnZlcnQoXG4gICAgICAgICAgICAgICAgICAgIHNjaGVtYSxcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgbW9kZWxOYW1lXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIC8vIFRPRE8gQ3J1dGNoLiBUaGlzIGNsYXNzIHNob3VsZCBuZXZlciBrbm93IGFib3V0IGFzc2lnbmVkVHlwZXNcbiAgICAgICAgICAgICAgICAvLyBpbiBHZW5lcmljRGVzY3JpcHRvclxuICAgICAgICAgICAgICAgIGlmIChzY2hlbWEgaW5zdGFuY2VvZiBTY2hlbWFHZW5lcmljKSB7XG4gICAgICAgICAgICAgICAgICAgIF8uZWFjaChjb250YWluZXIsIChkZXNjcmlwdGlvbjogRGF0YVR5cGVEZXNjcmlwdG9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVzY3JpcHRpb25bJ2Fzc2lnbmVkVHlwZXMnXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uWydhc3NpZ25lZFR5cGVzJ10gPSBbJ1RDb2RlJywgJ1RDb250ZW50VHlwZScsICdUMScsICdUMiddO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyDQmNGB0LrQu9GO0YfQtdC90LjQtSDQtNGD0LHQu9C40LrQsNGC0L7Qsi5cbiAgICAgICAgICAgICAgICAvLyDQlNGD0LHQu9C40LrQsNGC0Ysg0L/QvtGP0LLQu9GP0Y7RgtGB0Y8sINC60L7Qs9C00LAg0YLQuNC/0Ysg0LTQsNC90L3Ri9C1LCDQutC+0YLQvtGA0YvQtVxuICAgICAgICAgICAgICAgIC8vINGB0YHRi9C70LDRjtGC0YHRjyAoJHJlZikg0LHQtdC3INC40LfQvNC10L3QtdC90LjRjyDQvdCwINC00YDRg9Cz0LjQtSwg0L/QvtC00LzQtdC90Y/RjtGC0YHRj1xuICAgICAgICAgICAgICAgIC8vINC80L7QtNC10LvRj9C80Lgg0LjQtyBgc2NoZW1hYC5cbiAgICAgICAgICAgICAgICByZXR1cm4gXy5tYXAoY29udGFpbmVyLCAoZGVzY3I6IERhdGFUeXBlRGVzY3JpcHRvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAvLyBFeGNsdWRpbmcgb2YgZWxlbWVudHMgaGF2aW5nIGNvbW1vbiBgb3JpZ2luYWxTY2hlbWFQYXRoYFxuICAgICAgICAgICAgICAgICAgICAvLyBhbmQgc2ltdWx0YW5lb3VzbHkgYWxyZWFkeSByZWxhdGVkIHdpdGguXG4gICAgICAgICAgICAgICAgICAgIGlmIChkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGgpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKF8uZmluZEluZGV4KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscmVhZHlDb252ZXJ0ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdiA9PiB2ID09PSBkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGFscmVhZHlDb252ZXJ0ZWQucHVzaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVzY3I7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgZGF0YVR5cGVDb250YWluZXIgPSBfLmZsYXR0ZW5EZXB0aDxEYXRhVHlwZURlc2NyaXB0b3I+KFxuICAgICAgICAgICAgZGF0YVR5cGVDb250YWluZXJzXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIF8uY29tcGFjdChkYXRhVHlwZUNvbnRhaW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/QvtC70YPRh9C40YLRjCDQtNC10YHQutGA0LjQv9GC0L7RgCDRgtC40L/QsCDQv9C+IEpTT04gUGF0aDpcbiAgICAgKiDQstC+0LfQstGA0LDRidCw0LXRgiDRg9C20LUg0YHQvtC30LTQsNC90L3Ri9C5INGA0LDQvdC10LUsINC40LvQuCDRgdC+0LfQtNCw0LXRglxuICAgICAqINC90L7QstGL0Lkg0L/RgNC4INC/0LXRgNCy0L7QvCDRg9C/0L7QvNC40L3QsNC90LjQuC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwYXRoXG4gICAgICogQHBhcmFtIGNvbnRleHRcbiAgICAgKi9cbiAgICBwdWJsaWMgZmluZFR5cGVCeVBhdGgoXG4gICAgICAgIHBhdGg6IHN0cmluZyxcbiAgICAgICAgY29udGV4dDogRGVzY3JpcHRvckNvbnRleHRcbiAgICApOiBEYXRhVHlwZUNvbnRhaW5lciB7XG5cbiAgICAgICAgY29uc3QgYWxyZWFkeUZvdW5kID0gXy5maW5kKFxuICAgICAgICAgICAgXy52YWx1ZXMoY29udGV4dCksXG4gICAgICAgICAgICAodjogRGF0YVR5cGVEZXNjcmlwdG9yKSA9PlxuICAgICAgICAgICAgICAgIHYub3JpZ2luYWxTY2hlbWFQYXRoID09PSBwYXRoXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIGFscmVhZHlGb3VuZFxuICAgICAgICAgICAgPyBbYWxyZWFkeUZvdW5kXVxuICAgICAgICAgICAgOiB0aGlzLl9wcm9jZXNzU2NoZW1hKHBhdGgsIGNvbnRleHQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBkZXByZWNhdGVkIHdpbGwgYmUgcmVuYW1lZCB0byBgZ2V0U2NoZW1hQnlSZWZgXG4gICAgICogQHBhcmFtIHJlZlxuICAgICAqIEBwYXJhbSBwYXRoV2hlcmVSZWZlcnJlZFxuICAgICAqIEByZXR1cm5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0U2NoZW1hQnlQYXRoKHJlZjogc3RyaW5nLCBwYXRoV2hlcmVSZWZlcnJlZD86IHN0cmluZ1tdKTogU2NoZW1hIHtcbiAgICAgICAgY29uc3QgcGF0aE1hdGNoZXMgPSByZWYubWF0Y2goanNvblBhdGhSZWdleCk7XG5cbiAgICAgICAgaWYgKHBhdGhNYXRjaGVzKSB7XG4gICAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGhNYXRjaGVzWzFdO1xuICAgICAgICAgICAgY29uc3Qgc2NoZW1hUGF0aCA9IHBhdGhNYXRjaGVzWzJdO1xuICAgICAgICAgICAgY29uc3Qgc3JjID0gZmlsZVBhdGhcbiAgICAgICAgICAgICAgICA/IHRoaXMuX2dldEZvcmVpZ25TY2hlbWEoZmlsZVBhdGgpXG4gICAgICAgICAgICAgICAgOiB0aGlzLl9zdHJ1Y3R1cmU7XG5cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IF8uZ2V0KFxuICAgICAgICAgICAgICAgIHNyYyxcbiAgICAgICAgICAgICAgICBfLnRyaW0oc2NoZW1hUGF0aCwgJyMvXFxcXCcpLnJlcGxhY2UoL1tcXFxcXFwvXS9nLCAnLicpLFxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgaWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgUGFyc2luZ1Byb2JsZW1zLnBhcnNpbmdXYXJuaW5nKFxuICAgICAgICAgICAgICAgICAgICBgQ2FudCByZXNvbHZlICR7cmVmfSFgLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYXNTdHJ1Y3R1cmU6IHRoaXMuX3N0cnVjdHVyZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRSZWY6IHJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIGpzb25QYXRoOiBwYXRoV2hlcmVSZWZlcnJlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gbWFrZUpzb25QYXRoKC4uLnBhdGhXaGVyZVJlZmVycmVkKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2luZ0Vycm9yKFxuICAgICAgICAgICAgICAgIGBKU09OIFBhdGggZXJyb3I6ICR7cmVmfSBpcyBub3QgdmFsaWQgSlNPTiBwYXRoIWAsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBvYXNTdHJ1Y3R1cmU6IHRoaXMuX3N0cnVjdHVyZSxcbiAgICAgICAgICAgICAgICAgICAgcmVsYXRlZFJlZjogcmVmLFxuICAgICAgICAgICAgICAgICAgICBqc29uUGF0aDogcGF0aFdoZXJlUmVmZXJyZWRcbiAgICAgICAgICAgICAgICAgICAgICAgID8gbWFrZUpzb25QYXRoKC4uLnBhdGhXaGVyZVJlZmVycmVkKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/RgNC10LLRgNCw0YnQtdC90LjQtSBKU09OLdGB0YXQtdC80Ysg0LIg0L7Qv9C40YHQsNC90LjQtSDRgtC40L/QsCDQtNCw0L3QvdGL0YUuXG4gICAgICog0JLQvtC30LLRgNCw0YnQsNC10YIg0LrQvtC90YLQtdC50L3QtdGAIFvQtNC10YHQutGA0LjQv9GC0L7RgNC+0LIg0YLQuNC/0L7Qsl17QGxpbmsgRGF0YVR5cGVEZXNjcmlwdG9yfSxcbiAgICAgKiDQsiDQutC+0YLQvtGA0L7QvCDQv9C10YDQtdGH0LjRgdC70Y/RjtGC0YHRjyDRgtC40L/RiyDQtNCw0L3QvdGL0YUgKNCy0L7Qt9C80L7QttC90LAg0L/RgNC40L3QsNC00LvQtdC20L3QvtGB0YLRjFxuICAgICAqINC6INCx0L7Qu9C10LUg0YfQtdC8INC+0LTQvdC+0LzRgyDRgtC40L/RgyDQtNCw0L3QvdGL0YU6IGBudW1iZXJbXSB8IEludGVyZmFjZU5hbWVgKS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzY2hlbWFcbiAgICAgKiDQodGF0LXQvNC