@tripsnek/tmf
Version:
TypeScript Modeling Framework - A TypeScript port of the Eclipse Modeling Framework (EMF)
749 lines • 98 kB
JavaScript
import { TUtils } from '../tutils.js';
import { EClassImpl } from '../metamodel/impl/eclass-impl.js';
import { EReferenceImpl } from '../metamodel/impl/ereference-impl.js';
/**
* Utilities for converting between EObjects and JSON. Usage:
*
* (1) TJson.makeJson(EObject) - converts an EObject to JSON.
* (2) TJson.makeEObject(json) - deserializes EObject encoded with (1).
* (3) TJson.makeJsonArray(EObject[]) - converts an array of EObjects to a JSON Array.
* (4) TJson.makeEObjectArray(json) - converts a JSON Array to an array of EObjects.
*
* You may also configure which EClasses are eligible for conversion with
* 'addPackages(EPackage[])' and 'setPackages(EPackage[])'.
*
*/
export class TJson {
//the name of the special JSON field that indicates each object's type
static JSON_FIELD_TYPESCRIPT_TYPE = '@type';
//These will be automatically added by the PackageInitializer when a Package is "touched"
static packages = [];
static setPackages(packages) {
this.packages = packages;
}
//automatically used by package initializers to add JSON serialization support when they are touched
static addPackages(packages) {
for (const p of packages) {
if (!this.packages.includes(p))
this.packages.push(p);
}
}
//the currently registered EPackages
static getPackages() {
return TJson.packages;
}
// Simple check - warn if no packages registered
static warnIfNotInitialized() {
if (this.packages.length === 0) {
console.warn('TJson: No packages registered. Call the package initializer using ' +
'<MyRootPackage>PackageInitializer.registerAll() before using TJson');
}
}
/**
* Converts a TMF EObject to JSON.
*
* @param obj
*/
static makeJson(obj) {
this.warnIfNotInitialized();
const context = new SerializationContext(obj);
return this.eObjectToJsonAux(obj, new Map(), false, context);
}
/**
* Converts an object in JSON Object into a TMF EObject.
* Creates proxy objects for unresolved non-containment references.
*
* @param json
* @return
*/
static makeEObject(jsonObj) {
this.warnIfNotInitialized();
const serializedReferences = new Array();
//build containment heirarchy
const eobj = this.jsonToEObject(jsonObj, serializedReferences);
if (!eobj)
return undefined;
// Create deserialization context
const context = new DeserializationContext(eobj);
//deserialize references, collecting unresolved ones
const unresolvedRefs = new Array();
serializedReferences.forEach((ref) => {
if (!ref.deserialize(context)) {
unresolvedRefs.push(ref);
}
});
// Create proxies for unresolved references
unresolvedRefs.forEach((ref) => {
this.createAndSetProxy(ref, context);
});
return eobj;
}
/**
* Creates a proxy object for an unresolved reference and sets it on the source object.
*
* @param ref The unresolved serialized reference
* @param context The deserialization context
*/
static createAndSetProxy(ref, context) {
// Handle SerializedReferenceWithObject specially
let fromObj;
if (ref instanceof SerializedReferenceWithObject) {
fromObj = ref.fromObj;
if (!fromObj || !ref.toId)
return;
}
else {
if (!ref.fromId || !ref.toId)
return;
fromObj = context.resolveId(ref.fromId);
if (!fromObj)
return;
}
// Path-based IDs that couldn't be resolved are internal inconsistencies
if (ref.toId.startsWith('@path:')) {
console.warn(`Cannot create proxy for unresolved path-based reference: ${ref.toId}`);
return;
}
const feature = fromObj.eClass().getEStructuralFeature(ref.refName);
if (!feature || !(feature instanceof EReferenceImpl))
return;
// Check if proxy already exists for this target
let proxy = context.resolveId(ref.toId);
if (!proxy) {
proxy = this.createProxy(ref.toId, feature);
if (proxy) {
// Add proxy to the index so future references to it can be resolved
context.getIndex().set(ref.toId, proxy);
}
}
if (proxy) {
// Set the reference
if (feature.isMany()) {
fromObj.eGet(feature).add(proxy);
}
else {
fromObj.eSet(feature, proxy);
}
}
}
/**
* Creates a proxy EObject for an unresolved reference.
*
* @param fullId The full ID of the target object (format: "ClassName_actualId")
* @param reference The reference feature to determine the target EClass
* @returns A proxy EObject or undefined if creation failed
*/
static createProxy(fullId, reference) {
// Path-based IDs cannot be proxied (they're internal references that should have been resolved)
if (fullId.startsWith('@path:')) {
console.warn(`Cannot create proxy for path-based ID: ${fullId}`);
return undefined;
}
// Parse the fullId to extract class name and actual ID
const underscoreIndex = fullId.indexOf('_');
if (underscoreIndex === -1) {
console.warn(`Invalid fullId format for proxy creation: ${fullId}`);
return undefined;
}
const className = fullId.substring(0, underscoreIndex);
const actualId = fullId.substring(underscoreIndex + 1);
// Get the target EClass from the reference type
const targetEClass = reference.getEType();
if (!targetEClass) {
console.warn(`No target EClass found for reference: ${reference.getName()}`);
return undefined;
}
// Verify the class name matches (safety check)
if (targetEClass.getName() !== className) {
console.warn(`Class name mismatch for proxy: expected ${className}, got ${targetEClass.getName()}`);
// Continue anyway - the reference type is authoritative
}
// Find the appropriate EPackage and factory
for (const pkg of this.packages) {
const classifiers = pkg.getEClassifiers();
for (const classifier of classifiers) {
if (classifier === targetEClass) {
try {
// Create the proxy object
const proxy = pkg.getEFactoryInstance().create(targetEClass);
// Set the ID attribute if it exists
const idAttribute = targetEClass.getEIDAttribute();
if (idAttribute) {
try {
// Parse the ID value to the correct type using TUtils
const parsedId = TUtils.parseAttrValFromString(idAttribute, actualId);
proxy.eSet(idAttribute, parsedId);
}
catch (error) {
console.warn(`Failed to parse ID value for proxy: ${actualId}`, error);
}
}
// Mark as proxy
proxy.eSetProxy(true);
// console.debug(`Created proxy object for ${fullId}`);
return proxy;
}
catch (error) {
console.error(`Failed to create proxy for ${fullId}:`, error);
return undefined;
}
}
}
}
console.warn(`No EPackage found containing EClass ${targetEClass.getName()} for proxy creation`);
return undefined;
}
/**
* Converts a TMF EObject array to JSON array.
*
* @param obj
*/
static makeJsonArray(objs) {
this.warnIfNotInitialized();
const jsonArray = [];
if (objs) {
objs.forEach((element) => {
jsonArray.push(this.makeJson(element));
});
}
return jsonArray;
}
/**
* Converts an object in JSON Array into am array of TMF EObjects.
*
* @param json
* @return
*/
static makeEObjectArray(jsonArray) {
this.warnIfNotInitialized();
const eobjArray = [];
jsonArray.forEach((element) => {
const eobj = this.makeEObject(element);
if (eobj)
eobjArray.push(eobj);
});
return eobjArray;
}
static jsonToEObject(jsonObj, serializedRefs) {
if (jsonObj == null) {
throw new Error('ERROR: null value for JSON Object. Cannot convert to EObject.');
}
//get the type indicator and instantiate the TMF Object
const objectType = jsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE];
if (objectType == null) {
console.error('ERROR: No value for ' +
this.JSON_FIELD_TYPESCRIPT_TYPE +
' was specified for the JSON object: ' +
jsonObj);
return undefined;
}
let eClass;
let eObj;
for (const pkg of this.packages) {
eClass = this.eClassByNameCaseInsensitive(objectType, pkg);
if (eClass) {
eObj = pkg.getEFactoryInstance().create(eClass);
break;
}
}
if (eClass && eObj) {
//handle all primitive attributes
this.setPrimitiveValuesOnJson(jsonObj, eObj);
//handle all references
for (const ref of eObj.eClass().getEAllReferences()) {
this.deserializeReferencedObjects(jsonObj, eObj, ref, serializedRefs);
}
}
return eObj;
}
static deserializeReferencedObjects(jsonObj, dObj, ref, serializedRefs) {
const jsonFieldName = this.getJsonFieldName(ref);
//multi-valued references
if (ref.isMany()) {
this.deserializeManyValuedReference(jsonObj, jsonFieldName, ref, dObj, serializedRefs);
} //single-valued references
else {
this.deserializeSingleValuedReference(jsonObj, jsonFieldName, ref, dObj, serializedRefs);
}
}
static deserializeSingleValuedReference(jsonObj, jsonFieldName, ref, tObj, serializedRefs) {
const referencedObj = jsonObj[jsonFieldName];
if (referencedObj) {
if (ref.isContainment()) {
const containeTJsonObj = referencedObj;
if (!containeTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE]) {
containeTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = ref.getEType().getName();
}
const referencedEmfObj = this.jsonToEObject(containeTJsonObj, serializedRefs);
tObj.eSet(ref, referencedEmfObj);
}
else {
// Store the object itself, not its ID - we'll resolve IDs later
serializedRefs.push(new SerializedReferenceWithObject(tObj, referencedObj, ref.getName()));
}
}
}
static deserializeManyValuedReference(jsonObj, jsonFieldName, ref, tObj, serializedRefs) {
const jsonArray = jsonObj[jsonFieldName];
if (jsonArray) {
jsonArray.forEach((containedTJsonObj, index) => {
if (ref.isContainment()) {
if (!containedTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE]) {
containedTJsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = ref
.getEType()
.getName();
}
const containedDObj = this.jsonToEObject(containedTJsonObj, serializedRefs);
tObj.eGet(ref).add(containedDObj);
}
else {
// Store the object itself, not its ID - we'll resolve IDs later
serializedRefs.push(new SerializedReferenceWithObject(tObj, containedTJsonObj, ref.getName()));
}
});
}
}
static eObjectToJsonAux(obj, serializedSoFar, attributesOnly, context) {
//make sure there is really an object to convert
if (obj == null) {
return null;
}
const jsonObj = {};
//Generate IDs for all Entities in the heirarchy which do not have them
if (!TUtils.getOrCreateIdForObject(obj))
TUtils.genIdIfNotExists(obj);
//add a type indicator for everything (the class name)
jsonObj[this.JSON_FIELD_TYPESCRIPT_TYPE] = obj.eClass().getName();
//handle all primitive attributes
this.attributesToJson(obj, jsonObj);
//handle all references
if (!attributesOnly) {
this.referencesToJson(obj, serializedSoFar, jsonObj, context);
}
return jsonObj;
}
static referencesToJson(obj, serializedSoFar, jsonObj, context) {
for (const ref of obj.eClass().getEAllReferences()) {
if (!ref.isVolatile() && !ref.isTransient()) {
//multi-valued references
if (ref.isMany()) {
this.manyValuedReferenceToJson(obj, ref, serializedSoFar, jsonObj, context);
}
//single-valued references
else {
this.singleValuedRefToJson(obj, ref, serializedSoFar, jsonObj, context);
}
}
}
}
static manyValuedReferenceToJson(obj, ref, serializedSoFar, jsonObj, context) {
const jsonFieldName = this.getJsonFieldName(ref);
const jsonArray = [];
for (const referencedObj of obj.eGet(ref)) {
if (referencedObj != null) {
if (ref.isContainment()) {
const referenceTJsonObj = this.eObjectToJsonAux(referencedObj, serializedSoFar, !ref.isContainment(), context);
if (referenceTJsonObj != null)
jsonArray.push(referenceTJsonObj);
}
else {
const fromId = context.getStableId(obj);
const toId = context.getStableId(referencedObj);
const serializedRef = new SerializedReference(fromId, toId, jsonFieldName).serialize();
jsonArray.push(serializedRef);
}
}
}
jsonObj[jsonFieldName] = jsonArray;
}
static singleValuedRefToJson(obj, ref, serializedSoFar, jsonObj, context) {
const jsonFieldName = this.getJsonFieldName(ref);
const referencedObj = obj.eGet(ref);
if (referencedObj != null) {
let referenceTJsonObj = null;
//if the object is 'contained', we generate it's full representation
if (ref.isContainment()) {
referenceTJsonObj = this.eObjectToJsonAux(referencedObj, serializedSoFar, !ref.isContainment(), context);
}
//otherwise, we generate a serialized pointer to the referenced object
else {
const fromId = context.getStableId(obj);
const toId = context.getStableId(referencedObj);
referenceTJsonObj = new SerializedReference(fromId, toId, jsonFieldName).serialize();
}
if (referenceTJsonObj != null)
jsonObj[jsonFieldName] = referenceTJsonObj;
}
}
static attributesToJson(obj, jsonObj) {
for (const attr of obj.eClass().getEAllAttributes()) {
if (!attr.isVolatile() && !attr.isTransient()) {
const jsonFieldName = this.getJsonFieldName(attr);
const origVal = obj.eGet(attr);
const convertedVal = this.primitiveValueToJson(attr, origVal);
jsonObj[jsonFieldName] = convertedVal;
}
}
}
/**
* Converts a primitive value (or a Date) for use inside JSON.
*
* @param val
* @return
*/
static primitiveValueToJson(attr, val) {
//serialize many-valued eattributes
if (attr.isMany()) {
const toRet = [];
for (const v of val) {
toRet.push(v instanceof Date ? v.toJSON() : v);
}
return toRet;
}
if (val instanceof Date) {
return val.toJSON();
}
return val;
}
static getJsonFieldName(feature) {
return feature.getName();
}
static eClassByNameCaseInsensitive(objectType, pkg) {
let dClass = pkg.getEClassifier(objectType);
if (dClass) {
//case insensitive checking of names
for (const eclass of pkg.getEClassifiers()) {
if (eclass instanceof EClassImpl &&
eclass.getName().toLowerCase() === objectType.toLowerCase()) {
dClass = eclass;
}
}
}
return dClass;
}
/**
* Sets all primitive (EAttribute) values on the eobject, given a
* JSONObject with the same fields.
*
* @param propsObj
* @param eObj
*/
static setPrimitiveValuesOnJson(propsObj, eObj) {
for (const attr of eObj.eClass().getEAllAttributes()) {
const jsonFieldName = this.getJsonFieldName(attr);
const jsonVal = propsObj[jsonFieldName];
if (jsonVal || jsonVal === 0) {
if (attr.isMany()) {
const array = jsonVal;
const coll = eObj.eGet(attr);
for (const o of array) {
coll.add(TUtils.parseAttrValFromString(attr, o));
}
}
else {
const tVal = TUtils.parseAttrValFromString(attr, jsonVal);
if (tVal || tVal === 0) {
eObj.eSet(attr, tVal);
}
else {
console.warn('JSON parse failed for ' +
eObj.eClass().getName() +
'.' +
attr.getName() +
' with value ' +
jsonVal.toString());
}
}
}
}
}
}
export class SerializedReference {
fromId;
toId;
refName;
constructor(from, to, ref) {
this.fromId = from;
this.toId = to;
this.refName = ref;
}
static create(fromDId, toDId, fromRef) {
return new SerializedReference(fromDId, toDId, fromRef);
}
/**
* Swizzles the object to JSON.
*/
serialize() {
return this.toId;
}
/**
* Restores the swizzled reference.
*
* @param context The deserialization context
* @returns true if the reference was successfully resolved, false if target object not found
*/
deserialize(context) {
const fromObj = context.resolveId(this.fromId);
const toObj = context.resolveId(this.toId);
if (fromObj && toObj) {
const feature = fromObj.eClass().getEStructuralFeature(this.refName);
//enforce the reference
if (fromObj && toObj && feature) {
if (feature.isMany())
fromObj.eGet(feature).add(toObj);
else
fromObj.eSet(feature, toObj);
return true;
}
}
return false;
}
}
/**
* Context object for managing state during serialization
*/
class SerializationContext {
tempIdCounter = 0;
objectToTempId = new Map();
root;
constructor(root) {
this.root = root;
}
/**
* Gets or creates a stable identifier for an object.
* Uses the object's ID if available, otherwise creates a path-based identifier.
*/
getStableId(obj) {
// First try to get the actual ID
const actualId = TUtils.getOrCreateIdForObject(obj);
if (actualId) {
return actualId;
}
// Check if we already created a temp ID for this object
const existingTempId = this.objectToTempId.get(obj);
if (existingTempId) {
return existingTempId;
}
// Create and cache a path-based identifier
const pathId = this.createPathBasedId(obj);
this.objectToTempId.set(obj, pathId);
return pathId;
}
/**
* Creates a path-based identifier for an object based on its containment path.
* Format: "@path:ClassName:/feature1[index]/feature2[index]/..."
*/
createPathBasedId(obj) {
if (obj === this.root) {
return `@path:${obj.eClass().getName()}:@root`;
}
const path = [];
let current = obj;
while (current && current !== this.root) {
const container = current.eContainer();
if (!container)
break;
// Find which containment feature holds this object
for (const ref of container.eClass().getEAllReferences()) {
if (ref.isContainment()) {
const value = container.eGet(ref);
if (ref.isMany()) {
const list = value;
const index = list.indexOf(current);
if (index >= 0) {
path.unshift(`${ref.getName()}[${index}]`);
break;
}
}
else if (value === current) {
path.unshift(ref.getName());
break;
}
}
}
current = container;
}
return `@path:${obj.eClass().getName()}:/${path.join('/')}`;
}
}
/**
* Context object for managing state during deserialization
*/
class DeserializationContext {
pathToObject = new Map();
root;
idsToObjs = new Map();
constructor(root) {
this.root = root;
this.buildIndex();
}
/**
* Builds an index of all contained objects using both real IDs and path-based IDs
*/
buildIndex() {
// Add root
const rootId = this.getStableId(this.root);
this.idsToObjs.set(rootId, this.root);
// Add all contained objects
this.root.eAllContents().forEach((elem) => {
const id = this.getStableId(elem);
this.idsToObjs.set(id, elem);
});
}
/**
* Gets the stable ID for an object (for indexing purposes during deserialization)
*/
getStableId(obj) {
const actualId = TUtils.getOrCreateIdForObject(obj);
if (actualId) {
return actualId;
}
return this.createPathBasedId(obj);
}
/**
* Creates a path-based identifier (same logic as SerializationContext)
*/
createPathBasedId(obj) {
if (obj === this.root) {
return `@path:${obj.eClass().getName()}:@root`;
}
const path = [];
let current = obj;
while (current && current !== this.root) {
const container = current.eContainer();
if (!container)
break;
for (const ref of container.eClass().getEAllReferences()) {
if (ref.isContainment()) {
const value = container.eGet(ref);
if (ref.isMany()) {
const list = value;
const index = list.indexOf(current);
if (index >= 0) {
path.unshift(`${ref.getName()}[${index}]`);
break;
}
}
else if (value === current) {
path.unshift(ref.getName());
break;
}
}
}
current = container;
}
return `@path:${obj.eClass().getName()}:/${path.join('/')}`;
}
/**
* Resolves a path-based identifier to an object within the containment hierarchy.
*/
resolvePathBasedId(pathId) {
// Check cache first
const cached = this.pathToObject.get(pathId);
if (cached)
return cached;
if (!pathId.startsWith('@path:')) {
return undefined;
}
const parts = pathId.substring(6).split(':');
if (parts.length !== 2)
return undefined;
const [className, pathStr] = parts;
if (pathStr === '@root') {
const result = this.root.eClass().getName() === className ? this.root : undefined;
if (result)
this.pathToObject.set(pathId, result);
return result;
}
// Parse the path
const pathSegments = pathStr?.substring(1).split('/').filter(s => s.length > 0) || [];
let current = this.root;
for (const segment of pathSegments) {
const match = segment.match(/^(.+?)(?:\[(\d+)\])?$/);
if (!match)
return undefined;
const featureName = match[1];
const index = match[2] ? parseInt(match[2]) : undefined;
if (!featureName)
return undefined;
const feature = current.eClass().getEStructuralFeature(featureName);
if (!feature || !(feature instanceof EReferenceImpl) || !feature.isContainment()) {
return undefined;
}
const value = current.eGet(feature);
if (feature.isMany()) {
if (index === undefined)
return undefined;
const list = value;
if (index >= list.size())
return undefined;
current = list.get(index);
}
else {
if (!value)
return undefined;
current = value;
}
}
// Verify the class name matches
const result = current.eClass().getName() === className ? current : undefined;
if (result)
this.pathToObject.set(pathId, result);
return result;
}
/**
* Gets the index map for looking up objects by ID
*/
getIndex() {
return this.idsToObjs;
}
/**
* Resolves an ID to an object, handling both regular and path-based IDs
*/
resolveId(id) {
// Try direct lookup first
let obj = this.idsToObjs.get(id);
// If not found and it's a path-based ID, try resolving it
if (!obj && id.startsWith('@path:')) {
obj = this.resolvePathBasedId(id);
if (obj) {
// Cache it for future lookups
this.idsToObjs.set(id, obj);
}
}
return obj;
}
}
/**
* Specialized SerializedReference for deserialization that holds the actual objects
* instead of IDs, since we don't know the IDs yet during construction.
*/
class SerializedReferenceWithObject extends SerializedReference {
fromObj;
toIdOrPath;
constructor(fromObj, toIdOrPath, refName) {
super('', toIdOrPath, refName);
this.fromObj = fromObj;
this.toIdOrPath = toIdOrPath;
}
deserialize(context) {
// Get the stable ID for the from object now that the hierarchy is complete
const fromId = context.getStableId(this.fromObj);
// The toIdOrPath is the serialized ID from the JSON
const toObj = context.resolveId(this.toIdOrPath);
if (this.fromObj && toObj) {
const feature = this.fromObj.eClass().getEStructuralFeature(this.refName);
if (feature) {
if (feature.isMany()) {
this.fromObj.eGet(feature).add(toObj);
}
else {
this.fromObj.eSet(feature, toObj);
}
return true;
}
}
return false;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGpzb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2pzb24vdGpzb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDOUQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBRXRFOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxPQUFPLEtBQUs7SUFDaEIsc0VBQXNFO0lBQy9ELE1BQU0sQ0FBQywwQkFBMEIsR0FBRyxPQUFPLENBQUM7SUFFbkQseUZBQXlGO0lBQ3pGLE1BQU0sQ0FBQyxRQUFRLEdBQWdCLEVBQUUsQ0FBQztJQUMzQixNQUFNLENBQUMsV0FBVyxDQUFDLFFBQW9CO1FBQzVDLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRCxvR0FBb0c7SUFDN0YsTUFBTSxDQUFDLFdBQVcsQ0FBQyxRQUFvQjtRQUM1QyxLQUFJLE1BQU0sQ0FBQyxJQUFJLFFBQVEsRUFBQyxDQUFDO1lBQ3ZCLElBQUcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7Z0JBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRCxvQ0FBb0M7SUFDN0IsTUFBTSxDQUFDLFdBQVc7UUFDdkIsT0FBTyxLQUFLLENBQUMsUUFBUSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxnREFBZ0Q7SUFDeEMsTUFBTSxDQUFDLG9CQUFvQjtRQUNqQyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxJQUFJLENBQ1Ysb0VBQW9FO2dCQUNwRSxvRUFBb0UsQ0FDckUsQ0FBQztR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