mzinga
Version:
Node, React and MongoDB Headless CMS and Application Framework
520 lines (519 loc) • 73.3 kB
JavaScript
/* 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