faastjs
Version:
Serverless batch computing made simple.
115 lines • 13.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.caches = exports.PersistentCache = void 0;
const fs_extra_1 = require("fs-extra");
const os_1 = require("os");
const path_1 = require("path");
const uuid_1 = require("uuid");
const crypto_1 = require("crypto");
/**
* A simple persistent key-value store. Used to implement {@link Limits.cache}
* for {@link throttle}.
* @remarks
* Entries can be expired, but are not actually deleted individually. The entire
* cache can be deleted at once. Hence this cache is useful for storing results
* that are expensive to compute but do not change too often (e.g. the
* node_modules folder from an 'npm install' where 'package.json' is not
* expected to change too often).
*
* By default faast.js will use the directory `~/.faastjs` as a local cache to
* store data such as pricing retrieved from cloud APIs, and garbage collection
* information. This directory can be safely deleted if no faast.js instances
* are running.
* @public
*/
class PersistentCache {
async initialize(dir) {
if (!(await (0, fs_extra_1.pathExists)(dir))) {
await (0, fs_extra_1.mkdirp)(dir);
}
}
/**
* Construct a new persistent cache, typically used with {@link Limits} as
* part of the arguments to {@link throttle}.
* @param dirRelativeToHomeDir - The directory under the user's home
* directory that will be used to store cached values. The directory will be
* created if it doesn't exist.
* @param expiration - The age (in ms) after which a cached entry is
* invalid. Default: `24*3600*1000` (1 day).
*/
constructor(
/**
* The directory under the user's home directory that will be used to
* store cached values. The directory will be created if it doesn't
* exist.
*/
dirRelativeToHomeDir,
/**
* The age (in ms) after which a cached entry is invalid. Default:
* `24*3600*1000` (1 day).
*/
expiration = 24 * 3600 * 1000) {
this.dirRelativeToHomeDir = dirRelativeToHomeDir;
this.expiration = expiration;
this.dir = (0, path_1.join)((0, os_1.homedir)(), dirRelativeToHomeDir);
this.initialized = this.initialize(this.dir);
}
hash(key) {
const hasher = (0, crypto_1.createHash)("sha256");
hasher.update(key);
return hasher.digest("hex");
}
/**
* Retrieves the value previously set for the given key, or undefined if the
* key is not found.
*/
async get(key) {
await this.initialized;
const entry = (0, path_1.join)(this.dir, this.hash(key));
const statEntry = await (0, fs_extra_1.stat)(entry).catch(_ => { });
if (statEntry) {
if (Date.now() - statEntry.mtimeMs > this.expiration) {
return undefined;
}
return (0, fs_extra_1.readFile)(entry).catch(_ => undefined);
}
return undefined;
}
/**
* Set the cache key to the given value.
* @returns a Promise that resolves when the cache entry has been persisted.
*/
async set(key, value) {
await this.initialized;
const entry = (0, path_1.join)(this.dir, this.hash(key));
const tmpEntry = (0, path_1.join)(this.dir, (0, uuid_1.v4)());
await (0, fs_extra_1.writeFile)(tmpEntry, value, { mode: 0o600, encoding: "binary" });
await (0, fs_extra_1.rename)(tmpEntry, entry);
}
/**
* Retrieve all keys stored in the cache, including expired entries.
*/
entries() {
return (0, fs_extra_1.readdir)(this.dir);
}
/**
* Deletes all cached entries from disk.
* @param leaveEmptyDir - If true, leave the cache directory in place after
* deleting its contents. If false, the cache directory will be removed.
* Default: `true`.
*/
async clear({ leaveEmptyDir = true } = {}) {
await this.initialized;
await (0, fs_extra_1.remove)(this.dir);
if (leaveEmptyDir) {
await (0, fs_extra_1.mkdirp)(this.dir);
}
}
}
exports.PersistentCache = PersistentCache;
const days = 24 * 3600 * 1000;
exports.caches = {
awsPrices: new PersistentCache(".faastjs/aws/pricing", 1 * days),
awsGc: new PersistentCache(".faastjs/aws/gc", 7 * days)
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdUNBU2tCO0FBQ2xCLDJCQUE2QjtBQUM3QiwrQkFBNEI7QUFFNUIsK0JBQW9DO0FBQ3BDLG1DQUFvQztBQUlwQzs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFhLGVBQWU7SUFHaEIsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFXO1FBQ2hDLElBQUksQ0FBQyxDQUFDLE1BQU0sSUFBQSxxQkFBVSxFQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUU7WUFDMUIsTUFBTSxJQUFBLGlCQUFNLEVBQUMsR0FBRyxDQUFDLENBQUM7U0FDckI7SUFDTCxDQUFDO0lBT0Q7Ozs7Ozs7O09BUUc7SUFDSDtJQUNJOzs7O09BSUc7SUFDTSxvQkFBNEI7SUFDckM7OztPQUdHO0lBQ00sYUFBcUIsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJO1FBTHJDLHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBUTtRQUs1QixlQUFVLEdBQVYsVUFBVSxDQUEyQjtRQUU5QyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUEsV0FBSSxFQUFDLElBQUEsWUFBTyxHQUFFLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFTyxJQUFJLENBQUMsR0FBVztRQUNwQixNQUFNLE1BQU0sR0FBRyxJQUFBLG1CQUFVLEVBQUMsUUFBUSxDQUFDLENBQUM7UUFDcEMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQixPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBVztRQUNqQixNQUFNLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDdkIsTUFBTSxLQUFLLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDN0MsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFBLGVBQUksRUFBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztRQUNuRCxJQUFJLFNBQVMsRUFBRTtZQUNYLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRTtnQkFDbEQsT0FBTyxTQUFTLENBQUM7YUFDcEI7WUFDRCxPQUFPLElBQUEsbUJBQVEsRUFBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQztTQUNoRDtRQUNELE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsR0FBRyxDQUFDLEdBQVcsRUFBRSxLQUFtQztRQUN0RCxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDdkIsTUFBTSxLQUFLLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDN0MsTUFBTSxRQUFRLEdBQUcsSUFBQSxXQUFJLEVBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFBLFNBQU0sR0FBRSxDQUFDLENBQUM7UUFDMUMsTUFBTSxJQUFBLG9CQUFTLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDdEUsTUFBTSxJQUFBLGlCQUFNLEVBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7T0FFRztJQUNILE9BQU87UUFDSCxPQUFPLElBQUEsa0JBQU8sRUFBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLGFBQWEsR0FBRyxJQUFJLEVBQUUsR0FBRyxFQUFFO1FBQ3JDLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUV2QixNQUFNLElBQUEsaUJBQU0sRUFBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFdkIsSUFBSSxhQUFhLEVBQUU7WUFDZixNQUFNLElBQUEsaUJBQU0sRUFBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDMUI7SUFDTCxDQUFDO0NBQ0o7QUFqR0QsMENBaUdDO0FBRUQsTUFBTSxJQUFJLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFFakIsUUFBQSxNQUFNLEdBQUc7SUFDbEIsU0FBUyxFQUFFLElBQUksZUFBZSxDQUFDLHNCQUFzQixFQUFFLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDaEUsS0FBSyxFQUFFLElBQUksZUFBZSxDQUFDLGlCQUFpQixFQUFFLENBQUMsR0FBRyxJQUFJLENBQUM7Q0FDMUQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgbWtkaXJwLFxuICAgIHBhdGhFeGlzdHMsXG4gICAgcmVhZGRpcixcbiAgICByZWFkRmlsZSxcbiAgICByZW1vdmUsXG4gICAgcmVuYW1lLFxuICAgIHN0YXQsXG4gICAgd3JpdGVGaWxlXG59IGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IHsgaG9tZWRpciB9IGZyb20gXCJvc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBSZWFkYWJsZSB9IGZyb20gXCJzdHJlYW1cIjtcbmltcG9ydCB7IHY0IGFzIHV1aWR2NCB9IGZyb20gXCJ1dWlkXCI7XG5pbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSBcImNyeXB0b1wiO1xuXG5pbnRlcmZhY2UgQmxvYiB7fVxuXG4vKipcbiAqIEEgc2ltcGxlIHBlcnNpc3RlbnQga2V5LXZhbHVlIHN0b3JlLiBVc2VkIHRvIGltcGxlbWVudCB7QGxpbmsgTGltaXRzLmNhY2hlfVxuICogZm9yIHtAbGluayB0aHJvdHRsZX0uXG4gKiBAcmVtYXJrc1xuICogRW50cmllcyBjYW4gYmUgZXhwaXJlZCwgYnV0IGFyZSBub3QgYWN0dWFsbHkgZGVsZXRlZCBpbmRpdmlkdWFsbHkuIFRoZSBlbnRpcmVcbiAqIGNhY2hlIGNhbiBiZSBkZWxldGVkIGF0IG9uY2UuIEhlbmNlIHRoaXMgY2FjaGUgaXMgdXNlZnVsIGZvciBzdG9yaW5nIHJlc3VsdHNcbiAqIHRoYXQgYXJlIGV4cGVuc2l2ZSB0byBjb21wdXRlIGJ1dCBkbyBub3QgY2hhbmdlIHRvbyBvZnRlbiAoZS5nLiB0aGVcbiAqIG5vZGVfbW9kdWxlcyBmb2xkZXIgZnJvbSBhbiAnbnBtIGluc3RhbGwnIHdoZXJlICdwYWNrYWdlLmpzb24nIGlzIG5vdFxuICogZXhwZWN0ZWQgdG8gY2hhbmdlIHRvbyBvZnRlbikuXG4gKlxuICogQnkgZGVmYXVsdCBmYWFzdC5qcyB3aWxsIHVzZSB0aGUgZGlyZWN0b3J5IGB+Ly5mYWFzdGpzYCBhcyBhIGxvY2FsIGNhY2hlIHRvXG4gKiBzdG9yZSBkYXRhIHN1Y2ggYXMgcHJpY2luZyByZXRyaWV2ZWQgZnJvbSBjbG91ZCBBUElzLCBhbmQgZ2FyYmFnZSBjb2xsZWN0aW9uXG4gKiBpbmZvcm1hdGlvbi4gVGhpcyBkaXJlY3RvcnkgY2FuIGJlIHNhZmVseSBkZWxldGVkIGlmIG5vIGZhYXN0LmpzIGluc3RhbmNlc1xuICogYXJlIHJ1bm5pbmcuXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjbGFzcyBQZXJzaXN0ZW50Q2FjaGUge1xuICAgIHByaXZhdGUgaW5pdGlhbGl6ZWQ6IFByb21pc2U8dm9pZD47XG5cbiAgICBwcml2YXRlIGFzeW5jIGluaXRpYWxpemUoZGlyOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKCEoYXdhaXQgcGF0aEV4aXN0cyhkaXIpKSkge1xuICAgICAgICAgICAgYXdhaXQgbWtkaXJwKGRpcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZGlyZWN0b3J5IG9uIGRpc2sgd2hlcmUgY2FjaGVkIHZhbHVlcyBhcmUgc3RvcmVkLlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGRpcjogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgbmV3IHBlcnNpc3RlbnQgY2FjaGUsIHR5cGljYWxseSB1c2VkIHdpdGgge0BsaW5rIExpbWl0c30gYXNcbiAgICAgKiBwYXJ0IG9mIHRoZSBhcmd1bWVudHMgdG8ge0BsaW5rIHRocm90dGxlfS5cbiAgICAgKiBAcGFyYW0gZGlyUmVsYXRpdmVUb0hvbWVEaXIgLSBUaGUgZGlyZWN0b3J5IHVuZGVyIHRoZSB1c2VyJ3MgaG9tZVxuICAgICAqIGRpcmVjdG9yeSB0aGF0IHdpbGwgYmUgdXNlZCB0byBzdG9yZSBjYWNoZWQgdmFsdWVzLiBUaGUgZGlyZWN0b3J5IHdpbGwgYmVcbiAgICAgKiBjcmVhdGVkIGlmIGl0IGRvZXNuJ3QgZXhpc3QuXG4gICAgICogQHBhcmFtIGV4cGlyYXRpb24gLSBUaGUgYWdlIChpbiBtcykgYWZ0ZXIgd2hpY2ggYSBjYWNoZWQgZW50cnkgaXNcbiAgICAgKiBpbnZhbGlkLiBEZWZhdWx0OiBgMjQqMzYwMCoxMDAwYCAoMSBkYXkpLlxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGRpcmVjdG9yeSB1bmRlciB0aGUgdXNlcidzIGhvbWUgZGlyZWN0b3J5IHRoYXQgd2lsbCBiZSB1c2VkIHRvXG4gICAgICAgICAqIHN0b3JlIGNhY2hlZCB2YWx1ZXMuIFRoZSBkaXJlY3Rvcnkgd2lsbCBiZSBjcmVhdGVkIGlmIGl0IGRvZXNuJ3RcbiAgICAgICAgICogZXhpc3QuXG4gICAgICAgICAqL1xuICAgICAgICByZWFkb25seSBkaXJSZWxhdGl2ZVRvSG9tZURpcjogc3RyaW5nLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFnZSAoaW4gbXMpIGFmdGVyIHdoaWNoIGEgY2FjaGVkIGVudHJ5IGlzIGludmFsaWQuIERlZmF1bHQ6XG4gICAgICAgICAqIGAyNCozNjAwKjEwMDBgICgxIGRheSkuXG4gICAgICAgICAqL1xuICAgICAgICByZWFkb25seSBleHBpcmF0aW9uOiBudW1iZXIgPSAyNCAqIDM2MDAgKiAxMDAwXG4gICAgKSB7XG4gICAgICAgIHRoaXMuZGlyID0gam9pbihob21lZGlyKCksIGRpclJlbGF0aXZlVG9Ib21lRGlyKTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXplZCA9IHRoaXMuaW5pdGlhbGl6ZSh0aGlzLmRpcik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBoYXNoKGtleTogc3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGhhc2hlciA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIik7XG4gICAgICAgIGhhc2hlci51cGRhdGUoa2V5KTtcbiAgICAgICAgcmV0dXJuIGhhc2hlci5kaWdlc3QoXCJoZXhcIik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0cmlldmVzIHRoZSB2YWx1ZSBwcmV2aW91c2x5IHNldCBmb3IgdGhlIGdpdmVuIGtleSwgb3IgdW5kZWZpbmVkIGlmIHRoZVxuICAgICAqIGtleSBpcyBub3QgZm91bmQuXG4gICAgICovXG4gICAgYXN5bmMgZ2V0KGtleTogc3RyaW5nKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdGlhbGl6ZWQ7XG4gICAgICAgIGNvbnN0IGVudHJ5ID0gam9pbih0aGlzLmRpciwgdGhpcy5oYXNoKGtleSkpO1xuICAgICAgICBjb25zdCBzdGF0RW50cnkgPSBhd2FpdCBzdGF0KGVudHJ5KS5jYXRjaChfID0+IHt9KTtcbiAgICAgICAgaWYgKHN0YXRFbnRyeSkge1xuICAgICAgICAgICAgaWYgKERhdGUubm93KCkgLSBzdGF0RW50cnkubXRpbWVNcyA+IHRoaXMuZXhwaXJhdGlvbikge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVhZEZpbGUoZW50cnkpLmNhdGNoKF8gPT4gdW5kZWZpbmVkKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgY2FjaGUga2V5IHRvIHRoZSBnaXZlbiB2YWx1ZS5cbiAgICAgKiBAcmV0dXJucyBhIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBjYWNoZSBlbnRyeSBoYXMgYmVlbiBwZXJzaXN0ZWQuXG4gICAgICovXG4gICAgYXN5bmMgc2V0KGtleTogc3RyaW5nLCB2YWx1ZTogQnVmZmVyIHwgc3RyaW5nIHwgVWludDhBcnJheSkge1xuICAgICAgICBhd2FpdCB0aGlzLmluaXRpYWxpemVkO1xuICAgICAgICBjb25zdCBlbnRyeSA9IGpvaW4odGhpcy5kaXIsIHRoaXMuaGFzaChrZXkpKTtcbiAgICAgICAgY29uc3QgdG1wRW50cnkgPSBqb2luKHRoaXMuZGlyLCB1dWlkdjQoKSk7XG4gICAgICAgIGF3YWl0IHdyaXRlRmlsZSh0bXBFbnRyeSwgdmFsdWUsIHsgbW9kZTogMG82MDAsIGVuY29kaW5nOiBcImJpbmFyeVwiIH0pO1xuICAgICAgICBhd2FpdCByZW5hbWUodG1wRW50cnksIGVudHJ5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZSBhbGwga2V5cyBzdG9yZWQgaW4gdGhlIGNhY2hlLCBpbmNsdWRpbmcgZXhwaXJlZCBlbnRyaWVzLlxuICAgICAqL1xuICAgIGVudHJpZXMoKSB7XG4gICAgICAgIHJldHVybiByZWFkZGlyKHRoaXMuZGlyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZWxldGVzIGFsbCBjYWNoZWQgZW50cmllcyBmcm9tIGRpc2suXG4gICAgICogQHBhcmFtIGxlYXZlRW1wdHlEaXIgLSBJZiB0cnVlLCBsZWF2ZSB0aGUgY2FjaGUgZGlyZWN0b3J5IGluIHBsYWNlIGFmdGVyXG4gICAgICogZGVsZXRpbmcgaXRzIGNvbnRlbnRzLiBJZiBmYWxzZSwgdGhlIGNhY2hlIGRpcmVjdG9yeSB3aWxsIGJlIHJlbW92ZWQuXG4gICAgICogRGVmYXVsdDogYHRydWVgLlxuICAgICAqL1xuICAgIGFzeW5jIGNsZWFyKHsgbGVhdmVFbXB0eURpciA9IHRydWUgfSA9IHt9KSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaW5pdGlhbGl6ZWQ7XG5cbiAgICAgICAgYXdhaXQgcmVtb3ZlKHRoaXMuZGlyKTtcblxuICAgICAgICBpZiAobGVhdmVFbXB0eURpcikge1xuICAgICAgICAgICAgYXdhaXQgbWtkaXJwKHRoaXMuZGlyKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuY29uc3QgZGF5cyA9IDI0ICogMzYwMCAqIDEwMDA7XG5cbmV4cG9ydCBjb25zdCBjYWNoZXMgPSB7XG4gICAgYXdzUHJpY2VzOiBuZXcgUGVyc2lzdGVudENhY2hlKFwiLmZhYXN0anMvYXdzL3ByaWNpbmdcIiwgMSAqIGRheXMpLFxuICAgIGF3c0djOiBuZXcgUGVyc2lzdGVudENhY2hlKFwiLmZhYXN0anMvYXdzL2djXCIsIDcgKiBkYXlzKVxufTtcbiJdfQ==