breeze-client
Version:
Breeze data management for JavaScript clients
460 lines • 68.8 kB
JavaScript
import { core } from './core';
import { EntityKey } from './entity-key';
import { EntityAspect } from './entity-aspect';
import { EntityState } from './entity-state';
import { EntityAction } from './entity-action';
import { EntityQuery } from './entity-query';
/** @hidden @internal */
export function defaultPropertyInterceptor(property, newValue, rawAccessorFn) {
// 'this' is the entity itself in this context.
if (newValue === undefined)
newValue = null; // remove? to allow assignment to undefined in Babel constructors?
let oldValue = rawAccessorFn();
let dataType = property.dataType;
if (dataType && dataType.parse) {
// attempts to coerce a value to the correct type - if this fails return the value unchanged
if (Array.isArray(newValue) && !property.isScalar) {
newValue = newValue.map(function (nv) {
return dataType.parse(nv, typeof nv);
});
}
else {
newValue = dataType.parse(newValue, typeof newValue);
}
}
// exit if no change - extra cruft is because dateTimes don't compare cleanly.
if (newValue === oldValue || (newValue === null && oldValue === undefined) ||
(dataType && dataType.normalize && newValue && oldValue && dataType.normalize(newValue) === dataType.normalize(oldValue))) {
return;
}
// CANNOT DO NEXT LINE because it has the possibility of creating a new property
// 'entityAspect' on 'this'. - Not permitted by IE inside of a defined property on a prototype.
// let entityAspect = new EntityAspect(this);
let propertyName;
let entityAspect = this.entityAspect;
if (entityAspect) {
propertyName = property.name;
}
else {
let localAspect = this.complexAspect;
if (localAspect) {
entityAspect = localAspect.getEntityAspect();
propertyName = localAspect.getPropertyPath(property.name);
}
else {
// does not yet have an EntityAspect so just set the prop
rawAccessorFn(newValue);
return;
}
}
// Note that we need to handle multiple properties in process, not just one in order to avoid recursion.
// ( except in the case of null propagation with fks where null -> 0 in some cases.)
// (this may not be needed because of the newValue === oldValue test above)
let inProcess = entityAspect._inProcess = entityAspect._inProcess || [];
// check for recursion
if (inProcess.indexOf(property) >= 0)
return;
inProcess.push(property);
try {
let context = {
parent: this,
property: property,
newValue: newValue,
oldValue: oldValue,
propertyName: propertyName,
entityAspect: entityAspect
};
if (property.isComplexProperty) {
setDpValueComplex(context, rawAccessorFn);
}
else if (property.isDataProperty) {
setDpValueSimple(context, rawAccessorFn);
}
else {
setNpValue(context, rawAccessorFn);
}
postChangeEvents(context);
}
finally {
inProcess.pop();
}
}
function setDpValueSimple(context, rawAccessorFn) {
let parent = context.parent;
let property = context.property;
let entityAspect = context.entityAspect;
let oldValue = context.oldValue;
let newValue = context.newValue;
let entityManager = entityAspect.entityManager;
if (!property.isScalar) {
throw new Error("Nonscalar data properties are readonly - items may be added or removed but the collection may not be changed.");
}
// store an original value for this property if not already set
if (entityAspect.entityState.isUnchangedOrModified()) {
let propName = property.name;
// localAspect is not the same as entityAspect for complex props
let localAspect = EntityAspect.isEntity(parent) ? parent.entityAspect : parent.complexAspect;
if (localAspect.originalValues[propName] === undefined) {
// otherwise this entry will be skipped during serialization
localAspect.originalValues[propName] = oldValue !== undefined ? oldValue : property.defaultValue;
}
}
// if we are changing the key update our internal entityGroup indexes.
if (property.isPartOfKey && entityManager && !entityManager.isLoading) {
// 'entityType' on the next line be null for complex properties but it will only be ref'd within this
// fn when the property is part of the key
let entityType = parent.entityType;
let keyProps = entityType.keyProperties;
let values = keyProps.map(function (p) {
if (p === property) {
return newValue;
}
else {
return parent.getProperty(p.name);
}
});
let newKey = new EntityKey(entityType, values);
if (entityManager.getEntityByKey(newKey)) {
throw new Error("An entity with this key is already in the cache: " + newKey.toString());
}
let oldKey = parent.entityAspect.getKey();
let eg = entityManager._findEntityGroup(entityType);
eg._replaceKey(oldKey, newKey);
}
// process related updates ( the inverse relationship) first so that collection dups check works properly.
// update inverse relationship
let relatedNavProp = property.relatedNavigationProperty;
if (relatedNavProp && entityManager) {
// Example: bidirectional fkDataProperty: 1->n: order -> orderDetails
// orderDetail.orderId <- newOrderId || null
// ==> orderDetail.order = lookupOrder(newOrderId)
// ==> (see set navProp above)
// and
// Example: bidirectional fkDataProperty: 1->1: order -> internationalOrder
// internationalOrder.orderId <- newOrderId || null
// ==> internationalOrder.order = lookupOrder(newOrderId)
// ==> (see set navProp above)
if (newValue != null) {
let relatedEntity;
let key;
if (relatedNavProp.invForeignKeyNames.length) {
// property is related by field which is not the PK
const query = new EntityQuery(relatedNavProp.entityType.defaultResourceName).where(relatedNavProp.invForeignKeyNames[0], 'eq', newValue);
const qresult = entityManager.executeQueryLocally(query);
if (qresult.length === 1) {
relatedEntity = qresult[0];
}
}
else {
// property is related by the PK
key = new EntityKey(relatedNavProp.entityType, [newValue]);
relatedEntity = entityManager.getEntityByKey(key);
}
if (relatedEntity) {
parent.setProperty(relatedNavProp.name, relatedEntity);
}
else {
// it may not have been fetched yet in which case we want to add it as an unattachedChild.
if (key) {
// TODO currently _linkRelatedentities only works with PK relations, so we only add those.
entityManager._unattachedChildrenMap.addChild(key, relatedNavProp, parent);
}
parent.setProperty(relatedNavProp.name, null);
}
}
else {
parent.setProperty(relatedNavProp.name, null);
}
}
else if (property.inverseNavigationProperty && entityManager && !entityManager._inKeyFixup) {
// Example: unidirectional fkDataProperty: 1->n: region -> territories
// territory.regionId <- newRegionId
// ==> lookupRegion(newRegionId).territories.push(territory)
// and
// Example: unidirectional fkDataProperty: 1->1: order -> internationalOrder
// internationalOrder.orderId <- newOrderId
// ==> lookupOrder(newOrderId).internationalOrder = internationalOrder
// and
// Example: unidirectional fkDataProperty: 1->n: region -> territories
// territory.regionId <- null
// ==> lookupRegion(territory.oldRegionId).territories.remove(oldTerritory);
// and
// Example: unidirectional fkDataProperty: 1->1: order -> internationalOrder
// internationalOrder.orderId <- null
// ==> lookupOrder(internationalOrder.oldOrderId).internationalOrder = null;
let invNavProp = property.inverseNavigationProperty;
if (oldValue != null) {
let key = new EntityKey(invNavProp.parentType, [oldValue]);
let relatedEntity = entityManager.getEntityByKey(key);
if (relatedEntity) {
if (invNavProp.isScalar) {
relatedEntity.setProperty(invNavProp.name, null);
}
else {
// remove 'this' from old related nav prop
let relatedArray = relatedEntity.getProperty(invNavProp.name);
// arr.splice(arr.indexOf(value_to_remove), 1);
relatedArray.splice(relatedArray.indexOf(parent), 1);
}
}
}
if (newValue != null) {
let key = new EntityKey(invNavProp.parentType, [newValue]);
let relatedEntity = entityManager.getEntityByKey(key);
if (relatedEntity) {
if (invNavProp.isScalar) {
relatedEntity.setProperty(invNavProp.name, parent);
}
else {
relatedEntity.getProperty(invNavProp.name).push(parent);
}
}
else {
// it may not have been fetched yet in which case we want to add it as an unattachedChild.
entityManager._unattachedChildrenMap.addChild(key, invNavProp, parent);
}
}
}
rawAccessorFn(newValue);
updateStateAndValidate(context);
// if (property.isPartOfKey && (!this.complexAspect)) {
if (property.isPartOfKey) {
// propogate pk change to all related entities;
let entityType = parent.entityType;
let propertyIx = entityType.keyProperties.indexOf(property);
// this part handles order.orderId => orderDetail.orderId
// but won't handle product.productId => orderDetail.productId because product
// doesn't have an orderDetails property.
entityType.navigationProperties.forEach(function (np) {
let inverseNp = np.inverse;
let fkNames = inverseNp ? inverseNp.foreignKeyNames : np.invForeignKeyNames;
if (fkNames.length === 0)
return;
let npValue = parent.getProperty(np.name);
if (!npValue)
return;
let fkName = fkNames[propertyIx];
if (np.isScalar) {
npValue.setProperty(fkName, newValue);
}
else {
npValue.slice(0).forEach(function (iv) {
iv.setProperty(fkName, newValue);
});
}
});
// this handles unidirectional problems not covered above.
if (entityManager) {
let inverseForeignKeyProperties = entityType.inverseForeignKeyProperties;
let baseEntityType = entityType.baseEntityType;
while (baseEntityType) {
inverseForeignKeyProperties = inverseForeignKeyProperties.concat(baseEntityType.inverseForeignKeyProperties);
baseEntityType = baseEntityType.baseEntityType;
}
inverseForeignKeyProperties.forEach((invFkProp) => {
if (invFkProp.relatedNavigationProperty.inverse == null) {
// this next step may be slow - it iterates over all of the entities in a group;
// hopefully it doesn't happen often.
entityManager._updateFkVal(invFkProp, oldValue, newValue);
}
});
}
// insure that cached key is updated.
entityAspect.getKey(true);
}
}
function setDpValueComplex(context, rawAccessorFn) {
let property = context.property;
let oldValue = context.oldValue;
let newValue = context.newValue;
// To get here it must be a ComplexProperty
// 'dataType' will be a complexType
let dataType = property.dataType;
if (property.isScalar) {
if (!newValue) {
throw new Error(core.formatString("You cannot set the '%1' property to null because its datatype is the ComplexType: '%2'", property.name, property.dataType.name));
}
if (!oldValue) {
let ctor = dataType.getCtor();
oldValue = new ctor();
rawAccessorFn(oldValue);
}
dataType.dataProperties.forEach(function (dp) {
let pn = dp.name;
let nv = newValue.getProperty(pn);
oldValue.setProperty(pn, nv);
});
}
else {
throw new Error(core.formatString("You cannot set the non-scalar complex property: '%1' on the type: '%2'." +
"Instead get the property and use array functions like 'push' or 'splice' to change its contents.", property.name, property.parentType.name));
}
}
function setNpValue(context, rawAccessorFn) {
let parent = context.parent;
let property = context.property;
let entityAspect = context.entityAspect;
let oldValue = context.oldValue;
let newValue = context.newValue;
if (!property.isScalar) {
throw new Error("Nonscalar navigation properties are readonly - entities can be added or removed but the collection may not be changed.");
}
let entityManager = entityAspect.entityManager;
let inverseProp = property.inverse;
// manage attachment -
if (newValue != null) {
if (!newValue.entityAspect) {
return;
}
let newAspect = newValue.entityAspect;
if (entityManager) {
if (newAspect.entityState.isDetached()) {
if (!entityManager.isLoading) {
entityManager.attachEntity(newValue, EntityState.Added);
}
}
else {
if (newAspect.entityManager !== entityManager) {
throw new Error("An Entity cannot be attached to an entity in another EntityManager. One of the two entities must be detached first.");
}
}
}
else {
if (newAspect && newAspect.entityManager) {
entityManager = newAspect.entityManager;
if (!entityManager.isLoading) {
entityManager.attachEntity(entityAspect.entity, EntityState.Added);
}
}
}
}
// process related updates ( the inverse relationship) first so that collection dups check works properly.
// update inverse relationship
if (inverseProp) {
///
if (inverseProp.isScalar) {
// Example: bidirectional navProperty: 1->1: order -> internationalOrder
// order.internationalOrder <- internationalOrder || null
// ==> (oldInternationalOrder.order = null)
// ==> internationalOrder.order = order
if (oldValue != null) {
// TODO: null -> NullEntity later
oldValue.setProperty(inverseProp.name, null);
}
if (newValue != null) {
newValue.setProperty(inverseProp.name, parent);
}
}
else {
// Example: bidirectional navProperty: 1->n: order -> orderDetails
// orderDetail.order <- newOrder || null
// ==> (oldOrder).orderDetails.remove(orderDetail)
// ==> order.orderDetails.push(newOrder)
if (oldValue != null) {
let oldSiblings = oldValue.getProperty(inverseProp.name);
let ix = oldSiblings.indexOf(parent);
if (ix !== -1) {
oldSiblings.splice(ix, 1);
}
}
if (newValue != null) {
let siblings = newValue.getProperty(inverseProp.name);
// recursion check if already in the collection is performed by the relationArray
siblings.push(parent);
}
}
}
else if (property.invForeignKeyNames && entityManager && !entityManager._inKeyFixup) {
let invForeignKeyNames = property.invForeignKeyNames;
if (newValue != null) {
// Example: unidirectional navProperty: 1->1: order -> internationalOrder
// order.InternationalOrder <- internationalOrder
// ==> internationalOrder.orderId = orderId
// and
// Example: unidirectional navProperty: 1->n: order -> orderDetails
// orderDetail.order <-xxx newOrder
// ==> CAN'T HAPPEN because if unidirectional because orderDetail will not have an order prop
let pkValues = parent.entityAspect.getKey().values;
invForeignKeyNames.forEach((fkName, i) => {
newValue.setProperty(fkName, pkValues[i]);
});
}
else {
// Example: unidirectional navProperty: 1->1: order -> internationalOrder
// order.internationalOrder <- null
// ==> (old internationalOrder).orderId = null
// and
// Example: unidirectional navProperty: 1->n: order -> orderDetails
// orderDetail.order <-xxx newOrder
// ==> CAN'T HAPPEN because if unidirectional because orderDetail will not have an order prop
if (oldValue != null) {
invForeignKeyNames.forEach((fkName) => {
let fkProp = oldValue.entityType.getProperty(fkName);
if (!fkProp.isPartOfKey) {
// don't update with null if fk is part of the key
oldValue.setProperty(fkName, null);
}
});
}
}
}
rawAccessorFn(newValue);
updateStateAndValidate(context);
// update fk data property - this can only occur if this navProperty has
// a corresponding fk on this entity.
if (property.relatedDataProperties) {
let entityState = entityAspect.entityState;
// if either side of nav prop is detached don't clear fks. Note: oldValue in next line cannot be null so no check is needed.
if (newValue == null && (entityState.isDetached() || oldValue.entityAspect.entityState.isDetached()))
return;
if (entityState.isDeleted())
return;
// we may have inverse props indicating the related prop on the other entity, if it is not the other entity's PK
let inverseKeyProps = property.invForeignKeyNames;
if (!(inverseKeyProps && inverseKeyProps.length)) {
// otherwise, this prop is related to the other entity's PK
inverseKeyProps = property.entityType.keyProperties.map(k => k.name);
}
inverseKeyProps.forEach(function (keyProp, i) {
let relatedDataProp = property.relatedDataProperties[i];
// Do not trash related property if it is part of that entity's key
if (newValue || !relatedDataProp.isPartOfKey) {
let relatedValue = newValue ? newValue.getProperty(keyProp) : relatedDataProp.defaultValue;
parent.setProperty(relatedDataProp.name, relatedValue);
}
});
}
}
function postChangeEvents(context) {
let entityAspect = context.entityAspect;
let entityManager = entityAspect.entityManager;
let entity = entityAspect.entity;
let propChangedArgs = { entity: entity, parent: context.parent, property: context.property, propertyName: context.propertyName, oldValue: context.oldValue, newValue: context.newValue };
if (entityManager) {
// propertyChanged will be fired during loading but we only want to fire it once per entity, not once per property.
// so propertyChanged is fired in the entityManager mergeEntity method if not fired here.
if ((!entityManager.isLoading) && (!entityManager.isRejectingChanges)) {
entityAspect.propertyChanged.publish(propChangedArgs);
// don't fire entityChanged event if propertyChanged is suppressed.
entityManager.entityChanged.publish({ entityAction: EntityAction.PropertyChange, entity: entity, args: propChangedArgs });
}
}
else {
entityAspect.propertyChanged.publish(propChangedArgs);
}
}
function updateStateAndValidate(context) {
let entityAspect = context.entityAspect;
let entityManager = entityAspect.entityManager;
if (entityManager == null || entityManager.isLoading)
return;
let property = context.property;
if (entityAspect.entityState.isUnchanged() && !property.isUnmapped) {
entityAspect.setModified();
}
if (entityManager.validationOptions.validateOnPropertyChange) {
// entityAspect.entity is NOT the same as parent in the code below. It's use is deliberate.
entityAspect._validateProperty(context.newValue, { entity: entityAspect.entity, property: property, propertyName: context.propertyName, oldValue: context.oldValue });
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1wcm9wZXJ0eS1pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWZhdWx0LXByb3BlcnR5LWludGVyY2VwdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFOUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUEyQyxNQUFNLGlCQUFpQixDQUFDO0FBQ3hGLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDLHdCQUF3QjtBQUN4QixNQUFNLFVBQVUsMEJBQTBCLENBQXlCLFFBQXdCLEVBQUUsUUFBYSxFQUFFLGFBQXVCO0lBQ2pJLCtDQUErQztJQUUvQyxJQUFJLFFBQVEsS0FBSyxTQUFTO1FBQUUsUUFBUSxHQUFHLElBQUksQ0FBQyxDQUFDLGtFQUFrRTtJQUMvRyxJQUFJLFFBQVEsR0FBRyxhQUFhLEVBQUUsQ0FBQztJQUUvQixJQUFJLFFBQVEsR0FBSSxRQUFnQixDQUFDLFFBQVEsQ0FBQztJQUMxQyxJQUFJLFFBQVEsSUFBSSxRQUFRLENBQUMsS0FBSyxFQUFFO1FBQzlCLDRGQUE0RjtRQUM1RixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFO1lBQ2pELFFBQVEsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRTtnQkFDbEMsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZDLENBQUMsQ0FBQyxDQUFDO1NBQ0o7YUFBTTtZQUNMLFFB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LEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7S0FDMUg7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY29yZSB9IGZyb20gJy4vY29yZSc7XHJcbmltcG9ydCB7IENvbXBsZXhUeXBlLCBEYXRhUHJvcGVydHksIE5hdmlnYXRpb25Qcm9wZXJ0eSwgRW50aXR5UHJvcGVydHkgfSBmcm9tICcuL2VudGl0eS1tZXRhZGF0YSc7XHJcbmltcG9ydCB7IEVudGl0eUtleSB9IGZyb20gJy4vZW50aXR5LWtleSc7XHJcbmltcG9ydCB7IEVudGl0eUFzcGVjdCwgQ29tcGxleEFzcGVjdCwgRW50aXR5LCBTdHJ1Y3R1cmFsT2JqZWN0IH0gZnJvbSAnLi9lbnRpdHktYXNwZWN0JztcclxuaW1wb3J0IHsgRW50aXR5U3RhdGUgfSBmcm9tICcuL2VudGl0eS1zdGF0ZSc7XHJcbmltcG9ydCB7IEVudGl0eUFjdGlvbiB9IGZyb20gJy4vZW50aXR5LWFjdGlvbic7XHJcbmltcG9ydCB7IEVudGl0eVF1ZXJ5IH0gZnJvbSAnLi9lbnRpdHktcXVlcnknO1xyXG5cclxuLyoqIEBoaWRkZW4gQGludGVybmFsICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWZhdWx0UHJvcGVydHlJbnRlcmNlcHRvcih0aGlzOiBTdHJ1Y3R1cmFsT2JqZWN0LCBwcm9wZXJ0eTogRW50aXR5UHJvcGVydHksIG5ld1ZhbHVlOiBhbnksIHJhd0FjY2Vzc29yRm46IEZ1bmN0aW9uKSB7XHJcbiAgLy8gJ3RoaXMnIGlzIHRoZSBlbnRpdHkgaXRzZWxmIGluIHRoaXMgY29udGV4dC5cclxuXHJcbiAgaWYgKG5ld1ZhbHVlID09PSB1bmRlZmluZWQpIG5ld1ZhbHVlID0gbnVsbDsgLy8gcmVtb3ZlPyB0byBhbGxvdyBhc3NpZ25tZW50IHRvIHVuZGVmaW5lZCBpbiBCYWJlbCBjb25zdHJ1Y3RvcnM/XHJcbiAgbGV0IG9sZFZhbHVlID0gcmF3QWNjZXNzb3JGbigpO1xyXG5cclxuICBsZXQgZGF0YVR5cGUgPSAocHJvcGVydHkgYXMgYW55KS5kYXRhVHlwZTtcclxuICBpZiAoZGF0YVR5cGUgJiYgZGF0YVR5cGUucGFyc2UpIHtcclxuICAgIC8vIGF0dGVtcHRzIHRvIGNvZXJjZSBhIHZhbHVlIHRvIHRoZSBjb3JyZWN0IHR5cGUgLSBpZiB0aGlzIGZhaWxzIHJldHVybiB0aGUgdmFsdWUgdW5jaGFuZ2VkXHJcbiAgICBpZiAoQXJyYXkuaXNBcnJheShuZXdWYWx1ZSkgJiYgIXByb3BlcnR5LmlzU2NhbGFyKSB7XHJcbiAgICAgIG5ld1ZhbHVlID0gbmV3VmFsdWUubWFwKGZ1bmN0aW9uIChudikge1xyXG4gICAgICAgIHJldHVybiBkYXRhVHlwZS5wYXJzZShudiwgdHlwZW9mIG52KTtcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBuZXdWYWx1ZSA9IGRhdGFUeXBlLnBhcnNlKG5ld1ZhbHVlLCB0eXBlb2YgbmV3VmFsdWUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gZXhpdCBpZiBubyBjaGFuZ2UgLSBleHRyYSBjcnVmdCBpcyBiZWNhdXNlIGRhdGVUaW1lcyBkb24ndCBjb21wYXJlIGNsZWFubHkuXHJcbiAgaWYgKG5ld1ZhbHVlID09PSBvbGRWYWx1ZSB8fCAobmV3VmFsdWUgPT09IG51bGwgJiYgb2xkVmFsdWUgPT09IHVuZGVmaW5lZCkgfHwgXHJcbiAgICAoZGF0YVR5cGUgJiYgZGF0YVR5cGUubm9ybWFsaXplICYmIG5ld1ZhbHVlICYmIG9sZFZhbHVlICYmIGRhdGFUeXBlLm5vcm1hbGl6ZShuZXdWYWx1ZSkgPT09IGRhdGFUeXBlLm5vcm1hbGl6ZShvbGRWYWx1ZSkpKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDQU5OT1QgRE8gTkVYVCBMSU5FIGJlY2F1c2UgaXQgaGFzIHRoZSBwb3NzaWJpbGl0eSBvZiBjcmVhdGluZyBhIG5ldyBwcm9wZXJ0eVxyXG4gIC8vICdlbnRpdHlBc3BlY3QnIG9uICd0aGlzJy4gIC0gTm90IHBlcm1pdHRlZCBieSBJRSBpbnNpZGUgb2YgYSBkZWZpbmVkIHByb3BlcnR5IG9uIGEgcHJvdG90eXBlLlxyXG4gIC8vIGxldCBlbnRpdHlBc3BlY3QgPSBuZXcgRW50aXR5QXNwZWN0KHRoaXMpO1xyXG5cclxuICBsZXQgcHJvcGVydHlOYW1lOiBzdHJpbmc7XHJcbiAgbGV0IGVudGl0eUFzcGVjdCA9ICh0aGlzIGFzIGFueSkuZW50aXR5QXNwZWN0IGFzIEVudGl0eUFzcGVjdDtcclxuICBpZiAoZW50aXR5QXNwZWN0KSB7XHJcbiAgICBwcm9wZXJ0eU5hbWUgPSBwcm9wZXJ0eS5uYW1lO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgbG9jYWxBc3BlY3QgPSAodGhpcyBhcyBhbnkpLmNvbXBsZXhBc3BlY3QgYXMgQ29tcGxleEFzcGVjdDtcclxuICAgIGlmIChsb2NhbEFzcGVjdCkge1xyXG4gICAgICBlbnRpdHlBc3BlY3QgPSBsb2NhbEFzcGVjdC5nZXRFbnRpdHlBc3BlY3QoKTtcclxuICAgICAgcHJvcGVydHlOYW1lID0gbG9jYWxBc3BlY3QuZ2V0UHJvcGVydHlQYXRoKHByb3BlcnR5Lm5hbWUpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gZG9lcyBub3QgeWV0IGhhdmUgYW4gRW50aXR5QXNwZWN0IHNvIGp1c3Qgc2V0IHRoZSBwcm9wXHJcbiAgICAgIHJhd0FjY2Vzc29yRm4obmV3VmFsdWUpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBOb3RlIHRoYXQgd2UgbmVlZCB0byBoYW5kbGUgbXVsdGlwbGUgcHJvcGVydGllcyBpbiBwcm9jZXNzLCBub3QganVzdCBvbmUgaW4gb3JkZXIgdG8gYXZvaWQgcmVjdXJzaW9uLlxyXG4gIC8vICggZXhjZXB0IGluIHRoZSBjYXNlIG9mIG51bGwgcHJvcGFnYXRpb24gd2l0aCBma3Mgd2hlcmUgbnVsbCAtPiAwIGluIHNvbWUgY2FzZXMuKVxyXG4gIC8vICh0aGlzIG1heSBub3QgYmUgbmVlZGVkIGJlY2F1c2Ugb2YgdGhlIG5ld1ZhbHVlID09PSBvbGRWYWx1ZSB0ZXN0IGFib3ZlKVxyXG4gIGxldCBpblByb2Nlc3MgPSBlbnRpdHlBc3BlY3QuX2luUHJvY2VzcyA9IGVudGl0eUFzcGVjdC5faW5Qcm9jZXNzIHx8IFtdO1xyXG4gIC8vIGNoZWNrIGZvciByZWN1cnNpb25cclxuICBpZiAoaW5Qcm9jZXNzLmluZGV4T2YocHJvcGVydHkpID49IDApIHJldHVybjtcclxuICBpblByb2Nlc3MucHVzaChwcm9wZXJ0eSk7XHJcblxyXG4gIHRyeSB7XHJcblxyXG4gICAgbGV0IGNvbnRleHQ6IElDb250ZXh0ID0ge1xyXG4gICAgICBwYXJlbnQ6IHRoaXMsXHJcbiAgICAgIHByb3BlcnR5OiBwcm9wZXJ0eSxcclxuICAgICAgbmV3VmFsdWU6IG5ld1ZhbHVlLFxyXG4gICAgICBvbGRWYWx1ZTogb2xkVmFsdWUsXHJcbiAgICAgIHByb3BlcnR5TmFtZTogcHJvcGVydHlOYW1lLFxyXG4gICAgICBlbnRpdHlBc3BlY3Q6IGVudGl0eUFzcGVjdFxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoKHByb3BlcnR5IGFzIGFueSkuaXNDb21wbGV4UHJvcGVydHkpIHtcclxuICAgICAgc2V0RHBWYWx1ZUNvbXBsZXgoY29udGV4dCwgcmF3QWNjZXNzb3JGbik7XHJcbiAgICB9IGVsc2UgaWYgKHByb3BlcnR5LmlzRGF0YVByb3BlcnR5KSB7XHJcbiAgICAgIHNldERwVmFsdWVTaW1wbGUoY29udGV4dCwgcmF3QWNjZXNzb3JGbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzZXROcFZhbHVlKGNvbnRleHQsIHJhd0FjY2Vzc29yRm4pO1xyXG4gICAgfVxyXG5cclxuICAgIHBvc3RDaGFuZ2VFdmVudHMoY29udGV4dCk7XHJcblxyXG4gIH0gZmluYWxseSB7XHJcbiAgICBpblByb2Nlc3MucG9wKCk7XHJcbiAgfVxyXG59XHJcblxyXG5pbnRlcmZhY2UgSUNvbnRleHQge1xyXG4gIHBhcmVudDogU3RydWN0dXJhbE9iamVjdDtcclxuICBwcm9wZXJ0eTogRW50aXR5UHJvcGVydHk7XHJcbiAgcHJvcGVydHlOYW1lOiBzdHJpbmc7XHJcbiAgZW50aXR5QXNwZWN0OiBFbnRpdHlBc3BlY3Q7XHJcbiAgb2xkVmFsdWU6IGFueTtcclxuICBuZXdWYWx1ZTogYW55O1xyXG59XHJcblxyXG5mdW5jdGlvbiBzZXREcFZhbHVlU2ltcGxlKGNvbnRleHQ6IElDb250ZXh0LCByYXdBY2Nlc3NvckZuOiBhbnkpIHtcclxuICBsZXQgcGFyZW50ID0gY29udGV4dC5wYXJlbnQ7XHJcbiAgbGV0IHByb3BlcnR5ID0gY29udGV4dC5wcm9wZXJ0eSBhcyBEYXRhUHJvcGVydHk7XHJcbiAgbGV0IGVudGl0eUFzcGVjdCA9IGNvbnRleHQuZW50aXR5QXNwZWN0O1xyXG4gIGxldCBvbGRWYWx1ZSA9IGNvbnRleHQub2xkVmFsdWU7XHJcbiAgbGV0IG5ld1ZhbHVlID0gY29udGV4dC5uZXdWYWx1ZTtcclxuXHJcbiAgbGV0IGVudGl0eU1hbmFnZXIgPSBlbnRpdHlBc3BlY3QuZW50aXR5TWFuYWdlcjtcclxuXHJcbiAgaWYgKCFwcm9wZXJ0eS5pc1NjYWxhcikge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiTm9uc2NhbGFyIGRhdGEgcHJvcGVydGllcyBhcmUgcmVhZG9ubHkgLSBpdGVtcyBtYXkgYmUgYWRkZWQgb3IgcmVtb3ZlZCBidXQgdGhlIGNvbGxlY3Rpb24gbWF5IG5vdCBiZSBjaGFuZ2VkLlwiKTtcclxuICB9XHJcblxyXG4gIC8vIHN0b3JlIGFuIG9yaWdpbmFsIHZhbHVlIGZvciB0aGlzIHByb3BlcnR5IGlmIG5vdCBhbHJlYWR5IHNldFxyXG4gIGlmIChlbnRpdHlBc3BlY3QuZW50aXR5U3RhdGUuaXNVbmNoYW5nZWRPck1vZGlmaWVkKCkpIHtcclxuICAgIGxldCBwcm9wTmFtZSA9IHByb3BlcnR5Lm5hbWU7XHJcbiAgICAvLyBsb2NhbEFzcGVjdCBpcyBub3QgdGhlIHNhbWUgYXMgZW50aXR5QXNwZWN0IGZvciBjb21wbGV4IHByb3BzXHJcbiAgICBsZXQgbG9jYWxBc3BlY3QgPSBFbnRpdHlBc3BlY3QuaXNFbnRpdHkocGFyZW50KSA/IHBhcmVudC5lbnRpdHlBc3BlY3QgOiBwYXJlbnQuY29tcGxleEFzcGVjdDtcclxuICAgIGlmIChsb2NhbEFzcGVjdC5vcmlnaW5hbFZhbHVlc1twcm9wTmFtZV0gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAvLyBvdGhlcndpc2UgdGhpcyBlbnRyeSB3aWxsIGJlIHNraXBwZWQgZHVyaW5nIHNlcmlhbGl6YXRpb25cclxuICAgICAgbG9jYWxBc3BlY3Qub3JpZ2luYWxWYWx1ZXNbcHJvcE5hbWVdID0gb2xkVmFsdWUgIT09IHVuZGVmaW5lZCA/IG9sZFZhbHVlIDogcHJvcGVydHkuZGVmYXVsdFZhbHVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gaWYgd2UgYXJlIGNoYW5naW5nIHRoZSBrZXkgdXBkYXRlIG91ciBpbnRlcm5hbCBlbnRpdHlHcm91cCBpbmRleGVzLlxyXG4gIGlmIChwcm9wZXJ0eS5pc1BhcnRPZktleSAmJiBlbnRpdHlNYW5hZ2VyICYmICFlbnRpdHlNYW5hZ2VyLmlzTG9hZGluZykge1xyXG4gICAgLy8gJ2VudGl0eVR5cGUnIG9uIHRoZSBuZXh0IGxpbmUgYmUgbnVsbCBmb3IgY29tcGxleCBwcm9wZXJ0aWVzIGJ1dCBpdCB3aWxsIG9ubHkgYmUgcmVmJ2Qgd2l0aGluIHRoaXNcclxuICAgIC8vIGZuIHdoZW4gdGhlIHByb3BlcnR5IGlzIHBhcnQgb2YgdGhlIGtleVxyXG4gICAgbGV0IGVudGl0eVR5cGUgPSAocGFyZW50IGFzIEVudGl0eSkuZW50aXR5VHlwZTtcclxuICAgIGxldCBrZXlQcm9wcyA9IGVudGl0eVR5cGUua2V5UHJvcGVydGllcztcclxuICAgIGxldCB2YWx1ZXMgPSBrZXlQcm9wcy5tYXAoZnVuY3Rpb24gKHApIHtcclxuICAgICAgaWYgKHAgPT09IHByb3BlcnR5KSB7XHJcbiAgICAgICAgcmV0dXJuIG5ld1ZhbHVlO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBwYXJlbnQuZ2V0UHJvcGVydHkocC5uYW1lKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICBsZXQgbmV3S2V5ID0gbmV3IEVudGl0eUtleShlbnRpdHlUeXBlLCB2YWx1ZXMpO1xyXG4gICAgaWYgKGVudGl0eU1hbmFnZXIuZ2V0RW50aXR5QnlLZXkobmV3S2V5KSkge1xyXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBbiBlbnRpdHkgd2l0aCB0aGlzIGtleSBpcyBhbHJlYWR5IGluIHRoZSBjYWNoZTogXCIgKyBuZXdLZXkudG9TdHJpbmcoKSk7XHJcbiAgICB9XHJcbiAgICBsZXQgb2xkS2V5ID0gKHBhcmVudCBhcyBFbnRpdHkpLmVudGl0eUFzcGVjdC5nZXRLZXkoKTtcclxuICAgIGxldCBlZyA9IGVudGl0eU1hbmFnZXIuX2ZpbmRFbnRpdHlHcm91cChlbnRpdHlUeXBlKTtcclxuICAgIGVnLl9yZXBsYWNlS2V5KG9sZEtleSwgbmV3S2V5KTtcclxuICB9XHJcblxyXG4gIC8vIHByb2Nlc3MgcmVsYXRlZCB1cGRhdGVzICggdGhlIGludmVyc2UgcmVsYXRpb25zaGlwKSBmaXJzdCBzbyB0aGF0IGNvbGxlY3Rpb24gZHVwcyBjaGVjayB3b3JrcyBwcm9wZXJseS5cclxuICAvLyB1cGRhdGUgaW52ZXJzZSByZWxhdGlvbnNoaXBcclxuXHJcbiAgbGV0IHJlbGF0ZWROYXZQcm9wID0gcHJvcGVydHkucmVsYXRlZE5hdmlnYXRpb25Qcm9wZXJ0eTtcclxuICBpZiAocmVsYXRlZE5hdlByb3AgJiYgZW50aXR5TWFuYWdlcikge1xyXG4gICAgLy8gRXhhbXBsZTogYmlkaXJlY3Rpb25hbCBma0RhdGFQcm9wZXJ0eTogMS0+bjogb3JkZXIgLT4gb3JkZXJEZXRhaWxzXHJcbiAgICAvLyBvcmRlckRldGFpbC5vcmRlcklkIDwtIG5ld09yZGVySWQgfHwgbnVsbFxyXG4gICAgLy8gICAgPT0+IG9yZGVyRGV0YWlsLm9yZGVyID0gbG9va3VwT3JkZXIobmV3T3JkZXJJZClcclxuICAgIC8vICAgID09PiAoc2VlIHNldCBuYXZQcm9wIGFib3ZlKVxyXG4gICAgLy8gICAgICAgYW5kXHJcbiAgICAvLyBFeGFtcGxlOiBiaWRpcmVjdGlvbmFsIGZrRGF0YVByb3BlcnR5OiAxLT4xOiBvcmRlciAtPiBpbnRlcm5hdGlvbmFsT3JkZXJcclxuICAgIC8vIGludGVybmF0aW9uYWxPcmRlci5vcmRlcklkIDwtIG5ld09yZGVySWQgfHwgbnVsbFxyXG4gICAgLy8gICAgPT0+IGludGVybmF0aW9uYWxPcmRlci5vcmRlciA9IGxvb2t1cE9yZGVyKG5ld09yZGVySWQpXHJcbiAgICAvLyAgICA9PT4gKHNlZSBzZXQgbmF2UHJvcCBhYm92ZSlcclxuXHJcbiAgICBpZiAobmV3VmFsdWUgIT0gbnVsbCkge1xyXG4gICAgICBsZXQgcmVsYXRlZEVudGl0eTogRW50aXR5O1xyXG4gICAgICBsZXQga2V5OiBFbnRpdHlLZXk7XHJcbiAgICAgIGlmIChyZWxhdGVkTmF2UHJvcC5pbnZGb3JlaWduS2V5TmFtZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgLy8gcHJvcGVydHkgaXMgcmVsYXRlZCBieSBmaWVsZCB3aGljaCBpcyBub3QgdGhlIFBLXHJcbiAgICAgICAgY29uc3QgcXVlcnkgPSBuZXcgRW50aXR5UXVlcnkocmVsYXRlZE5hdlByb3AuZW50aXR5VHlwZS5kZWZhdWx0UmVzb3VyY2VOYW1lKS53aGVyZShyZWxhdGVkTmF2UHJvcC5pbnZGb3JlaWduS2V5TmFtZXNbMF0sICdlcScsIG5ld1ZhbHVlKTtcclxuICAgICAgICBjb25zdCBxcmVzdWx0ID0gZW50aXR5TWFuYWdlci5leGVjdXRlUXVlcnlMb2NhbGx5KHF1ZXJ5KTtcclxuICAgICAgICBpZiAocXJlc3VsdC5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgIHJlbGF0ZWRFbnRpdHkgPSBxcmVzdWx0WzBdO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBwcm9wZXJ0eSBpcyByZWxhdGVkIGJ5IHRoZSBQS1xyXG4gICAgICAgIGtleSA9IG5ldyBFbnRpdHlLZXkocmVsYXRlZE5hdlByb3AuZW50aXR5VHlwZSwgW25ld1ZhbHVlXSk7XHJcbiAgICAgICAgcmVsYXRlZEVudGl0eSA9IGVudGl0eU1hbmFnZXIuZ2V0RW50aXR5QnlLZXkoa2V5KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHJlbGF0ZWRFbnRpdHkpIHtcclxuICAgICAgICBwYXJlbnQuc2V0UHJvcGVydHkocmVsYXRlZE5hdlByb3AubmFtZ