Standardize settings file naming and relocate documentation files Fix code quality violations from rsx:check Reorganize user_management directory into logical subdirectories Move Quill Bundle to core and align with Tom Select pattern Simplify Site Settings page to focus on core site information Complete Phase 5: Multi-tenant authentication with login flow and site selection Add route query parameter rule and synchronize filename validation logic Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs Implement filename convention rule and resolve VS Code auto-rename conflict Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns Implement RPC server architecture for JavaScript parsing WIP: Add RPC server infrastructure for JS parsing (partial implementation) Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation Add JQHTML-CLASS-01 rule and fix redundant class names Improve code quality rules and resolve violations Remove legacy fatal error format in favor of unified 'fatal' error type Filter internal keys from window.rsxapp output Update button styling and comprehensive form/modal documentation Add conditional fly-in animation for modals Fix non-deterministic bundle compilation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
191 lines
19 KiB
JavaScript
Executable File
191 lines
19 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
// @FILE-SUBCLASS-01-EXCEPTION
|
|
|
|
/**
|
|
* Base class for JavaScript ORM models
|
|
*
|
|
* Provides core functionality for fetching records from backend PHP models.
|
|
* All model stubs generated by the manifest extend this base class.
|
|
*
|
|
* Example usage:
|
|
* // Fetch single record
|
|
* const user = await User_Model.fetch(123);
|
|
*
|
|
* // Fetch multiple records
|
|
* const users = await User_Model.fetch([1, 2, 3]);
|
|
*
|
|
* // Create instance with data
|
|
* const user = new User_Model({id: 1, name: 'John'});
|
|
*
|
|
* @Instantiatable
|
|
*/
|
|
class Rsx_Js_Model {
|
|
/**
|
|
* Constructor - Initialize model instance with data
|
|
*
|
|
* @param {Object} data - Key-value pairs to populate the model
|
|
*/
|
|
constructor() {
|
|
let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
// __MODEL SYSTEM: Enables automatic ORM instantiation when fetching from PHP models.
|
|
// PHP models add "__MODEL": "ClassName" to JSON, JavaScript uses it to create proper instances.
|
|
// This provides typed model objects instead of plain JSON, with methods and type checking.
|
|
|
|
// This constructor filters out the __MODEL marker that was used to identify which class
|
|
// to instantiate, keeping only the actual data properties on the instance.
|
|
const {
|
|
__MODEL,
|
|
...modelData
|
|
} = data;
|
|
Object.assign(this, modelData);
|
|
}
|
|
|
|
/**
|
|
* Fetch record(s) from the backend model
|
|
*
|
|
* This method mirrors the PHP Model::fetch() functionality.
|
|
* The backend model must have a fetch() method with the
|
|
* #[Ajax_Endpoint_Model_Fetch] annotation to be callable.
|
|
*
|
|
* @param {number|Array} id - Single ID or array of IDs to fetch
|
|
* @returns {Promise} - Single model instance, array of instances, or false
|
|
*/
|
|
static async fetch(id) {
|
|
const CurrentClass = this;
|
|
// Get the model class name from the current class
|
|
const modelName = CurrentClass.name;
|
|
const response = await $.ajax({
|
|
url: `/_fetch/${modelName}`,
|
|
method: 'POST',
|
|
data: {
|
|
id: id
|
|
},
|
|
dataType: 'json'
|
|
});
|
|
|
|
// Handle response based on type
|
|
if (response === false) {
|
|
return false;
|
|
}
|
|
|
|
// Use _instantiate_models_recursive to handle ORM instantiation
|
|
// This will automatically detect __MODEL properties and create appropriate instances
|
|
return Rsx_Js_Model._instantiate_models_recursive(response);
|
|
}
|
|
|
|
/**
|
|
* Get the model class name
|
|
* Used internally for API calls
|
|
*
|
|
* @returns {string} The class name
|
|
*/
|
|
static getModelName() {
|
|
const CurrentClass = this;
|
|
return CurrentClass.name;
|
|
}
|
|
|
|
/**
|
|
* Refresh this instance with latest data from server
|
|
*
|
|
* @returns {Promise} Updated instance or false if not found
|
|
*/
|
|
async refresh() {
|
|
const that = this;
|
|
if (!that.id) {
|
|
shouldnt_happen('Cannot refresh model without id property');
|
|
}
|
|
const fresh = await that.constructor.fetch(that.id);
|
|
if (fresh === false) {
|
|
return false;
|
|
}
|
|
|
|
// Update this instance with fresh data
|
|
Object.assign(that, fresh);
|
|
return that;
|
|
}
|
|
|
|
/**
|
|
* Convert model instance to plain object
|
|
* Useful for serialization or sending to APIs
|
|
*
|
|
* @returns {Object} Plain object representation
|
|
*/
|
|
toObject() {
|
|
const that = this;
|
|
const obj = {};
|
|
for (const key in that) {
|
|
if (that.hasOwnProperty(key) && typeof that[key] !== 'function') {
|
|
obj[key] = that[key];
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/**
|
|
* Convert model instance to JSON string
|
|
*
|
|
* @returns {string} JSON representation
|
|
*/
|
|
toJSON() {
|
|
const that = this;
|
|
return JSON.stringify(that.toObject());
|
|
}
|
|
|
|
/**
|
|
* Recursively instantiate ORM models in response data
|
|
*
|
|
* Looks for objects with __MODEL property and instantiates the appropriate
|
|
* JavaScript model class if it exists in the global scope.
|
|
*
|
|
* @param {*} data - The data to process (can be any type)
|
|
* @returns {*} The data with ORM objects instantiated
|
|
*/
|
|
static _instantiate_models_recursive(data) {
|
|
// __MODEL SYSTEM: Enables automatic ORM instantiation when fetching from PHP models.
|
|
// PHP models add "__MODEL": "ClassName" to JSON, JavaScript uses it to create proper instances.
|
|
// This provides typed model objects instead of plain JSON, with methods and type checking.
|
|
|
|
// This recursive processor scans all API response data looking for __MODEL markers.
|
|
// When found, it attempts to instantiate the appropriate JavaScript model class,
|
|
// converting {__MODEL: "User_Model", id: 1, name: "John"} into new User_Model({...}).
|
|
// Works recursively through arrays and nested objects to handle complex data structures.
|
|
// Handle null/undefined
|
|
if (data === null || data === undefined) {
|
|
return data;
|
|
}
|
|
|
|
// Handle arrays - recursively process each element
|
|
if (Array.isArray(data)) {
|
|
return data.map(item => Rsx_Js_Model._instantiate_models_recursive(item));
|
|
}
|
|
|
|
// Handle objects
|
|
if (typeof data === 'object') {
|
|
// Check if this object has a __MODEL property
|
|
if (data.__MODEL && typeof data.__MODEL === 'string') {
|
|
// Try to find the model class in the global scope
|
|
const ModelClass = window[data.__MODEL];
|
|
|
|
// If the model class exists and extends Rsx_Js_Model, instantiate it
|
|
// Dynamic model resolution requires checking class existence - @JS-DEFENSIVE-01-EXCEPTION
|
|
if (ModelClass && ModelClass.prototype instanceof Rsx_Js_Model) {
|
|
return new ModelClass(data);
|
|
}
|
|
}
|
|
|
|
// Recursively process all object properties
|
|
const result = {};
|
|
for (const key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
result[key] = Rsx_Js_Model._instantiate_models_recursive(data[key]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Return primitive values as-is
|
|
return data;
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSc3hfSnNfTW9kZWwiLCJjb25zdHJ1Y3RvciIsImRhdGEiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJ1bmRlZmluZWQiLCJfX01PREVMIiwibW9kZWxEYXRhIiwiT2JqZWN0IiwiYXNzaWduIiwiZmV0Y2giLCJpZCIsIkN1cnJlbnRDbGFzcyIsIm1vZGVsTmFtZSIsIm5hbWUiLCJyZXNwb25zZSIsIiQiLCJhamF4IiwidXJsIiwibWV0aG9kIiwiZGF0YVR5cGUiLCJfaW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZSIsImdldE1vZGVsTmFtZSIsInJlZnJlc2giLCJ0aGF0Iiwic2hvdWxkbnRfaGFwcGVuIiwiZnJlc2giLCJ0b09iamVjdCIsIm9iaiIsImtleSIsImhhc093blByb3BlcnR5IiwidG9KU09OIiwiSlNPTiIsInN0cmluZ2lmeSIsIkFycmF5IiwiaXNBcnJheSIsIm1hcCIsIml0ZW0iLCJNb2RlbENsYXNzIiwid2luZG93IiwicHJvdG90eXBlIiwicmVzdWx0Il0sInNvdXJjZXMiOlsiYXBwL1JTcGFkZS9Db3JlL0pzL1JzeF9Kc19Nb2RlbC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBARklMRS1TVUJDTEFTUy0wMS1FWENFUFRJT05cblxuLyoqXG4gKiBCYXNlIGNsYXNzIGZvciBKYXZhU2NyaXB0IE9STSBtb2RlbHNcbiAqXG4gKiBQcm92aWRlcyBjb3JlIGZ1bmN0aW9uYWxpdHkgZm9yIGZldGNoaW5nIHJlY29yZHMgZnJvbSBiYWNrZW5kIFBIUCBtb2RlbHMuXG4gKiBBbGwgbW9kZWwgc3R1YnMgZ2VuZXJhdGVkIGJ5IHRoZSBtYW5pZmVzdCBleHRlbmQgdGhpcyBiYXNlIGNsYXNzLlxuICpcbiAqIEV4YW1wbGUgdXNhZ2U6XG4gKiAgIC8vIEZldGNoIHNpbmdsZSByZWNvcmRcbiAqICAgY29uc3QgdXNlciA9IGF3YWl0IFVzZXJfTW9kZWwuZmV0Y2goMTIzKTtcbiAqXG4gKiAgIC8vIEZldGNoIG11bHRpcGxlIHJlY29yZHNcbiAqICAgY29uc3QgdXNlcnMgPSBhd2FpdCBVc2VyX01vZGVsLmZldGNoKFsxLCAyLCAzXSk7XG4gKlxuICogICAvLyBDcmVhdGUgaW5zdGFuY2Ugd2l0aCBkYXRhXG4gKiAgIGNvbnN0IHVzZXIgPSBuZXcgVXNlcl9Nb2RlbCh7aWQ6IDEsIG5hbWU6ICdKb2huJ30pO1xuICpcbiAqICBASW5zdGFudGlhdGFibGVcbiAqL1xuY2xhc3MgUnN4X0pzX01vZGVsIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvciAtIEluaXRpYWxpemUgbW9kZWwgaW5zdGFuY2Ugd2l0aCBkYXRhXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEtleS12YWx1ZSBwYWlycyB0byBwb3B1bGF0ZSB0aGUgbW9kZWxcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihkYXRhID0ge30pIHtcbiAgICAgICAgLy8gX19NT0RFTCBTWVNURU06IEVuYWJsZXMgYXV0b21hdGljIE9STSBpbnN0YW50aWF0aW9uIHdoZW4gZmV0Y2hpbmcgZnJvbSBQSFAgbW9kZWxzLlxuICAgICAgICAvLyBQSFAgbW9kZWxzIGFkZCBcIl9fTU9ERUxcIjogXCJDbGFzc05hbWVcIiB0byBKU09OLCBKYXZhU2NyaXB0IHVzZXMgaXQgdG8gY3JlYXRlIHByb3BlciBpbnN0YW5jZXMuXG4gICAgICAgIC8vIFRoaXMgcHJvdmlkZXMgdHlwZWQgbW9kZWwgb2JqZWN0cyBpbnN0ZWFkIG9mIHBsYWluIEpTT04sIHdpdGggbWV0aG9kcyBhbmQgdHlwZSBjaGVja2luZy5cblxuICAgICAgICAvLyBUaGlzIGNvbnN0cnVjdG9yIGZpbHRlcnMgb3V0IHRoZSBfX01PREVMIG1hcmtlciB0aGF0IHdhcyB1c2VkIHRvIGlkZW50aWZ5IHdoaWNoIGNsYXNzXG4gICAgICAgIC8vIHRvIGluc3RhbnRpYXRlLCBrZWVwaW5nIG9ubHkgdGhlIGFjdHVhbCBkYXRhIHByb3BlcnRpZXMgb24gdGhlIGluc3RhbmNlLlxuICAgICAgICBjb25zdCB7IF9fTU9ERUwsIC4uLm1vZGVsRGF0YSB9ID0gZGF0YTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLCBtb2RlbERhdGEpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZldGNoIHJlY29yZChzKSBmcm9tIHRoZSBiYWNrZW5kIG1vZGVsXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBtaXJyb3JzIHRoZSBQSFAgTW9kZWw6OmZldGNoKCkgZnVuY3Rpb25hbGl0eS5cbiAgICAgKiBUaGUgYmFja2VuZCBtb2RlbCBtdXN0IGhhdmUgYSBmZXRjaCgpIG1ldGhvZCB3aXRoIHRoZVxuICAgICAqICNbQWpheF9FbmRwb2ludF9Nb2RlbF9GZXRjaF0gYW5ub3RhdGlvbiB0byBiZSBjYWxsYWJsZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfEFycmF5fSBpZCAtIFNpbmdsZSBJRCBvciBhcnJheSBvZiBJRHMgdG8gZmV0Y2hcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBTaW5nbGUgbW9kZWwgaW5zdGFuY2UsIGFycmF5IG9mIGluc3RhbmNlcywgb3IgZmFsc2VcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgZmV0Y2goaWQpIHtcbiAgICAgICAgY29uc3QgQ3VycmVudENsYXNzID0gdGhpcztcbiAgICAgICAgLy8gR2V0IHRoZSBtb2RlbCBjbGFzcyBuYW1lIGZyb20gdGhlIGN1cnJlbnQgY2xhc3NcbiAgICAgICAgY29uc3QgbW9kZWxOYW1lID0gQ3VycmVudENsYXNzLm5hbWU7XG5cbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCAkLmFqYXgoe1xuICAgICAgICAgICAgdXJsOiBgL19mZXRjaC8ke21vZGVsTmFtZX1gLFxuICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICBkYXRhOiB7IGlkOiBpZCB9LFxuICAgICAgICAgICAgZGF0YVR5cGU6ICdqc29uJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gSGFuZGxlIHJlc3BvbnNlIGJhc2VkIG9uIHR5cGVcbiAgICAgICAgaWYgKHJlc3BvbnNlID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVXNlIF9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlIHRvIGhhbmRsZSBPUk0gaW5zdGFudGlhdGlvblxuICAgICAgICAvLyBUaGlzIHdpbGwgYXV0b21hdGljYWxseSBkZXRlY3QgX19NT0RFTCBwcm9wZXJ0aWVzIGFuZCBjcmVhdGUgYXBwcm9wcmlhdGUgaW5zdGFuY2VzXG4gICAgICAgIHJldHVybiBSc3hfSnNfTW9kZWwuX2luc3RhbnRpYXRlX21vZGVsc19yZWN1cnNpdmUocmVzcG9uc2UpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgbW9kZWwgY2xhc3MgbmFtZVxuICAgICAqIFVzZWQgaW50ZXJuYWxseSBmb3IgQVBJIGNhbGxzXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2xhc3MgbmFtZVxuICAgICAqL1xuICAgIHN0YXRpYyBnZXRNb2RlbE5hbWUoKSB7XG4gICAgICAgIGNvbnN0IEN1cnJlbnRDbGFzcyA9IHRoaXM7XG4gICAgICAgIHJldHVybiBDdXJyZW50Q2xhc3MubmFtZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWZyZXNoIHRoaXMgaW5zdGFuY2Ugd2l0aCBsYXRlc3QgZGF0YSBmcm9tIHNlcnZlclxuICAgICAqXG4gICAgICogQHJldHVybnMge1Byb21pc2V9IFVwZGF0ZWQgaW5zdGFuY2Ugb3IgZmFsc2UgaWYgbm90IGZvdW5kXG4gICAgICovXG4gICAgYXN5bmMgcmVmcmVzaCgpIHtcbiAgICAgICAgY29uc3QgdGhhdCA9IHRoaXM7XG4gICAgICAgIGlmICghdGhhdC5pZCkge1xuICAgICAgICAgICAgc2hvdWxkbnRfaGFwcGVuKCdDYW5ub3QgcmVmcmVzaCBtb2RlbCB3aXRob3V0IGlkIHByb3BlcnR5Jyk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBmcmVzaCA9IGF3YWl0IHRoYXQuY29uc3RydWN0b3IuZmV0Y2godGhhdC5pZCk7XG5cbiAgICAgICAgaWYgKGZyZXNoID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVXBkYXRlIHRoaXMgaW5zdGFuY2Ugd2l0aCBmcmVzaCBkYXRhXG4gICAgICAgIE9iamVjdC5hc3NpZ24odGhhdCwgZnJlc2gpO1xuICAgICAgICByZXR1cm4gdGhhdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb252ZXJ0IG1vZGVsIGluc3RhbmNlIHRvIHBsYWluIG9iamVjdFxuICAgICAqIFVzZWZ1bCBmb3Igc2VyaWFsaXphdGlvbiBvciBzZW5kaW5nIHRvIEFQSXNcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IFBsYWluIG9iamVjdCByZXByZXNlbnRhdGlvblxuICAgICAqL1xuICAgIHRvT2JqZWN0KCkge1xuICAgICAgICBjb25zdCB0aGF0ID0gdGhpcztcbiAgICAgICAgY29uc3Qgb2JqID0ge307XG4gICAgICAgIGZvciAoY29uc3Qga2V5IGluIHRoYXQpIHtcbiAgICAgICAgICAgIGlmICh0aGF0Lmhhc093blByb3BlcnR5KGtleSkgJiYgdHlwZW9mIHRoYXRba2V5XSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgIG9ialtrZXldID0gdGhhdFtrZXldO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydCBtb2RlbCBpbnN0YW5jZSB0byBKU09OIHN0cmluZ1xuICAgICAqXG4gICAgICogQHJldHVybnMge3N0cmluZ30gSlNPTiByZXByZXNlbnRhdGlvblxuICAgICAqL1xuICAgIHRvSlNPTigpIHtcbiAgICAgICAgY29uc3QgdGhhdCA9IHRoaXM7XG4gICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh0aGF0LnRvT2JqZWN0KCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlY3Vyc2l2ZWx5IGluc3RhbnRpYXRlIE9STSBtb2RlbHMgaW4gcmVzcG9uc2UgZGF0YVxuICAgICAqXG4gICAgICogTG9va3MgZm9yIG9iamVjdHMgd2l0aCBfX01PREVMIHByb3BlcnR5IGFuZCBpbnN0YW50aWF0ZXMgdGhlIGFwcHJvcHJpYXRlXG4gICAgICogSmF2YVNjcmlwdCBtb2RlbCBjbGFzcyBpZiBpdCBleGlzdHMgaW4gdGhlIGdsb2JhbCBzY29wZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Kn0gZGF0YSAtIFRoZSBkYXRhIHRvIHByb2Nlc3MgKGNhbiBiZSBhbnkgdHlwZSlcbiAgICAgKiBAcmV0dXJucyB7Kn0gVGhlIGRhdGEgd2l0aCBPUk0gb2JqZWN0cyBpbnN0YW50aWF0ZWRcbiAgICAgKi9cbiAgICBzdGF0aWMgX2luc3RhbnRpYXRlX21vZGVsc19yZWN1cnNpdmUoZGF0YSkge1xuICAgICAgICAvLyBfX01PREVMIFNZU1RFTTogRW5hYmxlcyBhdXRvbWF0aWMgT1JNIGluc3RhbnRpYXRpb24gd2hlbiBmZXRjaGluZyBmcm9tIFBIUCBtb2RlbHMuXG4gICAgICAgIC8vIFBIUCBtb2RlbHMgYWRkIFwiX19NT0RFTFwiOiBcIkNsYXNzTmFtZVwiIHRvIEpTT04sIEphdmFTY3JpcHQgdXNlcyBpdCB0byBjcmVhdGUgcHJvcGVyIGluc3RhbmNlcy5cbiAgICAgICAgLy8gVGhpcyBwcm92aWRlcyB0eXBlZCBtb2RlbCBvYmplY3RzIGluc3RlYWQgb2YgcGxhaW4gSlNPTiwgd2l0aCBtZXRob2RzIGFuZCB0eXBlIGNoZWNraW5nLlxuXG4gICAgICAgIC8vIFRoaXMgcmVjdXJzaXZlIHByb2Nlc3NvciBzY2FucyBhbGwgQVBJIHJlc3BvbnNlIGRhdGEgbG9va2luZyBmb3IgX19NT0RFTCBtYXJrZXJzLlxuICAgICAgICAvLyBXaGVuIGZvdW5kLCBpdCBhdHRlbXB0cyB0byBpbnN0YW50aWF0ZSB0aGUgYXBwcm9wcmlhdGUgSmF2YVNjcmlwdCBtb2RlbCBjbGFzcyxcbiAgICAgICAgLy8gY29udmVydGluZyB7X19NT0RFTDogXCJVc2VyX01vZGVsXCIsIGlkOiAxLCBuYW1lOiBcIkpvaG5cIn0gaW50byBuZXcgVXNlcl9Nb2RlbCh7Li4ufSkuXG4gICAgICAgIC8vIFdvcmtzIHJlY3Vyc2l2ZWx5IHRocm91Z2ggYXJyYXlzIGFuZCBuZXN0ZWQgb2JqZWN0cyB0byBoYW5kbGUgY29tcGxleCBkYXRhIHN0cnVjdHVyZXMuXG4gICAgICAgIC8vIEhhbmRsZSBudWxsL3VuZGVmaW5lZFxuICAgICAgICBpZiAoZGF0YSA9PT0gbnVsbCB8fCBkYXRhID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGFycmF5cyAtIHJlY3Vyc2l2ZWx5IHByb2Nlc3MgZWFjaCBlbGVtZW50XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgICAgICAgICByZXR1cm4gZGF0YS5tYXAoKGl0ZW0pID0+IFJzeF9Kc19Nb2RlbC5faW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZShpdGVtKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBIYW5kbGUgb2JqZWN0c1xuICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGlzIG9iamVjdCBoYXMgYSBfX01PREVMIHByb3BlcnR5XG4gICAgICAgICAgICBpZiAoZGF0YS5fX01PREVMICYmIHR5cGVvZiBkYXRhLl9fTU9ERUwgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGZpbmQgdGhlIG1vZGVsIGNsYXNzIGluIHRoZSBnbG9iYWwgc2NvcGVcbiAgICAgICAgICAgICAgICBjb25zdCBNb2RlbENsYXNzID0gd2luZG93W2RhdGEuX19NT0RFTF07XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgbW9kZWwgY2xhc3MgZXhpc3RzIGFuZCBleHRlbmRzIFJzeF9Kc19Nb2RlbCwgaW5zdGFudGlhdGUgaXRcbiAgICAgICAgICAgICAgICAvLyBEeW5hbWljIG1vZGVsIHJlc29sdXRpb24gcmVxdWlyZXMgY2hlY2tpbmcgY2xhc3MgZXhpc3RlbmNlIC0gQEpTLURFRkVOU0lWRS0wMS1FWENFUFRJT05cbiAgICAgICAgICAgICAgICBpZiAoTW9kZWxDbGFzcyAmJiBNb2RlbENsYXNzLnByb3RvdHlwZSBpbnN0YW5jZW9mIFJzeF9Kc19Nb2RlbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE1vZGVsQ2xhc3MoZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBSZWN1cnNpdmVseSBwcm9jZXNzIGFsbCBvYmplY3QgcHJvcGVydGllc1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0ge307XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHRba2V5XSA9IFJzeF9Kc19Nb2RlbC5faW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZShkYXRhW2tleV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZXR1cm4gcHJpbWl0aXZlIHZhbHVlcyBhcy1pc1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTUEsWUFBWSxDQUFDO0VBQ2Y7QUFDSjtB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
|