@fly/edge
Version:
Fly's TypeScript Edge
168 lines • 19.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.httpCache = void 0;
/**
* @module Middleware
*/
const cache_1 = require("@fly/v8env/lib/fly/cache");
/**
* Cache HTTP responses with `cache-control` headers.
*
* Basic example:
* ```typescript
* import httpCache from "./src/middleware/http-cache";
* import backends from "./src/backends";
*
* const glitch = backends.glitch("fly-example");
*
* const origin = httpCache(glitch, { overrideMaxAge: 3600 });
*
* fly.http.respondWith(origin);
* ```
*
* @param fetch
* @param options
*/
function httpCache(fetch, options) {
return async function httpCacheFetch(req, init) {
if (!options)
options = {};
if (typeof req === "string") {
req = new Request(req, init);
init = undefined;
}
// check the cache
let cacheable = true;
for (const h of ["Authorization", "Cookie"]) {
if (req.headers.get(h)) {
console.warn(h + " headers are not supported in http-cache");
cacheable = false;
}
}
let resp = cacheable ? await storage.match(req) : undefined;
if (resp) {
// got a hit
resp.headers.set("Fly-Cache", "hit");
return resp;
}
resp = await fetch(req, init);
// this should do nothing if the response can't be cached
const cacheHappened = cacheable ? await storage.put(req, resp, options.overrideMaxAge) : false;
if (cacheHappened) {
resp.headers.set("Fly-Cache", "miss");
}
return resp;
};
}
exports.httpCache = httpCache;
/**
* Configurable HTTP caching middleware. This is extremely useful within a `pipeline`:
*
* ```typescript
* const app = pipeline(
* httpsUpgrader,
* httpCaching.configure({overrideMaxAge: 3600}),
* glitch("fly-example")
* )
*
*/
httpCache.configure = (options) => {
return (fetch) => httpCache(fetch, options);
};
// copied from fly v8env
const CachePolicy = require("http-cache-semantics");
/**
* export:
* match(req): res | null
* add(req): void
* put(req, res): void
* @private
*/
const storage = {
async match(req) {
const hashed = hashData(req);
const key = "httpcache:policy:" + hashed; // first try with no vary variant
for (let i = 0; i < 5; i++) {
const policyRaw = await cache_1.default.getString(key);
console.debug("Got policy:", key, policyRaw);
if (!policyRaw) {
return undefined;
}
const policy = CachePolicy.fromObject(JSON.parse(policyRaw));
// if it fits i sits
if (policy.satisfiesWithoutRevalidation(req)) {
const headers = policy.responseHeaders();
const bodyKey = "httpcache:body:" + hashed;
const body = await cache_1.default.get(bodyKey);
console.debug("Got body", body.constructor.name, body.byteLength);
return new Response(body, { status: policy._status, headers });
// }else if(policy._headers){
// TODO: try a new vary based key
// policy._headers has the varies / vary values
// key = hashData(req, policy._headers)
// return undefined
}
else {
return undefined;
}
}
return undefined; // no matches found
},
async add(req) {
console.debug("cache add");
const res = await fetch(req);
return await storage.put(req, res);
},
async put(req, res, ttl) {
const resHeaders = {};
const key = hashData(req);
if (res.headers.get("vary")) {
console.warn("Vary headers are not supported in http-cache");
return false;
}
for (const [name, value] of res.headers) {
resHeaders[name] = value;
}
const cacheableRes = {
status: res.status,
headers: resHeaders
};
const policy = new CachePolicy({
url: req.url,
method: req.method,
headers: req.headers || {}
}, cacheableRes);
if (typeof ttl === "number") {
policy._rescc['max-age'] = ttl; // hack to make policy handle overridden ttl
console.warn("ttl:", ttl, "storable:", policy.storable());
}
ttl = typeof ttl === "number" ? ttl : Math.floor(policy.timeToLive() / 1000);
if (policy.storable() && ttl > 0) {
console.debug("Setting cache policy:", "httpcache:policy:" + key, ttl);
await cache_1.default.set("httpcache:policy:" + key, JSON.stringify(policy.toObject()), ttl);
const respBody = await res.arrayBuffer();
await cache_1.default.set("httpcache:body:" + key, respBody, ttl);
return true;
}
return false;
}
};
function hashData(req) {
let toHash = ``;
const u = normalizeURL(req.url);
toHash += u.toString();
toHash += req.method;
// TODO: cacheable cookies
// TODO: cache version for grand busting
console.debug("hashData", toHash);
return crypto.subtle.digestSync("sha-1", toHash, "hex");
}
function normalizeURL(u) {
const url = new URL(u);
url.hash = "";
const sp = url.searchParams;
sp.sort();
url.search = sp.toString();
return url;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9taWRkbGV3YXJlL2h0dHAtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUE7O0dBRUc7QUFDSCxvREFBNkM7QUFVN0M7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUJHO0FBQ0gsU0FBZ0IsU0FBUyxDQUFDLEtBQW9CLEVBQUUsT0FBMEI7SUFDeEUsT0FBTyxLQUFLLFVBQVUsY0FBYyxDQUFDLEdBQWdCLEVBQUUsSUFBa0I7UUFDdkUsSUFBRyxDQUFDLE9BQU87WUFBRSxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQzFCLElBQUcsT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFDO1lBQ3pCLEdBQUcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDN0IsSUFBSSxHQUFHLFNBQVMsQ0FBQztTQUNsQjtRQUVELGtCQUFrQjtRQUNsQixJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUM7UUFDckIsS0FBSSxNQUFNLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxRQUFRLENBQUMsRUFBQztZQUN6QyxJQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO2dCQUNwQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRywwQ0FBMEMsQ0FBQyxDQUFBO2dCQUM1RCxTQUFTLEdBQUcsS0FBSyxDQUFDO2FBQ25CO1NBQ0Y7UUFDRCxJQUFJLElBQUksR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRTVELElBQUcsSUFBSSxFQUFDO1lBQ04sWUFBWTtZQUNaLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNyQyxPQUFPLElBQUksQ0FBQztTQUNi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QTtJQUN0QixHQUFHLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQTtJQUNiLE1BQU0sRUFBRSxHQUFHLEdBQUcsQ0FBQyxZQUFZLENBQUE7SUFDM0IsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFBO0lBQ1QsR0FBRyxDQUFDLE1BQU0sR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUE7SUFFMUIsT0FBTyxHQUFHLENBQUE7QUFDWixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbW9kdWxlIE1pZGRsZXdhcmVcbiAqL1xuaW1wb3J0IGNhY2hlIGZyb20gXCJAZmx5L3Y4ZW52L2xpYi9mbHkvY2FjaGVcIjtcbmltcG9ydCB7IEZldGNoRnVuY3Rpb24gfSBmcm9tIFwiLi4vZmV0Y2hcIjtcblxuLyoqXG4gKiBIVFRQIGNhY2hpbmcgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIVFRQQ2FjaGVPcHRpb25ze1xuICAvKiogT3ZlcnJpZGVzIHRoZSBjYWNoZSBUVEwgZm9yIGFsbCBjYWNoZWFibGUgcmVxdWVzdHMgKi9cbiAgb3ZlcnJpZGVNYXhBZ2U/OiBudW1iZXJcbn1cbi8qKlxuICogQ2FjaGUgSFRUUCByZXNwb25zZXMgd2l0aCBgY2FjaGUtY29udHJvbGAgaGVhZGVycy5cbiAqIFxuICogQmFzaWMgZXhhbXBsZTpcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCBodHRwQ2FjaGUgZnJvbSBcIi4vc3JjL21pZGRsZXdhcmUvaHR0cC1jYWNoZVwiO1xuICogaW1wb3J0IGJhY2tlbmRzIGZyb20gXCIuL3NyYy9iYWNrZW5kc1wiO1xuICogXG4gKiBjb25zdCBnbGl0Y2ggPSBiYWNrZW5kcy5nbGl0Y2goXCJmbHktZXhhbXBsZVwiKTtcbiAqIFxuICogY29uc3Qgb3JpZ2luID0gaHR0cENhY2hlKGdsaXRjaCwgeyBvdmVycmlkZU1heEFnZTogMzYwMCB9KTtcbiAqIFxuICogZmx5Lmh0dHAucmVzcG9uZFdpdGgob3JpZ2luKTtcbiAqIGBgYFxuICogXG4gKiBAcGFyYW0gZmV0Y2ggXG4gKiBAcGFyYW0gb3B0aW9ucyBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGh0dHBDYWNoZShmZXRjaDogRmV0Y2hGdW5jdGlvbiwgb3B0aW9ucz86IEhUVFBDYWNoZU9wdGlvbnMpOiBGZXRjaEZ1bmN0aW9ue1xuICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gaHR0cENhY2hlRmV0Y2gocmVxOiBSZXF1ZXN0SW5mbywgaW5pdD86IFJlcXVlc3RJbml0KTogUHJvbWlzZTxSZXNwb25zZT57XG4gICAgaWYoIW9wdGlvbnMpIG9wdGlvbnMgPSB7fTtcbiAgICBpZih0eXBlb2YgcmVxID09PSBcInN0cmluZ1wiKXtcbiAgICAgIHJlcSA9IG5ldyBSZXF1ZXN0KHJlcSwgaW5pdCk7XG4gICAgICBpbml0ID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIHRoZSBjYWNoZVxuICAgIGxldCBjYWNoZWFibGUgPSB0cnVlO1xuICAgIGZvcihjb25zdCBoIG9mIFtcIkF1dGhvcml6YXRpb25cIiwgXCJDb29raWVcIl0pe1xuICAgICAgaWYocmVxLmhlYWRlcnMuZ2V0KGgpKXtcbiAgICAgICAgY29uc29sZS53YXJuKGggKyBcIiBoZWFkZXJzIGFyZSBub3Qgc3VwcG9ydGVkIGluIGh0dHAtY2FjaGVcIilcbiAgICAgICAgY2FjaGVhYmxlID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIGxldCByZXNwID0gY2FjaGVhYmxlID8gYXdhaXQgc3RvcmFnZS5tYXRjaChyZXEpIDogdW5kZWZpbmVkO1xuXG4gICAgaWYocmVzcCl7XG4gICAgICAvLyBnb3QgYSBoaXRcbiAgICAgIHJlc3AuaGVhZGVycy5zZXQoXCJGbHktQ2FjaGVcIiwgXCJoaXRcIik7XG4gICAgICByZXR1cm4gcmVzcDtcbiAgICB9XG5cbiAgICByZXNwID0gYXdhaXQgZmV0Y2gocmVxLCBpbml0KTtcblxuICAgIC8vIHRoaXMgc2hvdWxkIGRvIG5vdGhpbmcgaWYgdGhlIHJlc3BvbnNlIGNhbid0IGJlIGNhY2hlZFxuICAgIGNvbnN0IGNhY2hlSGFwcGVuZWQgPSBjYWNoZWFibGUgPyBhd2FpdCBzdG9yYWdlLnB1dChyZXEsIHJlc3AsIG9wdGlvbnMub3ZlcnJpZGVNYXhBZ2UpIDogZmFsc2U7XG5cbiAgICBpZihjYWNoZUhhcHBlbmVkKXtcbiAgICAgIHJlc3AuaGVhZGVycy5zZXQoXCJGbHktQ2FjaGVcIiwgXCJtaXNzXCIpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzcDtcbiAgfVxufVxuXG4vKipcbiAqIENvbmZpZ3VyYWJsZSBIVFRQIGNhY2hpbmcgbWlkZGxld2FyZS4gVGhpcyBpcyBleHRyZW1lbHkgdXNlZnVsIHdpdGhpbiBhIGBwaXBlbGluZWA6XG4gKiBcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGFwcCA9IHBpcGVsaW5lKFxuICogICAgIGh0dHBzVXBncmFkZXIsXG4gKiAgICAgaHR0cENhY2hpbmcuY29uZmlndXJlKHtvdmVycmlkZU1heEFnZTogMzYwMH0pLFxuICogICAgIGdsaXRjaChcImZseS1leGFtcGxlXCIpXG4gKiApXG4gKiBcbiAqL1xuaHR0cENhY2hlLmNvbmZpZ3VyZSA9IChvcHRpb25zPzogSFRUUENhY2hlT3B0aW9ucykgPT4ge1xuICByZXR1cm4gKGZldGNoOiBGZXRjaEZ1bmN0aW9uKSA9PiBodHRwQ2FjaGUoZmV0Y2gsIG9wdGlvbnMpXG59XG5cbi8vIGNvcGllZCBmcm9tIGZseSB2OGVudlxuY29uc3QgQ2FjaGVQb2xpY3kgPSByZXF1aXJlKFwiaHR0cC1jYWNoZS1zZW1hbnRpY3NcIik7XG4vKipcbiAqIGV4cG9ydDpcbiAqIFx0bWF0Y2gocmVxKTogcmVzIHwgbnVsbFxuICogXHRhZGQocmVxKTogdm9pZFxuICogXHRwdXQocmVxLCByZXMpOiB2b2lkXG4gKiBAcHJpdmF0ZVxuICovXG5cbmNvbnN0IHN0b3JhZ2UgPSB7XG4gIGFzeW5jIG1hdGNoKHJlcTogUmVxdWVzdCkge1xuICAgIGNvbnN0IGhhc2hlZCA9IGhhc2hEYXRhKHJlcSlcbiAgICBjb25zdCBrZXkgPSBcImh0dHBjYWNoZTpwb2xpY3k6XCIgKyBoYXNoZWQgLy8gZmlyc3QgdHJ5IHdpdGggbm8gdmFyeSB2YXJpYW50XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCA1OyBpKyspIHtcbiAgICAgIGNvbnN0IHBvbGljeVJhdyA9IGF3YWl0IGNhY2hlLmdldFN0cmluZyhrZXkpXG4gICAgICBjb25zb2xlLmRlYnVnKFwiR290IHBvbGljeTpcIiwga2V5LCBwb2xpY3lSYXcpXG4gICAgICBpZiAoIXBvbGljeVJhdykge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICB9XG4gICAgICBjb25zdCBwb2xpY3kgPSBDYWNoZVBvbGljeS5mcm9tT2JqZWN0KEpTT04ucGFyc2UocG9saWN5UmF3KSlcblxuICAgICAgLy8gaWYgaXQgZml0cyBpIHNpdHNcbiAgICAgIGlmIChwb2xpY3kuc2F0aXNmaWVzV2l0aG91dFJldmFsaWRhdGlvbihyZXEpKSB7XG4gICAgICAgIGNvbnN0IGhlYWRlcnMgPSBwb2xpY3kucmVzcG9uc2VIZWFkZXJzKClcbiAgICAgICAgY29uc3QgYm9keUtleSA9IFwiaHR0cGNhY2hlOmJvZHk6XCIgKyBoYXNoZWRcblxuICAgICAgICBjb25zdCBib2R5ID0gYXdhaXQgY2FjaGUuZ2V0KGJvZHlLZXkpXG4gICAgICAgIGNvbnNvbGUuZGVidWcoXCJHb3QgYm9keVwiLCBib2R5LmNvbnN0cnVjdG9yLm5hbWUsIGJvZHkuYnl0ZUxlbmd0aClcbiAgICAgICAgcmV0dXJuIG5ldyBSZXNwb25zZShib2R5LCB7IHN0YXR1czogcG9saWN5Ll9zdGF0dXMsIGhlYWRlcnMgfSlcbiAgICAgICAgLy8gfWVsc2UgaWYocG9saWN5Ll9oZWFkZXJzKXtcbiAgICAgICAgLy8gVE9ETzogdHJ5IGEgbmV3IHZhcnkgYmFzZWQga2V5XG4gICAgICAgIC8vIHBvbGljeS5faGVhZGVycyBoYXMgdGhlIHZhcmllcyAvIHZhcnkgdmFsdWVzXG4gICAgICAgIC8vIGtleSA9IGhhc2hEYXRhKHJlcSwgcG9saWN5Ll9oZWFkZXJzKVxuICAgICAgICAvLyByZXR1cm4gdW5kZWZpbmVkXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQgLy8gbm8gbWF0Y2hlcyBmb3VuZFxuICB9LFxuICBhc3luYyBhZGQocmVxOiBSZXF1ZXN0KSB7XG4gICAgY29uc29sZS5kZWJ1ZyhcImNhY2hlIGFkZFwiKVxuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2gocmVxKVxuICAgIHJldHVybiBhd2FpdCBzdG9yYWdlLnB1dChyZXEsIHJlcylcbiAgfSxcbiAgYXN5bmMgcHV0KHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgdHRsPzogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgcmVzSGVhZGVyczogYW55ID0ge31cbiAgICBjb25zdCBrZXkgPSBoYXNoRGF0YShyZXEpXG5cbiAgICBpZihyZXMuaGVhZGVycy5nZXQoXCJ2YXJ5XCIpKXtcbiAgICAgIGNvbnNvbGUud2FybihcIlZhcnkgaGVhZGVycyBhcmUgbm90IHN1cHBvcnRlZCBpbiBodHRwLWNhY2hlXCIpXG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIChyZXMgYXMgYW55KS5oZWFkZXJzKSB7XG4gICAgICByZXNIZWFkZXJzW25hbWVdID0gdmFsdWVcbiAgICB9XG4gICAgY29uc3QgY2FjaGVhYmxlUmVzID0ge1xuICAgICAgc3RhdHVzOiByZXMuc3RhdHVzLFxuICAgICAgaGVhZGVyczogcmVzSGVhZGVyc1xuICAgIH1cbiAgICBjb25zdCBwb2xpY3kgPSBuZXcgQ2FjaGVQb2xpY3koXG4gICAgICB7XG4gICAgICAgIHVybDogcmVxLnVybCxcbiAgICAgICAgbWV0aG9kOiByZXEubWV0aG9kLFxuICAgICAgICBoZWFkZXJzOiByZXEuaGVhZGVycyB8fCB7fVxuICAgICAgfSxcbiAgICAgIGNhY2hlYWJsZVJlc1xuICAgIClcblxuICAgIGlmKHR5cGVvZiB0dGwgPT09IFwibnVtYmVyXCIpe1xuICAgICAgcG9saWN5Ll9yZXNjY1snbWF4LWFnZSddID0gdHRsOyAvLyBoYWNrIHRvIG1ha2UgcG9saWN5IGhhbmRsZSBvdmVycmlkZGVuIHR0bFxuICAgICAgY29uc29sZS53YXJuKFwidHRsOlwiLCB0dGwsIFwic3RvcmFibGU6XCIsIHBvbGljeS5zdG9yYWJsZSgpKTtcbiAgICB9XG5cbiAgICB0dGwgPSB0eXBlb2YgdHRsID09PSBcIm51bWJlclwiID8gdHRsIDogTWF0aC5mbG9vcihwb2xpY3kudGltZVRvTGl2ZSgpIC8gMTAwMCk7XG4gICAgaWYgKHBvbGljeS5zdG9yYWJsZSgpICYmIHR0bCA+IDApIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoXCJTZXR0aW5nIGNhY2hlIHBvbGljeTpcIiwgXCJodHRwY2FjaGU6cG9saWN5OlwiICsga2V5LCB0dGwpXG4gICAgICBhd2FpdCBjYWNoZS5zZXQoXCJodHRwY2FjaGU6cG9saWN5OlwiICsga2V5LCBKU09OLnN0cmluZ2lmeShwb2xpY3kudG9PYmplY3QoKSksIHR0bClcbiAgICAgIGNvbnN0IHJlc3BCb2R5ID0gYXdhaXQgcmVzLmFycmF5QnVmZmVyKClcbiAgICAgIGF3YWl0IGNhY2hlLnNldChcImh0dHBjYWNoZTpib2R5OlwiICsga2V5LCByZXNwQm9keSwgdHRsKVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG5mdW5jdGlvbiBoYXNoRGF0YShyZXE6IFJlcXVlc3QpIHtcbiAgbGV0IHRvSGFzaCA9IGBgXG5cbiAgY29uc3QgdSA9IG5vcm1hbGl6ZVVSTChyZXEudXJsKVxuXG4gIHRvSGFzaCArPSB1LnRvU3RyaW5nKClcbiAgdG9IYXNoICs9IHJlcS5tZXRob2RcblxuICAvLyBUT0RPOiBjYWNoZWFibGUgY29va2llc1xuICAvLyBUT0RPOiBjYWNoZSB2ZXJzaW9uIGZvciBncmFuZCBidXN0aW5nXG5cbiAgY29uc29sZS5kZWJ1ZyhcImhhc2hEYXRhXCIsIHRvSGFzaClcbiAgcmV0dXJuIChjcnlwdG8gYXMgYW55KS5zdWJ0bGUuZGlnZXN0U3luYyhcInNoYS0xXCIsIHRvSGFzaCwgXCJoZXhcIilcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplVVJMKHU6c3RyaW5nKSB7XG4gIGNvbnN0IHVybCA9IG5ldyBVUkwodSlcbiAgdXJsLmhhc2ggPSBcIlwiXG4gIGNvbnN0IHNwID0gdXJsLnNlYXJjaFBhcmFtc1xuICBzcC5zb3J0KClcbiAgdXJsLnNlYXJjaCA9IHNwLnRvU3RyaW5nKClcblxuICByZXR1cm4gdXJsXG59XG4iXX0=