UNPKG

mzinga

Version:

Node, React and MongoDB Headless CMS and Application Framework

520 lines (519 loc) 73.3 kB
/* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable no-await-in-loop */ /* eslint-disable no-restricted-syntax */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return _default; } }); const _graphql = require("graphql"); const _graphqlscalars = require("graphql-scalars"); const _graphqltypejson = require("graphql-type-json"); const _types = require("../../fields/config/types"); const _formatLabels = require("../../utilities/formatLabels"); const _combineParentName = /*#__PURE__*/ _interop_require_default(require("../utilities/combineParentName")); const _formatName = /*#__PURE__*/ _interop_require_default(require("../utilities/formatName")); const _formatOptions = /*#__PURE__*/ _interop_require_default(require("../utilities/formatOptions")); const _buildWhereInputType = /*#__PURE__*/ _interop_require_default(require("./buildWhereInputType")); const _isFieldNullable = /*#__PURE__*/ _interop_require_default(require("./isFieldNullable")); const _withNullableType = /*#__PURE__*/ _interop_require_default(require("./withNullableType")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function buildObjectType({ name, baseFields = {}, fields, forceNullable, parentName, payload }) { const fieldToSchemaMap = { array: (objectTypeConfig, field)=>{ const interfaceName = field?.interfaceName || (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(field.name, true)); if (!payload.types.arrayTypes[interfaceName]) { const objectType = buildObjectType({ name: interfaceName, fields: field.fields, forceNullable: (0, _isFieldNullable.default)(field, forceNullable), parentName: interfaceName, payload }); if (Object.keys(objectType.getFields()).length) { payload.types.arrayTypes[interfaceName] = objectType; } } if (!payload.types.arrayTypes[interfaceName]) { return objectTypeConfig; } const arrayType = new _graphql.GraphQLList(new _graphql.GraphQLNonNull(payload.types.arrayTypes[interfaceName])); return { ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, arrayType) } }; }, blocks: (objectTypeConfig, field)=>{ const blockTypes = field.blocks.reduce((acc, block)=>{ if (!payload.types.blockTypes[block.slug]) { const interfaceName = block?.interfaceName || block?.graphQL?.singularName || (0, _formatLabels.toWords)(block.slug, true); const objectType = buildObjectType({ name: interfaceName, fields: [ ...block.fields, { name: 'blockType', type: 'text' } ], forceNullable, parentName: interfaceName, payload }); if (Object.keys(objectType.getFields()).length) { payload.types.blockTypes[block.slug] = objectType; } } if (payload.types.blockTypes[block.slug]) { acc.push(payload.types.blockTypes[block.slug]); } return acc; }, []); if (blockTypes.length === 0) { return objectTypeConfig; } const fullName = (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(field.name, true)); const type = new _graphql.GraphQLList(new _graphql.GraphQLNonNull(new _graphql.GraphQLUnionType({ name: fullName, resolveType: (data)=>payload.types.blockTypes[data.blockType].name, types: blockTypes }))); return { ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, type) } }; }, checkbox: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphql.GraphQLBoolean, forceNullable) } }), code: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphql.GraphQLString, forceNullable) } }), collapsible: (objectTypeConfig, field)=>field.fields.reduce((objectTypeConfigWithCollapsibleFields, subField)=>{ const addSubField = fieldToSchemaMap[subField.type]; if (addSubField) return addSubField(objectTypeConfigWithCollapsibleFields, subField); return objectTypeConfigWithCollapsibleFields; }, objectTypeConfig), date: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphqlscalars.DateTimeResolver, forceNullable) } }), email: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphqlscalars.EmailAddressResolver, forceNullable) } }), group: (objectTypeConfig, field)=>{ const interfaceName = field?.interfaceName || (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(field.name, true)); if (!payload.types.groupTypes[interfaceName]) { const objectType = buildObjectType({ name: interfaceName, fields: field.fields, forceNullable: (0, _isFieldNullable.default)(field, forceNullable), parentName: interfaceName, payload }); if (Object.keys(objectType.getFields()).length) { payload.types.groupTypes[interfaceName] = objectType; } } if (!payload.types.groupTypes[interfaceName]) { return objectTypeConfig; } return { ...objectTypeConfig, [field.name]: { type: payload.types.groupTypes[interfaceName] } }; }, json: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphqltypejson.GraphQLJSON, forceNullable) } }), number: (objectTypeConfig, field)=>{ const type = field?.name === 'id' ? _graphql.GraphQLInt : _graphql.GraphQLFloat; return { ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, field?.hasMany === true ? new _graphql.GraphQLList(type) : type, forceNullable) } }; }, point: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, new _graphql.GraphQLList(new _graphql.GraphQLNonNull(_graphql.GraphQLFloat)), forceNullable) } }), radio: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, new _graphql.GraphQLEnumType({ name: (0, _combineParentName.default)(parentName, field.name), values: (0, _formatOptions.default)(field) }), forceNullable) } }), relationship: (objectTypeConfig, field)=>{ const { relationTo } = field; const isRelatedToManyCollections = Array.isArray(relationTo); const hasManyValues = field.hasMany; const relationshipName = (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(field.name, true)); let type; let relationToType = null; if (Array.isArray(relationTo)) { relationToType = new _graphql.GraphQLEnumType({ name: `${relationshipName}_RelationTo`, values: relationTo.reduce((relations, relation)=>({ ...relations, [(0, _formatName.default)(relation)]: { value: relation } }), {}) }); const types = relationTo.map((relation)=>payload.collections[relation].graphQL.type); type = new _graphql.GraphQLObjectType({ name: `${relationshipName}_Relationship`, fields: { relationTo: { type: relationToType }, value: { type: new _graphql.GraphQLUnionType({ name: relationshipName, async resolveType (data, { req }) { return payload.collections[data.collection].graphQL.type.name; }, types }) } } }); } else { ({ type } = payload.collections[relationTo].graphQL); } // If the relationshipType is undefined at this point, // it can be assumed that this blockType can have a relationship // to itself. Therefore, we set the relationshipType equal to the blockType // that is currently being created. type = type || newlyCreatedBlockType; const relationshipArgs = {}; const relationsUseDrafts = (Array.isArray(relationTo) ? relationTo : [ relationTo ]).some((relation)=>payload.collections[relation].config.versions?.drafts); if (relationsUseDrafts) { relationshipArgs.draft = { type: _graphql.GraphQLBoolean }; } if (payload.config.localization) { relationshipArgs.locale = { type: payload.types.localeInputType }; relationshipArgs.fallbackLocale = { type: payload.types.fallbackLocaleInputType }; } const relationship = { type: (0, _withNullableType.default)(field, hasManyValues ? new _graphql.GraphQLList(new _graphql.GraphQLNonNull(type)) : type, forceNullable), args: relationshipArgs, extensions: { complexity: 10 }, async resolve (parent, args, context) { const value = parent[field.name]; const locale = args.locale || context.req.locale; const fallbackLocale = args.fallbackLocale || context.req.fallbackLocale; let relatedCollectionSlug = field.relationTo; const draft = args.draft ?? context.req.query?.draft; if (hasManyValues) { const results = []; const resultPromises = []; const createPopulationPromise = async (relatedDoc, i)=>{ let id = relatedDoc; let collectionSlug = field.relationTo; if (isRelatedToManyCollections) { collectionSlug = relatedDoc.relationTo; id = relatedDoc.value; } const result = await context.req.payloadDataLoader.load(JSON.stringify([ context.req.transactionID, collectionSlug, id, 0, 0, locale, fallbackLocale, false, false, draft ])); if (result) { if (isRelatedToManyCollections) { results[i] = { relationTo: collectionSlug, value: { ...result, collection: collectionSlug } }; } else { results[i] = result; } } }; if (value) { value.forEach((relatedDoc, i)=>{ resultPromises.push(createPopulationPromise(relatedDoc, i)); }); } await Promise.all(resultPromises); return results.filter((doc)=>doc != null); } let id = value; if (isRelatedToManyCollections && value) { id = value.value; relatedCollectionSlug = value.relationTo; } if (id) { const relatedDocument = await context.req.payloadDataLoader.load(JSON.stringify([ context.req.transactionID, relatedCollectionSlug, id, 0, 0, locale, fallbackLocale, false, false, draft ])); if (relatedDocument) { if (isRelatedToManyCollections) { return { relationTo: relatedCollectionSlug, value: { ...relatedDocument, collection: relatedCollectionSlug } }; } return relatedDocument; } return null; } return null; } }; return { ...objectTypeConfig, [field.name]: relationship }; }, richText: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphqltypejson.GraphQLJSON, forceNullable), args: { depth: { type: _graphql.GraphQLInt } }, async resolve (parent, args, context) { let depth = payload.config.defaultDepth; if (typeof args.depth !== 'undefined') depth = args.depth; const editor = field?.editor; // RichText fields have their own depth argument in GraphQL. // This is why the populationPromise (which populates richtext fields like uploads and relationships) // is run here again, with the provided depth. // In the graphql find.ts resolver, the depth is then hard-coded to 0. // Effectively, this means that the populationPromise for GraphQL is only run here, and not in the find.ts resolver / normal population promise. if (editor?.populationPromise) { const populateDepth = field?.maxDepth !== undefined && field?.maxDepth < depth ? field?.maxDepth : depth; await editor?.populationPromise({ context, depth: populateDepth, draft: args.draft, field, findMany: false, flattenLocales: false, overrideAccess: false, populationPromises: [], req: context.req, showHiddenFields: false, siblingDoc: parent }); } return parent[field.name]; } } }), row: (objectTypeConfig, field)=>field.fields.reduce((objectTypeConfigWithRowFields, subField)=>{ const addSubField = fieldToSchemaMap[subField.type]; if (addSubField) return addSubField(objectTypeConfigWithRowFields, subField); return objectTypeConfigWithRowFields; }, objectTypeConfig), select: (objectTypeConfig, field)=>{ const fullName = (0, _combineParentName.default)(parentName, field.name); let type = new _graphql.GraphQLEnumType({ name: fullName, values: (0, _formatOptions.default)(field) }); type = field.hasMany ? new _graphql.GraphQLList(new _graphql.GraphQLNonNull(type)) : type; type = (0, _withNullableType.default)(field, type, forceNullable); return { ...objectTypeConfig, [field.name]: { type } }; }, tabs: (objectTypeConfig, field)=>field.tabs.reduce((tabSchema, tab)=>{ if ((0, _types.tabHasName)(tab)) { const interfaceName = tab?.interfaceName || (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(tab.name, true)); if (!payload.types.groupTypes[interfaceName]) { const objectType = buildObjectType({ name: interfaceName, fields: tab.fields, forceNullable, parentName: interfaceName, payload }); if (Object.keys(objectType.getFields()).length) { payload.types.groupTypes[interfaceName] = objectType; } } if (!payload.types.groupTypes[interfaceName]) { return tabSchema; } return { ...tabSchema, [tab.name]: { type: payload.types.groupTypes[interfaceName] } }; } return { ...tabSchema, ...tab.fields.reduce((subFieldSchema, subField)=>{ const addSubField = fieldToSchemaMap[subField.type]; if (addSubField) return addSubField(subFieldSchema, subField); return subFieldSchema; }, tabSchema) }; }, objectTypeConfig), text: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, field.hasMany === true ? new _graphql.GraphQLList(_graphql.GraphQLString) : _graphql.GraphQLString, forceNullable) } }), textarea: (objectTypeConfig, field)=>({ ...objectTypeConfig, [field.name]: { type: (0, _withNullableType.default)(field, _graphql.GraphQLString, forceNullable) } }), upload: (objectTypeConfig, field)=>{ const { relationTo } = field; const uploadName = (0, _combineParentName.default)(parentName, (0, _formatLabels.toWords)(field.name, true)); // If the relationshipType is undefined at this point, // it can be assumed that this blockType can have a relationship // to itself. Therefore, we set the relationshipType equal to the blockType // that is currently being created. const type = (0, _withNullableType.default)(field, payload.collections[relationTo].graphQL.type || newlyCreatedBlockType, forceNullable); const uploadArgs = {}; if (payload.config.localization) { uploadArgs.locale = { type: payload.types.localeInputType }; uploadArgs.fallbackLocale = { type: payload.types.fallbackLocaleInputType }; } const relatedCollectionSlug = field.relationTo; const upload = { type, args: uploadArgs, extensions: { complexity: 20 }, async resolve (parent, args, context) { const value = parent[field.name]; const locale = args.locale || context.req.locale; const fallbackLocale = args.fallbackLocale || context.req.fallbackLocale; const id = value; const draft = args.draft ?? context.req.query?.draft; if (id) { const relatedDocument = await context.req.payloadDataLoader.load(JSON.stringify([ context.req.transactionID, relatedCollectionSlug, id, 0, 0, locale, fallbackLocale, false, false, Boolean(draft) ])); return relatedDocument || null; } return null; } }; const whereFields = payload.collections[relationTo].config.fields; upload.args.where = { type: (0, _buildWhereInputType.default)({ name: uploadName, fields: whereFields, parentName: uploadName, payload }) }; return { ...objectTypeConfig, [field.name]: upload }; } }; const objectSchema = { name, fields: ()=>fields.reduce((objectTypeConfig, field)=>{ const fieldSchema = fieldToSchemaMap[field.type]; if (typeof fieldSchema !== 'function') { return objectTypeConfig; } return { ...objectTypeConfig, ...fieldSchema(objectTypeConfig, field) }; }, baseFields) }; const newlyCreatedBlockType = new _graphql.GraphQLObjectType(objectSchema); return newlyCreatedBlockType; } const _default = buildObjectType; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9ncmFwaHFsL3NjaGVtYS9idWlsZE9iamVjdFR5cGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVzZS1iZWZvcmUtZGVmaW5lICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1hd2FpdC1pbi1sb29wICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1yZXN0cmljdGVkLXN5bnRheCAqL1xuaW1wb3J0IHR5cGUgeyBHcmFwaFFMRmllbGRDb25maWcsIEdyYXBoUUxUeXBlIH0gZnJvbSAnZ3JhcGhxbCdcblxuaW1wb3J0IHtcbiAgR3JhcGhRTEJvb2xlYW4sXG4gIEdyYXBoUUxFbnVtVHlwZSxcbiAgR3JhcGhRTEZsb2F0LFxuICBHcmFwaFFMSW50LFxuICBHcmFwaFFMTGlzdCxcbiAgR3JhcGhRTE5vbk51bGwsXG4gIEdyYXBoUUxPYmplY3RUeXBlLFxuICBHcmFwaFFMU3RyaW5nLFxuICBHcmFwaFFMVW5pb25UeXBlLFxufSBmcm9tICdncmFwaHFsJ1xuaW1wb3J0IHsgRGF0ZVRpbWVSZXNvbHZlciwgRW1haWxBZGRyZXNzUmVzb2x2ZXIgfSBmcm9tICdncmFwaHFsLXNjYWxhcnMnXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11c2UtYmVmb3JlLWRlZmluZSAqL1xuaW1wb3J0IHsgR3JhcGhRTEpTT04gfSBmcm9tICdncmFwaHFsLXR5cGUtanNvbidcblxuaW1wb3J0IHR5cGUgeyBSaWNoVGV4dEFkYXB0ZXIgfSBmcm9tICcuLi8uLi9hZG1pbi9jb21wb25lbnRzL2Zvcm1zL2ZpZWxkLXR5cGVzL1JpY2hUZXh0L3R5cGVzJ1xuaW1wb3J0IHR5cGUge1xuICBBcnJheUZpZWxkLFxuICBCbG9ja0ZpZWxkLFxuICBDaGVja2JveEZpZWxkLFxuICBDb2RlRmllbGQsXG4gIENvbGxhcHNpYmxlRmllbGQsXG4gIERhdGVGaWVsZCxcbiAgRW1haWxGaWVsZCxcbiAgRmllbGQsXG4gIEdyb3VwRmllbGQsXG4gIEpTT05GaWVsZCxcbiAgTnVtYmVyRmllbGQsXG4gIFBvaW50RmllbGQsXG4gIFJhZGlvRmllbGQsXG4gIFJlbGF0aW9uc2hpcEZpZWxkLFxuICBSaWNoVGV4dEZpZWxkLFxuICBSb3dGaWVsZCxcbiAgU2VsZWN0RmllbGQsXG4gIFRhYnNGaWVsZCxcbiAgVGV4dEZpZWxkLFxuICBUZXh0YXJlYUZpZWxkLFxuICBVcGxvYWRGaWVsZCxcbn0gZnJvbSAnLi4vLi4vZmllbGRzL2NvbmZpZy90eXBlcydcbmltcG9ydCB0eXBlIHsgUGF5bG9hZCB9IGZyb20gJy4uLy4uL216aW5nYSdcblxuaW1wb3J0IHsgdGFiSGFzTmFtZSB9IGZyb20gJy4uLy4uL2ZpZWxkcy9jb25maWcvdHlwZXMnXG5pbXBvcnQgeyB0b1dvcmRzIH0gZnJvbSAnLi4vLi4vdXRpbGl0aWVzL2Zvcm1hdExhYmVscydcbmltcG9ydCBjb21iaW5lUGFyZW50TmFtZSBmcm9tICcuLi91dGlsaXRpZXMvY29tYmluZVBhcmVudE5hbWUnXG5pbXBvcnQgZm9ybWF0TmFtZSBmcm9tICcuLi91dGlsaXRpZXMvZm9ybWF0TmFtZSdcbmltcG9ydCBmb3JtYXRPcHRpb25zIGZyb20gJy4uL3V0aWxpdGllcy9mb3JtYXRPcHRpb25zJ1xuaW1wb3J0IGJ1aWxkV2hlcmVJbnB1dFR5cGUgZnJvbSAnLi9idWlsZFdoZXJlSW5wdXRUeXBlJ1xuaW1wb3J0IGlzRmllbGROdWxsYWJsZSBmcm9tICcuL2lzRmllbGROdWxsYWJsZSdcbmltcG9ydCB3aXRoTnVsbGFibGVUeXBlIGZyb20gJy4vd2l0aE51bGxhYmxlVHlwZSdcblxudHlwZSBMb2NhbGVJbnB1dFR5cGUgPSB7XG4gIGZhbGxiYWNrTG9jYWxlOiB7XG4gICAgdHlwZTogR3JhcGhRTFR5cGVcbiAgfVxuICBsb2NhbGU6IHtcbiAgICB0eXBlOiBHcmFwaFFMVHlwZVxuICB9XG4gIHdoZXJlOiB7XG4gICAgdHlwZTogR3JhcGhRTFR5cGVcbiAgfVxufVxuXG5leHBvcnQgdHlwZSBPYmplY3RUeXBlQ29uZmlnID0ge1xuICBbcGF0aDogc3RyaW5nXTogR3JhcGhRTEZpZWxkQ29uZmlnPGFueSwgYW55PlxufVxuXG50eXBlIEFyZ3MgPSB7XG4gIGJhc2VGaWVsZHM/OiBPYmplY3RUeXBlQ29uZmlnXG4gIGZpZWxkczogRmllbGRbXVxuICBmb3JjZU51bGxhYmxlPzogYm9vbGVhblxuICBuYW1lOiBzdHJpbmdcbiAgcGFyZW50TmFtZTogc3RyaW5nXG4gIHBheWxvYWQ6IFBheWxvYWRcbn1cblxuZnVuY3Rpb24gYnVpbGRPYmplY3RUeXBlKHtcbiAgbmFtZSxcbiAgYmFzZUZpZWxkcyA9IHt9LFxuICBmaWVsZHMsXG4gIGZvcmNlTnVsbGFibGUsXG4gIHBhcmVudE5hbWUsXG4gIHBheWxvYWQsXG59OiBBcmdzKTogR3JhcGhRTE9iamVjdFR5cGUge1xuICBjb25zdCBmaWVsZFRvU2NoZW1hTWFwID0ge1xuICAgIGFycmF5OiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IEFycmF5RmllbGQpID0+IHtcbiAgICAgIGNvbnN0IGludGVyZmFjZU5hbWUgPVxuICAgICAgICBmaWVsZD8uaW50ZXJmYWNlTmFtZSB8fCBjb21iaW5lUGFyZW50TmFtZShwYXJlbnROYW1lLCB0b1dvcmRzKGZpZWxkLm5hbWUsIHRydWUpKVxuXG4gICAgICBpZiAoIXBheWxvYWQudHlwZXMuYXJyYXlUeXBlc1tpbnRlcmZhY2VOYW1lXSkge1xuICAgICAgICBjb25zdCBvYmplY3RUeXBlID0gYnVpbGRPYmplY3RUeXBlKHtcbiAgICAgICAgICBuYW1lOiBpbnRlcmZhY2VOYW1lLFxuICAgICAgICAgIGZpZWxkczogZmllbGQuZmllbGRzLFxuICAgICAgICAgIGZvcmNlTnVsbGFibGU6IGlzRmllbGROdWxsYWJsZShmaWVsZCwgZm9yY2VOdWxsYWJsZSksXG4gICAgICAgICAgcGFyZW50TmFtZTogaW50ZXJmYWNlTmFtZSxcbiAgICAgICAgICBwYXlsb2FkLFxuICAgICAgICB9KVxuXG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhvYmplY3RUeXBlLmdldEZpZWxkcygpKS5sZW5ndGgpIHtcbiAgICAgICAgICBwYXlsb2FkLnR5cGVzLmFycmF5VHlwZXNbaW50ZXJmYWNlTmFtZV0gPSBvYmplY3RUeXBlXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKCFwYXlsb2FkLnR5cGVzLmFycmF5VHlwZXNbaW50ZXJmYWNlTmFtZV0pIHtcbiAgICAgICAgcmV0dXJuIG9iamVjdFR5cGVDb25maWdcbiAgICAgIH1cblxuICAgICAgY29uc3QgYXJyYXlUeXBlID0gbmV3IEdyYXBoUUxMaXN0KG5ldyBHcmFwaFFMTm9uTnVsbChwYXlsb2FkLnR5cGVzLmFycmF5VHlwZXNbaW50ZXJmYWNlTmFtZV0pKVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi5vYmplY3RUeXBlQ29uZmlnLFxuICAgICAgICBbZmllbGQubmFtZV06IHsgdHlwZTogd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgYXJyYXlUeXBlKSB9LFxuICAgICAgfVxuICAgIH0sXG4gICAgYmxvY2tzOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IEJsb2NrRmllbGQpID0+IHtcbiAgICAgIGNvbnN0IGJsb2NrVHlwZXM6IEdyYXBoUUxPYmplY3RUeXBlPGFueSwgYW55PltdID0gZmllbGQuYmxvY2tzLnJlZHVjZSgoYWNjLCBibG9jaykgPT4ge1xuICAgICAgICBpZiAoIXBheWxvYWQudHlwZXMuYmxvY2tUeXBlc1tibG9jay5zbHVnXSkge1xuICAgICAgICAgIGNvbnN0IGludGVyZmFjZU5hbWUgPVxuICAgICAgICAgICAgYmxvY2s/LmludGVyZmFjZU5hbWUgfHwgYmxvY2s/LmdyYXBoUUw/LnNpbmd1bGFyTmFtZSB8fCB0b1dvcmRzKGJsb2NrLnNsdWcsIHRydWUpXG5cbiAgICAgICAgICBjb25zdCBvYmplY3RUeXBlID0gYnVpbGRPYmplY3RUeXBlKHtcbiAgICAgICAgICAgIG5hbWU6IGludGVyZmFjZU5hbWUsXG4gICAgICAgICAgICBmaWVsZHM6IFtcbiAgICAgICAgICAgICAgLi4uYmxvY2suZmllbGRzLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogJ2Jsb2NrVHlwZScsXG4gICAgICAgICAgICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIGZvcmNlTnVsbGFibGUsXG4gICAgICAgICAgICBwYXJlbnROYW1lOiBpbnRlcmZhY2VOYW1lLFxuICAgICAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgICB9KVxuXG4gICAgICAgICAgaWYgKE9iamVjdC5rZXlzKG9iamVjdFR5cGUuZ2V0RmllbGRzKCkpLmxlbmd0aCkge1xuICAgICAgICAgICAgcGF5bG9hZC50eXBlcy5ibG9ja1R5cGVzW2Jsb2NrLnNsdWddID0gb2JqZWN0VHlwZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXlsb2FkLnR5cGVzLmJsb2NrVHlwZXNbYmxvY2suc2x1Z10pIHtcbiAgICAgICAgICBhY2MucHVzaChwYXlsb2FkLnR5cGVzLmJsb2NrVHlwZXNbYmxvY2suc2x1Z10pXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYWNjXG4gICAgICB9LCBbXSlcblxuICAgICAgaWYgKGJsb2NrVHlwZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBvYmplY3RUeXBlQ29uZmlnXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZ1bGxOYW1lID0gY29tYmluZVBhcmVudE5hbWUocGFyZW50TmFtZSwgdG9Xb3JkcyhmaWVsZC5uYW1lLCB0cnVlKSlcblxuICAgICAgY29uc3QgdHlwZSA9IG5ldyBHcmFwaFFMTGlzdChcbiAgICAgICAgbmV3IEdyYXBoUUxOb25OdWxsKFxuICAgICAgICAgIG5ldyBHcmFwaFFMVW5pb25UeXBlKHtcbiAgICAgICAgICAgIG5hbWU6IGZ1bGxOYW1lLFxuICAgICAgICAgICAgcmVzb2x2ZVR5cGU6IChkYXRhKSA9PiBwYXlsb2FkLnR5cGVzLmJsb2NrVHlwZXNbZGF0YS5ibG9ja1R5cGVdLm5hbWUsXG4gICAgICAgICAgICB0eXBlczogYmxvY2tUeXBlcyxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgIClcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4ub2JqZWN0VHlwZUNvbmZpZyxcbiAgICAgICAgW2ZpZWxkLm5hbWVdOiB7IHR5cGU6IHdpdGhOdWxsYWJsZVR5cGUoZmllbGQsIHR5cGUpIH0sXG4gICAgICB9XG4gICAgfSxcbiAgICBjaGVja2JveDogKG9iamVjdFR5cGVDb25maWc6IE9iamVjdFR5cGVDb25maWcsIGZpZWxkOiBDaGVja2JveEZpZWxkKSA9PiAoe1xuICAgICAgLi4ub2JqZWN0VHlwZUNvbmZpZyxcbiAgICAgIFtmaWVsZC5uYW1lXTogeyB0eXBlOiB3aXRoTnVsbGFibGVUeXBlKGZpZWxkLCBHcmFwaFFMQm9vbGVhbiwgZm9yY2VOdWxsYWJsZSkgfSxcbiAgICB9KSxcbiAgICBjb2RlOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IENvZGVGaWVsZCkgPT4gKHtcbiAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICBbZmllbGQubmFtZV06IHsgdHlwZTogd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgR3JhcGhRTFN0cmluZywgZm9yY2VOdWxsYWJsZSkgfSxcbiAgICB9KSxcbiAgICBjb2xsYXBzaWJsZTogKG9iamVjdFR5cGVDb25maWc6IE9iamVjdFR5cGVDb25maWcsIGZpZWxkOiBDb2xsYXBzaWJsZUZpZWxkKSA9PlxuICAgICAgZmllbGQuZmllbGRzLnJlZHVjZSgob2JqZWN0VHlwZUNvbmZpZ1dpdGhDb2xsYXBzaWJsZUZpZWxkcywgc3ViRmllbGQpID0+IHtcbiAgICAgICAgY29uc3QgYWRkU3ViRmllbGQgPSBmaWVsZFRvU2NoZW1hTWFwW3N1YkZpZWxkLnR5cGVdXG4gICAgICAgIGlmIChhZGRTdWJGaWVsZCkgcmV0dXJuIGFkZFN1YkZpZWxkKG9iamVjdFR5cGVDb25maWdXaXRoQ29sbGFwc2libGVGaWVsZHMsIHN1YkZpZWxkKVxuICAgICAgICByZXR1cm4gb2JqZWN0VHlwZUNvbmZpZ1dpdGhDb2xsYXBzaWJsZUZpZWxkc1xuICAgICAgfSwgb2JqZWN0VHlwZUNvbmZpZyksXG4gICAgZGF0ZTogKG9iamVjdFR5cGVDb25maWc6IE9iamVjdFR5cGVDb25maWcsIGZpZWxkOiBEYXRlRmllbGQpID0+ICh7XG4gICAgICAuLi5vYmplY3RUeXBlQ29uZmlnLFxuICAgICAgW2ZpZWxkLm5hbWVdOiB7IHR5cGU6IHdpdGhOdWxsYWJsZVR5cGUoZmllbGQsIERhdGVUaW1lUmVzb2x2ZXIsIGZvcmNlTnVsbGFibGUpIH0sXG4gICAgfSksXG4gICAgZW1haWw6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogRW1haWxGaWVsZCkgPT4gKHtcbiAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICBbZmllbGQubmFtZV06IHsgdHlwZTogd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgRW1haWxBZGRyZXNzUmVzb2x2ZXIsIGZvcmNlTnVsbGFibGUpIH0sXG4gICAgfSksXG4gICAgZ3JvdXA6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogR3JvdXBGaWVsZCkgPT4ge1xuICAgICAgY29uc3QgaW50ZXJmYWNlTmFtZSA9XG4gICAgICAgIGZpZWxkPy5pbnRlcmZhY2VOYW1lIHx8IGNvbWJpbmVQYXJlbnROYW1lKHBhcmVudE5hbWUsIHRvV29yZHMoZmllbGQubmFtZSwgdHJ1ZSkpXG5cbiAgICAgIGlmICghcGF5bG9hZC50eXBlcy5ncm91cFR5cGVzW2ludGVyZmFjZU5hbWVdKSB7XG4gICAgICAgIGNvbnN0IG9iamVjdFR5cGUgPSBidWlsZE9iamVjdFR5cGUoe1xuICAgICAgICAgIG5hbWU6IGludGVyZmFjZU5hbWUsXG4gICAgICAgICAgZmllbGRzOiBmaWVsZC5maWVsZHMsXG4gICAgICAgICAgZm9yY2VOdWxsYWJsZTogaXNGaWVsZE51bGxhYmxlKGZpZWxkLCBmb3JjZU51bGxhYmxlKSxcbiAgICAgICAgICBwYXJlbnROYW1lOiBpbnRlcmZhY2VOYW1lLFxuICAgICAgICAgIHBheWxvYWQsXG4gICAgICAgIH0pXG5cbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKG9iamVjdFR5cGUuZ2V0RmllbGRzKCkpLmxlbmd0aCkge1xuICAgICAgICAgIHBheWxvYWQudHlwZXMuZ3JvdXBUeXBlc1tpbnRlcmZhY2VOYW1lXSA9IG9iamVjdFR5cGVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIXBheWxvYWQudHlwZXMuZ3JvdXBUeXBlc1tpbnRlcmZhY2VOYW1lXSkge1xuICAgICAgICByZXR1cm4gb2JqZWN0VHlwZUNvbmZpZ1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi5vYmplY3RUeXBlQ29uZmlnLFxuICAgICAgICBbZmllbGQubmFtZV06IHsgdHlwZTogcGF5bG9hZC50eXBlcy5ncm91cFR5cGVzW2ludGVyZmFjZU5hbWVdIH0sXG4gICAgICB9XG4gICAgfSxcbiAgICBqc29uOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IEpTT05GaWVsZCkgPT4gKHtcbiAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICBbZmllbGQubmFtZV06IHsgdHlwZTogd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgR3JhcGhRTEpTT04sIGZvcmNlTnVsbGFibGUpIH0sXG4gICAgfSksXG4gICAgbnVtYmVyOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IE51bWJlckZpZWxkKSA9PiB7XG4gICAgICBjb25zdCB0eXBlID0gZmllbGQ/Lm5hbWUgPT09ICdpZCcgPyBHcmFwaFFMSW50IDogR3JhcGhRTEZsb2F0XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi5vYmplY3RUeXBlQ29uZmlnLFxuICAgICAgICBbZmllbGQubmFtZV06IHtcbiAgICAgICAgICB0eXBlOiB3aXRoTnVsbGFibGVUeXBlKFxuICAgICAgICAgICAgZmllbGQsXG4gICAgICAgICAgICBmaWVsZD8uaGFzTWFueSA9PT0gdHJ1ZSA/IG5ldyBHcmFwaFFMTGlzdCh0eXBlKSA6IHR5cGUsXG4gICAgICAgICAgICBmb3JjZU51bGxhYmxlLFxuICAgICAgICAgICksXG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgfSxcbiAgICBwb2ludDogKG9iamVjdFR5cGVDb25maWc6IE9iamVjdFR5cGVDb25maWcsIGZpZWxkOiBQb2ludEZpZWxkKSA9PiAoe1xuICAgICAgLi4ub2JqZWN0VHlwZUNvbmZpZyxcbiAgICAgIFtmaWVsZC5uYW1lXToge1xuICAgICAgICB0eXBlOiB3aXRoTnVsbGFibGVUeXBlKFxuICAgICAgICAgIGZpZWxkLFxuICAgICAgICAgIG5ldyBHcmFwaFFMTGlzdChuZXcgR3JhcGhRTE5vbk51bGwoR3JhcGhRTEZsb2F0KSksXG4gICAgICAgICAgZm9yY2VOdWxsYWJsZSxcbiAgICAgICAgKSxcbiAgICAgIH0sXG4gICAgfSksXG4gICAgcmFkaW86IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogUmFkaW9GaWVsZCkgPT4gKHtcbiAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICBbZmllbGQubmFtZV06IHtcbiAgICAgICAgdHlwZTogd2l0aE51bGxhYmxlVHlwZShcbiAgICAgICAgICBmaWVsZCxcbiAgICAgICAgICBuZXcgR3JhcGhRTEVudW1UeXBlKHtcbiAgICAgICAgICAgIG5hbWU6IGNvbWJpbmVQYXJlbnROYW1lKHBhcmVudE5hbWUsIGZpZWxkLm5hbWUpLFxuICAgICAgICAgICAgdmFsdWVzOiBmb3JtYXRPcHRpb25zKGZpZWxkKSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBmb3JjZU51bGxhYmxlLFxuICAgICAgICApLFxuICAgICAgfSxcbiAgICB9KSxcbiAgICByZWxhdGlvbnNoaXA6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogUmVsYXRpb25zaGlwRmllbGQpID0+IHtcbiAgICAgIGNvbnN0IHsgcmVsYXRpb25UbyB9ID0gZmllbGRcbiAgICAgIGNvbnN0IGlzUmVsYXRlZFRvTWFueUNvbGxlY3Rpb25zID0gQXJyYXkuaXNBcnJheShyZWxhdGlvblRvKVxuICAgICAgY29uc3QgaGFzTWFueVZhbHVlcyA9IGZpZWxkLmhhc01hbnlcbiAgICAgIGNvbnN0IHJlbGF0aW9uc2hpcE5hbWUgPSBjb21iaW5lUGFyZW50TmFtZShwYXJlbnROYW1lLCB0b1dvcmRzKGZpZWxkLm5hbWUsIHRydWUpKVxuXG4gICAgICBsZXQgdHlwZVxuICAgICAgbGV0IHJlbGF0aW9uVG9UeXBlID0gbnVsbFxuXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShyZWxhdGlvblRvKSkge1xuICAgICAgICByZWxhdGlvblRvVHlwZSA9IG5ldyBHcmFwaFFMRW51bVR5cGUoe1xuICAgICAgICAgIG5hbWU6IGAke3JlbGF0aW9uc2hpcE5hbWV9X1JlbGF0aW9uVG9gLFxuICAgICAgICAgIHZhbHVlczogcmVsYXRpb25Uby5yZWR1Y2UoXG4gICAgICAgICAgICAocmVsYXRpb25zLCByZWxhdGlvbikgPT4gKHtcbiAgICAgICAgICAgICAgLi4ucmVsYXRpb25zLFxuICAgICAgICAgICAgICBbZm9ybWF0TmFtZShyZWxhdGlvbildOiB7XG4gICAgICAgICAgICAgICAgdmFsdWU6IHJlbGF0aW9uLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB7fSxcbiAgICAgICAgICApLFxuICAgICAgICB9KVxuXG4gICAgICAgIGNvbnN0IHR5cGVzID0gcmVsYXRpb25Uby5tYXAoKHJlbGF0aW9uKSA9PiBwYXlsb2FkLmNvbGxlY3Rpb25zW3JlbGF0aW9uXS5ncmFwaFFMLnR5cGUpXG5cbiAgICAgICAgdHlwZSA9IG5ldyBHcmFwaFFMT2JqZWN0VHlwZSh7XG4gICAgICAgICAgbmFtZTogYCR7cmVsYXRpb25zaGlwTmFtZX1fUmVsYXRpb25zaGlwYCxcbiAgICAgICAgICBmaWVsZHM6IHtcbiAgICAgICAgICAgIHJlbGF0aW9uVG86IHtcbiAgICAgICAgICAgICAgdHlwZTogcmVsYXRpb25Ub1R5cGUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICAgICAgdHlwZTogbmV3IEdyYXBoUUxVbmlvblR5cGUoe1xuICAgICAgICAgICAgICAgIG5hbWU6IHJlbGF0aW9uc2hpcE5hbWUsXG4gICAgICAgICAgICAgICAgYXN5bmMgcmVzb2x2ZVR5cGUoZGF0YSwgeyByZXEgfSkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHBheWxvYWQuY29sbGVjdGlvbnNbZGF0YS5jb2xsZWN0aW9uXS5ncmFwaFFMLnR5cGUubmFtZVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdHlwZXMsXG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgOyh7IHR5cGUgfSA9IHBheWxvYWQuY29sbGVjdGlvbnNbcmVsYXRpb25Ub10uZ3JhcGhRTClcbiAgICAgIH1cblxuICAgICAgLy8gSWYgdGhlIHJlbGF0aW9uc2hpcFR5cGUgaXMgdW5kZWZpbmVkIGF0IHRoaXMgcG9pbnQsXG4gICAgICAvLyBpdCBjYW4gYmUgYXNzdW1lZCB0aGF0IHRoaXMgYmxvY2tUeXBlIGNhbiBoYXZlIGEgcmVsYXRpb25zaGlwXG4gICAgICAvLyB0byBpdHNlbGYuIFRoZXJlZm9yZSwgd2Ugc2V0IHRoZSByZWxhdGlvbnNoaXBUeXBlIGVxdWFsIHRvIHRoZSBibG9ja1R5cGVcbiAgICAgIC8vIHRoYXQgaXMgY3VycmVudGx5IGJlaW5nIGNyZWF0ZWQuXG5cbiAgICAgIHR5cGUgPSB0eXBlIHx8IG5ld2x5Q3JlYXRlZEJsb2NrVHlwZVxuXG4gICAgICBjb25zdCByZWxhdGlvbnNoaXBBcmdzOiB7XG4gICAgICAgIGRyYWZ0PzogdW5rbm93blxuICAgICAgICBmYWxsYmFja0xvY2FsZT86IHVua25vd25cbiAgICAgICAgbGltaXQ/OiB1bmtub3duXG4gICAgICAgIGxvY2FsZT86IHVua25vd25cbiAgICAgICAgcGFnZT86IHVua25vd25cbiAgICAgICAgd2hlcmU/OiB1bmtub3duXG4gICAgICB9ID0ge31cblxuICAgICAgY29uc3QgcmVsYXRpb25zVXNlRHJhZnRzID0gKEFycmF5LmlzQXJyYXkocmVsYXRpb25UbykgPyByZWxhdGlvblRvIDogW3JlbGF0aW9uVG9dKS5zb21lKFxuICAgICAgICAocmVsYXRpb24pID0+IHBheWxvYWQuY29sbGVjdGlvbnNbcmVsYXRpb25dLmNvbmZpZy52ZXJzaW9ucz8uZHJhZnRzLFxuICAgICAgKVxuXG4gICAgICBpZiAocmVsYXRpb25zVXNlRHJhZnRzKSB7XG4gICAgICAgIHJlbGF0aW9uc2hpcEFyZ3MuZHJhZnQgPSB7XG4gICAgICAgICAgdHlwZTogR3JhcGhRTEJvb2xlYW4sXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHBheWxvYWQuY29uZmlnLmxvY2FsaXphdGlvbikge1xuICAgICAgICByZWxhdGlvbnNoaXBBcmdzLmxvY2FsZSA9IHtcbiAgICAgICAgICB0eXBlOiBwYXlsb2FkLnR5cGVzLmxvY2FsZUlucHV0VHlwZSxcbiAgICAgICAgfVxuXG4gICAgICAgIHJlbGF0aW9uc2hpcEFyZ3MuZmFsbGJhY2tMb2NhbGUgPSB7XG4gICAgICAgICAgdHlwZTogcGF5bG9hZC50eXBlcy5mYWxsYmFja0xvY2FsZUlucHV0VHlwZSxcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCByZWxhdGlvbnNoaXAgPSB7XG4gICAgICAgIHR5cGU6IHdpdGhOdWxsYWJsZVR5cGUoXG4gICAgICAgICAgZmllbGQsXG4gICAgICAgICAgaGFzTWFueVZhbHVlcyA/IG5ldyBHcmFwaFFMTGlzdChuZXcgR3JhcGhRTE5vbk51bGwodHlwZSkpIDogdHlwZSxcbiAgICAgICAgICBmb3JjZU51bGxhYmxlLFxuICAgICAgICApLFxuICAgICAgICBhcmdzOiByZWxhdGlvbnNoaXBBcmdzLFxuICAgICAgICBleHRlbnNpb25zOiB7IGNvbXBsZXhpdHk6IDEwIH0sXG4gICAgICAgIGFzeW5jIHJlc29sdmUocGFyZW50LCBhcmdzLCBjb250ZXh0KSB7XG4gICAgICAgICAgY29uc3QgdmFsdWUgPSBwYXJlbnRbZmllbGQubmFtZV1cbiAgICAgICAgICBjb25zdCBsb2NhbGUgPSBhcmdzLmxvY2FsZSB8fCBjb250ZXh0LnJlcS5sb2NhbGVcbiAgICAgICAgICBjb25zdCBmYWxsYmFja0xvY2FsZSA9IGFyZ3MuZmFsbGJhY2tMb2NhbGUgfHwgY29udGV4dC5yZXEuZmFsbGJhY2tMb2NhbGVcbiAgICAgICAgICBsZXQgcmVsYXRlZENvbGxlY3Rpb25TbHVnID0gZmllbGQucmVsYXRpb25Ub1xuICAgICAgICAgIGNvbnN0IGRyYWZ0ID0gYXJncy5kcmFmdCA/PyBjb250ZXh0LnJlcS5xdWVyeT8uZHJhZnRcblxuICAgICAgICAgIGlmIChoYXNNYW55VmFsdWVzKSB7XG4gICAgICAgICAgICBjb25zdCByZXN1bHRzID0gW11cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdFByb21pc2VzID0gW11cblxuICAgICAgICAgICAgY29uc3QgY3JlYXRlUG9wdWxhdGlvblByb21pc2UgPSBhc3luYyAocmVsYXRlZERvYywgaSkgPT4ge1xuICAgICAgICAgICAgICBsZXQgaWQgPSByZWxhdGVkRG9jXG4gICAgICAgICAgICAgIGxldCBjb2xsZWN0aW9uU2x1ZyA9IGZpZWxkLnJlbGF0aW9uVG9cblxuICAgICAgICAgICAgICBpZiAoaXNSZWxhdGVkVG9NYW55Q29sbGVjdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBjb2xsZWN0aW9uU2x1ZyA9IHJlbGF0ZWREb2MucmVsYXRpb25Ub1xuICAgICAgICAgICAgICAgIGlkID0gcmVsYXRlZERvYy52YWx1ZVxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY29udGV4dC5yZXEucGF5bG9hZERhdGFMb2FkZXIubG9hZChcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShbXG4gICAgICAgICAgICAgICAgICBjb250ZXh0LnJlcS50cmFuc2FjdGlvbklELFxuICAgICAgICAgICAgICAgICAgY29sbGVjdGlvblNsdWcsXG4gICAgICAgICAgICAgICAgICBpZCxcbiAgICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgICAgbG9jYWxlLFxuICAgICAgICAgICAgICAgICAgZmFsbGJhY2tMb2NhbGUsXG4gICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgZHJhZnQsXG4gICAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICAgIClcblxuICAgICAgICAgICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzUmVsYXRlZFRvTWFueUNvbGxlY3Rpb25zKSB7XG4gICAgICAgICAgICAgICAgICByZXN1bHRzW2ldID0ge1xuICAgICAgICAgICAgICAgICAgICByZWxhdGlvblRvOiBjb2xsZWN0aW9uU2x1ZyxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAuLi5yZXN1bHQsXG4gICAgICAgICAgICAgICAgICAgICAgY29sbGVjdGlvbjogY29sbGVjdGlvblNsdWcsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIHJlc3VsdHNbaV0gPSByZXN1bHRcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgICAgICAgIHZhbHVlLmZvckVhY2goKHJlbGF0ZWREb2MsIGkpID0+IHtcbiAgICAgICAgICAgICAgICByZXN1bHRQcm9taXNlcy5wdXNoKGNyZWF0ZVBvcHVsYXRpb25Qcm9taXNlKHJlbGF0ZWREb2MsIGkpKVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChyZXN1bHRQcm9taXNlcylcbiAgICAgICAgICAgIHJldHVybiByZXN1bHRzLmZpbHRlcigoZG9jKSA9PiBkb2MgIT0gbnVsbClcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsZXQgaWQgPSB2YWx1ZVxuICAgICAgICAgIGlmIChpc1JlbGF0ZWRUb01hbnlDb2xsZWN0aW9ucyAmJiB2YWx1ZSkge1xuICAgICAgICAgICAgaWQgPSB2YWx1ZS52YWx1ZVxuICAgICAgICAgICAgcmVsYXRlZENvbGxlY3Rpb25TbHVnID0gdmFsdWUucmVsYXRpb25Ub1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgY29uc3QgcmVsYXRlZERvY3VtZW50ID0gYXdhaXQgY29udGV4dC5yZXEucGF5bG9hZERhdGFMb2FkZXIubG9hZChcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoW1xuICAgICAgICAgICAgICAgIGNvbnRleHQucmVxLnRyYW5zYWN0aW9uSUQsXG4gICAgICAgICAgICAgICAgcmVsYXRlZENvbGxlY3Rpb25TbHVnLFxuICAgICAgICAgICAgICAgIGlkLFxuICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICBsb2NhbGUsXG4gICAgICAgICAgICAgICAgZmFsbGJhY2tMb2NhbGUsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgZHJhZnQsXG4gICAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgKVxuXG4gICAgICAgICAgICBpZiAocmVsYXRlZERvY3VtZW50KSB7XG4gICAgICAgICAgICAgIGlmIChpc1JlbGF0ZWRUb01hbnlDb2xsZWN0aW9ucykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICByZWxhdGlvblRvOiByZWxhdGVkQ29sbGVjdGlvblNsdWcsXG4gICAgICAgICAgICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgICAgICAgICAuLi5yZWxhdGVkRG9jdW1lbnQsXG4gICAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb246IHJlbGF0ZWRDb2xsZWN0aW9uU2x1ZyxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHJlbGF0ZWREb2N1bWVudFxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbnVsbFxuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIH0sXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICAgIFtmaWVsZC5uYW1lXTogcmVsYXRpb25zaGlwLFxuICAgICAgfVxuICAgIH0sXG4gICAgcmljaFRleHQ6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogUmljaFRleHRGaWVsZCkgPT4gKHtcbiAgICAgIC4uLm9iamVjdFR5cGVDb25maWcsXG4gICAgICBbZmllbGQubmFtZV06IHtcbiAgICAgICAgdHlwZTogd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgR3JhcGhRTEpTT04sIGZvcmNlTnVsbGFibGUpLFxuICAgICAgICBhcmdzOiB7XG4gICAgICAgICAgZGVwdGg6IHtcbiAgICAgICAgICAgIHR5cGU6IEdyYXBoUUxJbnQsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgcmVzb2x2ZShwYXJlbnQsIGFyZ3MsIGNvbnRleHQpIHtcbiAgICAgICAgICBsZXQgZGVwdGggPSBwYXlsb2FkLmNvbmZpZy5kZWZhdWx0RGVwdGhcbiAgICAgICAgICBpZiAodHlwZW9mIGFyZ3MuZGVwdGggIT09ICd1bmRlZmluZWQnKSBkZXB0aCA9IGFyZ3MuZGVwdGhcbiAgICAgICAgICBjb25zdCBlZGl0b3I6IFJpY2hUZXh0QWRhcHRlciA9IGZpZWxkPy5lZGl0b3JcblxuICAgICAgICAgIC8vIFJpY2hUZXh0IGZpZWxkcyBoYXZlIHRoZWlyIG93biBkZXB0aCBhcmd1bWVudCBpbiBHcmFwaFFMLlxuICAgICAgICAgIC8vIFRoaXMgaXMgd2h5IHRoZSBwb3B1bGF0aW9uUHJvbWlzZSAod2hpY2ggcG9wdWxhdGVzIHJpY2h0ZXh0IGZpZWxkcyBsaWtlIHVwbG9hZHMgYW5kIHJlbGF0aW9uc2hpcHMpXG4gICAgICAgICAgLy8gaXMgcnVuIGhlcmUgYWdhaW4sIHdpdGggdGhlIHByb3ZpZGVkIGRlcHRoLlxuICAgICAgICAgIC8vIEluIHRoZSBncmFwaHFsIGZpbmQudHMgcmVzb2x2ZXIsIHRoZSBkZXB0aCBpcyB0aGVuIGhhcmQtY29kZWQgdG8gMC5cbiAgICAgICAgICAvLyBFZmZlY3RpdmVseSwgdGhpcyBtZWFucyB0aGF0IHRoZSBwb3B1bGF0aW9uUHJvbWlzZSBmb3IgR3JhcGhRTCBpcyBvbmx5IHJ1biBoZXJlLCBhbmQgbm90IGluIHRoZSBmaW5kLnRzIHJlc29sdmVyIC8gbm9ybWFsIHBvcHVsYXRpb24gcHJvbWlzZS5cbiAgICAgICAgICBpZiAoZWRpdG9yPy5wb3B1bGF0aW9uUHJvbWlzZSkge1xuICAgICAgICAgICAgY29uc3QgcG9wdWxhdGVEZXB0aCA9XG4gICAgICAgICAgICAgIGZpZWxkPy5tYXhEZXB0aCAhPT0gdW5kZWZpbmVkICYmIGZpZWxkPy5tYXhEZXB0aCA8IGRlcHRoID8gZmllbGQ/Lm1heERlcHRoIDogZGVwdGhcblxuICAgICAgICAgICAgYXdhaXQgZWRpdG9yPy5wb3B1bGF0aW9uUHJvbWlzZSh7XG4gICAgICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgICAgIGRlcHRoOiBwb3B1bGF0ZURlcHRoLFxuICAgICAgICAgICAgICBkcmFmdDogYXJncy5kcmFmdCxcbiAgICAgICAgICAgICAgZmllbGQsXG4gICAgICAgICAgICAgIGZpbmRNYW55OiBmYWxzZSxcbiAgICAgICAgICAgICAgZmxhdHRlbkxvY2FsZXM6IGZhbHNlLFxuICAgICAgICAgICAgICBvdmVycmlkZUFjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgIHBvcHVsYXRpb25Qcm9taXNlczogW10sXG4gICAgICAgICAgICAgIHJlcTogY29udGV4dC5yZXEsXG4gICAgICAgICAgICAgIHNob3dIaWRkZW5GaWVsZHM6IGZhbHNlLFxuICAgICAgICAgICAgICBzaWJsaW5nRG9jOiBwYXJlbnQsXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBwYXJlbnRbZmllbGQubmFtZV1cbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSksXG4gICAgcm93OiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IFJvd0ZpZWxkKSA9PlxuICAgICAgZmllbGQuZmllbGRzLnJlZHVjZSgob2JqZWN0VHlwZUNvbmZpZ1dpdGhSb3dGaWVsZHMsIHN1YkZpZWxkKSA9PiB7XG4gICAgICAgIGNvbnN0IGFkZFN1YkZpZWxkID0gZmllbGRUb1NjaGVtYU1hcFtzdWJGaWVsZC50eXBlXVxuICAgICAgICBpZiAoYWRkU3ViRmllbGQpIHJldHVybiBhZGRTdWJGaWVsZChvYmplY3RUeXBlQ29uZmlnV2l0aFJvd0ZpZWxkcywgc3ViRmllbGQpXG4gICAgICAgIHJldHVybiBvYmplY3RUeXBlQ29uZmlnV2l0aFJvd0ZpZWxkc1xuICAgICAgfSwgb2JqZWN0VHlwZUNvbmZpZyksXG4gICAgc2VsZWN0OiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IFNlbGVjdEZpZWxkKSA9PiB7XG4gICAgICBjb25zdCBmdWxsTmFtZSA9IGNvbWJpbmVQYXJlbnROYW1lKHBhcmVudE5hbWUsIGZpZWxkLm5hbWUpXG5cbiAgICAgIGxldCB0eXBlOiBHcmFwaFFMVHlwZSA9IG5ldyBHcmFwaFFMRW51bVR5cGUoe1xuICAgICAgICBuYW1lOiBmdWxsTmFtZSxcbiAgICAgICAgdmFsdWVzOiBmb3JtYXRPcHRpb25zKGZpZWxkKSxcbiAgICAgIH0pXG5cbiAgICAgIHR5cGUgPSBmaWVsZC5oYXNNYW55ID8gbmV3IEdyYXBoUUxMaXN0KG5ldyBHcmFwaFFMTm9uTnVsbCh0eXBlKSkgOiB0eXBlXG4gICAgICB0eXBlID0gd2l0aE51bGxhYmxlVHlwZShmaWVsZCwgdHlwZSwgZm9yY2VOdWxsYWJsZSlcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4ub2JqZWN0VHlwZUNvbmZpZyxcbiAgICAgICAgW2ZpZWxkLm5hbWVdOiB7IHR5cGUgfSxcbiAgICAgIH1cbiAgICB9LFxuICAgIHRhYnM6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogVGFic0ZpZWxkKSA9PlxuICAgICAgZmllbGQudGFicy5yZWR1Y2UoKHRhYlNjaGVtYSwgdGFiKSA9PiB7XG4gICAgICAgIGlmICh0YWJIYXNOYW1lKHRhYikpIHtcbiAgICAgICAgICBjb25zdCBpbnRlcmZhY2VOYW1lID1cbiAgICAgICAgICAgIHRhYj8uaW50ZXJmYWNlTmFtZSB8fCBjb21iaW5lUGFyZW50TmFtZShwYXJlbnROYW1lLCB0b1dvcmRzKHRhYi5uYW1lLCB0cnVlKSlcblxuICAgICAgICAgIGlmICghcGF5bG9hZC50eXBlcy5ncm91cFR5cGVzW2ludGVyZmFjZU5hbWVdKSB7XG4gICAgICAgICAgICBjb25zdCBvYmplY3RUeXBlID0gYnVpbGRPYmplY3RUeXBlKHtcbiAgICAgICAgICAgICAgbmFtZTogaW50ZXJmYWNlTmFtZSxcbiAgICAgICAgICAgICAgZmllbGRzOiB0YWIuZmllbGRzLFxuICAgICAgICAgICAgICBmb3JjZU51bGxhYmxlLFxuICAgICAgICAgICAgICBwYXJlbnROYW1lOiBpbnRlcmZhY2VOYW1lLFxuICAgICAgICAgICAgICBwYXlsb2FkLFxuICAgICAgICAgICAgfSlcblxuICAgICAgICAgICAgaWYgKE9iamVjdC5rZXlzKG9iamVjdFR5cGUuZ2V0RmllbGRzKCkpLmxlbmd0aCkge1xuICAgICAgICAgICAgICBwYXlsb2FkLnR5cGVzLmdyb3VwVHlwZXNbaW50ZXJmYWNlTmFtZV0gPSBvYmplY3RUeXBlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFwYXlsb2FkLnR5cGVzLmdyb3VwVHlwZXNbaW50ZXJmYWNlTmFtZV0pIHtcbiAgICAgICAgICAgIHJldHVybiB0YWJTY2hlbWFcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4udGFiU2NoZW1hLFxuICAgICAgICAgICAgW3RhYi5uYW1lXTogeyB0eXBlOiBwYXlsb2FkLnR5cGVzLmdyb3VwVHlwZXNbaW50ZXJmYWNlTmFtZV0gfSxcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIC4uLnRhYlNjaGVtYSxcbiAgICAgICAgICAuLi50YWIuZmllbGRzLnJlZHVjZSgoc3ViRmllbGRTY2hlbWEsIHN1YkZpZWxkKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBhZGRTdWJGaWVsZCA9IGZpZWxkVG9TY2hlbWFNYXBbc3ViRmllbGQudHlwZV1cbiAgICAgICAgICAgIGlmIChhZGRTdWJGaWVsZCkgcmV0dXJuIGFkZFN1YkZpZWxkKHN1YkZpZWxkU2NoZW1hLCBzdWJGaWVsZClcbiAgICAgICAgICAgIHJldHVybiBzdWJGaWVsZFNjaGVtYVxuICAgICAgICAgIH0sIHRhYlNjaGVtYSksXG4gICAgICAgIH1cbiAgICAgIH0sIG9iamVjdFR5cGVDb25maWcpLFxuICAgIHRleHQ6IChvYmplY3RUeXBlQ29uZmlnOiBPYmplY3RUeXBlQ29uZmlnLCBmaWVsZDogVGV4dEZpZWxkKSA9PiAoe1xuICAgICAgLi4ub2JqZWN0VHlwZUNvbmZpZyxcbiAgICAgIFtmaWVsZC5uYW1lXToge1xuICAgICAgICB0eXBlOiB3aXRoTnVsbGFibGVUeXBlKFxuICAgICAgICAgIGZpZWxkLFxuICAgICAgICAgIGZpZWxkLmhhc01hbnkgPT09IHRydWUgPyBuZXcgR3JhcGhRTExpc3QoR3JhcGhRTFN0cmluZykgOiBHcmFwaFFMU3RyaW5nLFxuICAgICAgICAgIGZvcmNlTnVsbGFibGUsXG4gICAgICAgICksXG4gICAgICB9LFxuICAgIH0pLFxuICAgIHRleHRhcmVhOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IFRleHRhcmVhRmllbGQpID0+ICh7XG4gICAgICAuLi5vYmplY3RUeXBlQ29uZmlnLFxuICAgICAgW2ZpZWxkLm5hbWVdOiB7IHR5cGU6IHdpdGhOdWxsYWJsZVR5cGUoZmllbGQsIEdyYXBoUUxTdHJpbmcsIGZvcmNlTnVsbGFibGUpIH0sXG4gICAgfSksXG4gICAgdXBsb2FkOiAob2JqZWN0VHlwZUNvbmZpZzogT2JqZWN0VHlwZUNvbmZpZywgZmllbGQ6IFVwbG9hZEZpZWxkKSA9PiB7XG4gICAgICBjb25zdCB7IHJlbGF0aW9uVG8gfSA9IGZpZWxkXG5cbiAgICAgIGNvbnN0IHVwbG9hZE5hbWUgPSBjb21iaW5lUGFyZW50TmFtZShwYXJlbnROYW1lLCB0b1dvcmRzKGZpZWxkLm5hbWUsIHRydWUpKVxuXG4gICAgICAvLyBJZiB0aGUgcmVsYXRpb25zaGlwVHlwZSBpcyB1bmRlZmluZWQgYXQgdGhpcyBwb2ludCxcbiAgICAgIC8vIGl0IGNhbiBiZSBhc3N1bWVkIHRoYXQgdGhpcyBibG9ja1R5cGUgY2FuIGhhdmUgYSByZWxhdGlvbnNoaXBcbiAgICAgIC8vIHRvIG