@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
329 lines • 29.6 kB
JavaScript
import { __awaiter } from "tslib";
/**
* GLTF specs can be found here:
* https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
*/
import { TgdDataset } from "./../../dataset/index.js";
import { parseGLB } from "./parser.js";
import { assertTgdTypeArrayForElements, } from "./../../types/index.js";
import { TgdGeometry } from "./../../geometry/index.js";
import { TgdTexture2D } from "./../../texture/index.js";
export class TgdParserGLTransfertFormatBinary {
constructor(content) {
this.cacheImages = new Map();
this.cacheImageURLs = new Map();
this.cacheBufferViewDatas = new Map();
try {
const data = parseGLB(content);
this.gltf = data.gltf;
this.chunks = data.chunks;
}
catch (error) {
const message = error instanceof Error ? error.message : JSON.stringify(error);
throw new Error(`[TgdParserGLTransfertFormatBinary] ${message}`);
}
}
get fileSize() {
return (12 + this.chunks.reduce((size, chunk) => size + chunk.byteLength, 0));
}
getScenes() {
var _a;
return (_a = this.gltf.scenes) !== null && _a !== void 0 ? _a : [];
}
getScene(sceneIndex) {
var _a;
const scene = (_a = this.gltf.scenes) === null || _a === void 0 ? void 0 : _a[sceneIndex];
if (!scene) {
throw new Error(`Asset has no scene with index #${sceneIndex}!`);
}
return scene;
}
getNode(nodeIndex) {
var _a;
const node = (_a = this.gltf.nodes) === null || _a === void 0 ? void 0 : _a[nodeIndex];
if (!node) {
throw new Error(`Asset has no node with index #${nodeIndex}!`);
}
return node;
}
getNodeByName(nodeName) {
const nodes = this.gltf.nodes;
if (!nodes)
return;
for (const node of nodes) {
if (node.name === nodeName)
return node;
}
}
getNodeByNameOrThrow(nodeName) {
var _a;
const node = this.getNodeByName(nodeName);
if (node)
return node;
throw new Error(`Unknown node "${nodeName}"!\nAvailable names:${((_a = this.gltf.nodes) !== null && _a !== void 0 ? _a : [])
.map((node, index) => `\n - ${typeof node.name === "string"
? JSON.stringify(node.name)
: `#${index}`}`)
.join("")}`);
}
getAccessor(accessorIndex = 0) {
var _a;
const accessor = (_a = this.gltf.accessors) === null || _a === void 0 ? void 0 : _a[accessorIndex];
if (!accessor) {
throw new Error(`Asset has no accessor with index #${accessorIndex}!`);
}
return accessor;
}
getMaterial(materialIndex) {
var _a;
const material = (_a = this.gltf.materials) === null || _a === void 0 ? void 0 : _a[materialIndex];
if (!material) {
throw new Error(`Asset has no material with index #${materialIndex}!`);
}
return material;
}
getMesh(meshIndex = 0) {
var _a;
const mesh = (_a = this.gltf.meshes) === null || _a === void 0 ? void 0 : _a[meshIndex];
if (!mesh) {
throw new Error(`Asset has no mesh with index #${meshIndex}!`);
}
return mesh;
}
getMeshPrimitive(meshIndex = 0, primitiveIndex = 0) {
const mesh = this.getMesh(meshIndex);
const primitive = mesh.primitives[primitiveIndex];
if (!primitive) {
throw new Error(`Asset has no primitive #${primitiveIndex} in mesh #${meshIndex}!`);
}
return primitive;
}
getMeshPrimitiveIndices(meshIndex = 0, primitiveIndex = 0) {
var _a, _b;
const primitive = this.getMeshPrimitive(meshIndex, primitiveIndex);
const accessor = this.getAccessor((_a = primitive.indices) !== null && _a !== void 0 ? _a : 0);
const elements = this.getBufferViewData((_b = accessor.bufferView) !== null && _b !== void 0 ? _b : 0, accessor.componentType);
assertTgdTypeArrayForElements(elements);
return elements;
}
getAccessorByAttributeName(primitive, attribName) {
const { attributes } = primitive;
if (!attributes || Object.keys(attributes).length === 0)
throw new Error("No attributes found!");
const accessorIndex = attributes[attribName];
if (typeof accessorIndex !== "number") {
throw new TypeError(`No attribute with name "${attribName}"!\nAvailable names are: ${Object.keys(attributes)
.map(name => JSON.stringify(name))
.join(", ")}.`);
}
try {
return this.getAccessor(accessorIndex);
}
catch (error) {
const message = error instanceof Error ? error.message : JSON.stringify(error);
throw new Error(`Attribute "${attribName}" pointed to an inexisting accessor!\n${message}`);
}
}
createTexture2D(context, textureIndex) {
var _a, _b, _c, _d, _e;
const gltfTex = (_a = this.gltf.textures) === null || _a === void 0 ? void 0 : _a[textureIndex];
if (!gltfTex) {
throw new Error(`Asset has no texture with index #${textureIndex}!`);
}
const source = (_e = (_b = gltfTex.source) !== null && _b !== void 0 ? _b : (_d = (_c = gltfTex.extensions) === null || _c === void 0 ? void 0 : _c.EXT_texture_webp) === null || _d === void 0 ? void 0 : _d.source) !== null && _e !== void 0 ? _e : 0;
const url = this.getImageURL(source);
const texture = new TgdTexture2D(context);
if (url) {
loadImage(url)
.then(bmp => {
if (bmp)
texture.loadBitmap(bmp);
else
console.error("Unable to load this file:", url);
})
.catch(console.error);
}
else {
console.error(`[GLTF] texture index #${textureIndex} is empty!`);
}
return texture;
}
loadImage(imageIndex) {
return __awaiter(this, void 0, void 0, function* () {
const fromCache = this.cacheImages.get(imageIndex);
if (fromCache)
return fromCache;
const url = this.getImageURL(imageIndex);
if (!url)
return;
const promise = new Promise((resolve, reject) => {
const img = new Image();
img.src = url;
img.addEventListener("load", () => {
resolve(img);
});
img.addEventListener("error", () => {
var _a;
console.error(`Unable to load image #${imageIndex}!`, (_a = this.gltf.images) === null || _a === void 0 ? void 0 : _a[imageIndex]);
reject();
});
});
this.cacheImages.set(imageIndex, promise);
return promise;
});
}
getImageURL(imageIndex) {
var _a;
const fromCache = this.cacheImageURLs.get(imageIndex);
if (fromCache)
return fromCache;
const { gltf } = this;
const image = (_a = gltf.images) === null || _a === void 0 ? void 0 : _a[imageIndex];
if (!image)
return;
if (image.uri)
return image.uri;
if (typeof image.bufferView !== "number")
return;
const buffer = this.getBufferViewData(image.bufferView, "Uint8");
if (!buffer)
return;
const blob = new Blob([buffer], {
type: image.mimeType,
});
const url = URL.createObjectURL(blob);
this.cacheImageURLs.set(imageIndex, url);
return url;
}
getBufferViewData(accessor, type = "Float32") {
var _a, _b, _c, _d, _e;
if (typeof accessor !== "number") {
return this.getBufferViewData((_a = accessor.bufferView) !== null && _a !== void 0 ? _a : 0, accessor.componentType);
}
const bufferViewIndex = accessor;
const fromCache = this.cacheBufferViewDatas.get(bufferViewIndex);
if (fromCache)
return fromCache;
const { gltf } = this;
const bufferView = (_b = gltf.bufferViews) === null || _b === void 0 ? void 0 : _b[bufferViewIndex];
if (!bufferView)
throw new Error(`No bufferView with index #${bufferViewIndex}!`);
const buffer = this.chunks[bufferView.buffer];
const byteOffset = (_c = bufferView.byteOffset) !== null && _c !== void 0 ? _c : 0;
const data = buffer.slice(byteOffset, byteOffset + bufferView.byteLength);
const view = figureOutView(data, convertTypeToNumber((_e = type !== null && type !== void 0 ? type : (_d = this.findAccessorForBufferView(bufferViewIndex)) === null || _d === void 0 ? void 0 : _d.componentType) !== null && _e !== void 0 ? _e : "Float32"));
this.cacheBufferViewDatas.set(bufferViewIndex, view);
return view;
}
findAccessorForBufferView(bufferViewIndex) {
var _a;
return ((_a = this.gltf.accessors) !== null && _a !== void 0 ? _a : []).find(accessor => accessor.bufferView === bufferViewIndex);
}
setAttrib(dataset, attribName, meshIndex = 0, primitiveIndex = 0, primitiveAttribName) {
var _a, _b, _c, _d, _e;
const { gltf } = this;
const accessorIndex = (_b = (_a = gltf.meshes) === null || _a === void 0 ? void 0 : _a[meshIndex].primitives[primitiveIndex].attributes[primitiveAttribName !== null && primitiveAttribName !== void 0 ? primitiveAttribName : attribName]) !== null && _b !== void 0 ? _b : -1;
const accessor = (_c = gltf.accessors) === null || _c === void 0 ? void 0 : _c[accessorIndex];
if (!accessor) {
throw new Error(`No attribute "${primitiveAttribName !== null && primitiveAttribName !== void 0 ? primitiveAttribName : attribName}" for primitive #${primitiveIndex} of mesh #${meshIndex}!`);
}
const bufferViewIndex = (_d = accessor.bufferView) !== null && _d !== void 0 ? _d : 0;
const bufferView = (_e = gltf.bufferViews) === null || _e === void 0 ? void 0 : _e[bufferViewIndex];
if (!bufferView) {
throw new Error(`No bufferView with index #${bufferViewIndex}!`);
}
const view = this.getBufferViewData(bufferViewIndex, accessor.componentType);
dataset.set(attribName, view, {
byteStride: bufferView.byteStride,
byteOffset: accessor.byteOffset,
count: accessor.count,
});
}
makeGeometry({ computeNormals, meshIndex = 0, primitiveIndex = 0, attPositionName = "POSITION", attNormalName = "NORMAL", attTextureCoordsName = "TEXCOORD_0", } = {}) {
const primitive = this.getMeshPrimitive(meshIndex, primitiveIndex);
try {
const { attributes } = primitive;
if (!attributes)
throw new Error("No attributes found!");
const elements = this.getMeshPrimitiveIndices(meshIndex, primitiveIndex);
const definition = {
[attPositionName]: "vec3",
};
if (typeof attributes[attNormalName] === "string") {
definition[attNormalName] = "vec3";
}
if (typeof attributes[attTextureCoordsName] === "string") {
definition[attTextureCoordsName] = "vec2";
}
const dataset = new TgdDataset(definition);
dataset.set(attPositionName, returnFloat32Array(this.getBufferViewData(this.getAccessorByAttributeName(primitive, attPositionName))));
if (typeof attributes[attNormalName] === "string") {
dataset.set(attNormalName, returnFloat32Array(this.getBufferViewData(this.getAccessorByAttributeName(primitive, attNormalName))));
}
if (typeof attributes[attTextureCoordsName] === "string") {
dataset.set(attTextureCoordsName, returnFloat32Array(this.getBufferViewData(this.getAccessorByAttributeName(primitive, attTextureCoordsName))));
}
return new TgdGeometry({
computeNormalsIfMissing: computeNormals,
dataset,
elements,
attPosition: attPositionName,
attNormal: attNormalName,
attUV: attTextureCoordsName,
});
}
catch (error) {
const message = error instanceof Error ? error.message : JSON.stringify(error);
throw new Error(`Error in primitive #${primitiveIndex} of mesh #${meshIndex}:\n${message}`);
}
}
}
function figureOutView(data, componentType) {
switch (componentType) {
case 5120:
return new Int8Array(data);
case 5121:
return new Uint8Array(data);
case 5122:
return new Int16Array(data);
case 5123:
return new Uint16Array(data);
case 5125:
return new Uint32Array(data);
default:
return new Float32Array(data);
}
}
function convertTypeToNumber(type) {
if (typeof type === "number")
return type;
switch (type) {
case "Int8":
return 5120;
case "Uint8":
return 5121;
case "Int16":
return 5122;
case "Uint16":
return 5123;
case "Uint32":
return 5125;
default:
return WebGL2RenderingContext.FLOAT;
}
throw new Error("Function not implemented.");
}
function returnFloat32Array(data) {
if (data instanceof Float32Array)
return data;
throw new Error("We were expecting a Float32Array!");
}
function loadImage(url) {
return new Promise(resolve => {
const img = new Image();
img.src = url;
img.addEventListener("load", () => resolve(img));
img.addEventListener("error", () => resolve(null));
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2x0Zi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wYXJzZXIvZ2x0Zi9nbHRmLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O0dBR0c7QUFDSCxPQUFPLEVBQUUsVUFBVSxFQUF3QixNQUFNLGNBQWMsQ0FBQTtBQUMvRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBVW5DLE9BQU8sRUFDSCw2QkFBNkIsR0FFaEMsTUFBTSxZQUFZLENBQUE7QUFDbkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBRTNDLE1BQU0sT0FBTyxnQ0FBZ0M7SUFtQnpDLFlBQVksT0FBb0I7UUFmZixnQkFBVyxHQUFHLElBQUksR0FBRyxFQUduQyxDQUFBO1FBQ2MsbUJBQWMsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQTtRQUMxQyx5QkFBb0IsR0FBRyxJQUFJLEdBQUcsRUFRNUMsQ0FBQTtRQUdDLElBQUksQ0FBQztZQUNELE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQTtZQUM5QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUE7WUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFBO1FBQzdCLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2IsTUFBTSxPQUFPLEdBQ1QsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQTtZQUNsRSxNQUFNLElBQUksS0FBSyxDQUFDLHNDQUFzQyxPQUFPLEVBQUUsQ0FBQyxDQUFBO1FBQ3BFLENBQUM7SUFDTCxDQUFDO0lBRUQsSUFBSSxRQUFRO1FBQ1IsT0FBTyxDQUNILEVBQUUsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUN2RSxDQUFBO0lBQ0wsQ0FBQztJQUVELFNBQVM7O1FBQ0wsT0FBTyxNQUFBLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxtQ0FBSSxFQUFFLENBQUE7SUFDakMsQ0FBQztJQUVELFFBQVEsQ0FBQyxVQUFrQjs7UUFDdkIsTUFBTSxLQUFLLEdBQUcsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sMENBQUcsVUFBVSxDQUFDLENBQUE7UUFDNUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1QsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQ0FBa0MsVUFBVSxHQUFHLENBQUMsQ0FBQTtRQUNwRSxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUE7SUFDaEIsQ0FBQztJQUVELE9BQU8sQ0FBQyxTQUFpQjs7UUFDckIsTUFBTSxJQUFJLEdBQUcsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssMENBQUcsU0FBUyxDQUFDLENBQUE7UUFDekMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsU0FBUyxHQUFHLENBQUMsQ0FBQTtRQUNsRSxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUE7SUFDZixDQUFDO0lBRUQsYUFBYSxDQUFDLFFBQWdCO1FBQzFCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFBO1FBQzdCLElBQUksQ0FBQyxLQUFLO1lBQUUsT0FBTTtRQUVsQixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3ZCLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxRQUFRO2dCQUFFLE9BQU8sSUFBSSxDQUFBO1FBQzNDLENBQUM7SUFDTCxDQUFDO0lBRUQsb0JBQW9CLENBQUMsUUFBZ0I7O1FBQ2pDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDekMsSUFBSSxJQUFJO1lBQUUsT0FBTyxJQUFJLENBQUE7UUFFckIsTUFBTSxJQUFJLEtBQUssQ0FDWCxpQkFBaUIsUUFBUSx1QkFBdUIsQ0FDNUMsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssbUNBQUksRUFBRSxDQUN4QjthQUNJLEdBQUcsQ0FDQSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUNaLFNBQ0ksT0FBTyxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVE7WUFDekIsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztZQUMzQixDQUFDLENBQUMsSUFBSSxLQUFLLEVBQ25CLEVBQUUsQ0FDVDthQUNBLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUNsQixDQUFBO0lBQ0wsQ0FBQztJQUVELFdBQVcsQ0FBQyxhQUFhLEdBQUcsQ0FBQzs7UUFDekIsTUFBTSxRQUFRLEdBQUcsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsMENBQUcsYUFBYSxDQUFDLENBQUE7UUFDckQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FDWCxxQ0FBcUMsYUFBYSxHQUFHLENBQ3hELENBQUE7UUFDTCxDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUE7SUFDbkIsQ0FBQztJQUVELFdBQVcsQ0FBQyxhQUFxQjs7UUFDN0IsTUFBTSxRQUFRLEdBQUcsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsMENBQUcsYUFBYSxDQUFDLENBQUE7UUFDckQsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FDWCxxQ0FBcUMsYUFBYSxHQUFHLENBQ3hELENBQUE7UUFDTCxDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUE7SUFDbkIsQ0FBQztJQUVELE9BQU8sQ0FBQyxTQUFTLEdBQUcsQ0FBQzs7UUFDakIsTUFBTSxJQUFJLEdBQUcsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sMENBQUcsU0FBUyxDQUFDLENBQUE7UUFDMUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsU0FBUyxHQUFHLENBQUMsQ0FBQTtRQUNsRSxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUE7SUFDZixDQUFDO0lBRUQsZ0JBQWdCLENBQ1osU0FBUyxHQUFHLENBQUMsRUFDYixjQUFjLEdBQUcsQ0FBQztRQU9sQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQ3BDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLENBQUE7UUFDakQsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FDWCwyQkFBMkIsY0FBYyxhQUFhLFNBQVMsR0FBRyxDQUNyRSxDQUFBO1FBQ0wsQ0FBQztRQUVELE9BQU8sU0FBUyxDQUFBO0lBQ3BCLENBQUM7SUFFRCx1QkFBdUIsQ0FDbkIsU0FBUyxHQUFHLENBQUMsRUFDYixjQUFjLEdBQUcsQ0FBQzs7UUFFbEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQTtRQUNsRSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQUEsU0FBUyxDQUFDLE9BQU8sbUNBQUksQ0FBQyxDQUFDLENBQUE7UUFDekQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUNuQyxNQUFBLFFBQVEsQ0FBQyxVQUFVLG1DQUFJLENBQUMsRUFDeEIsUUFBUSxDQUFDLGFBQWEsQ0FDekIsQ0FBQTtRQUNELDZCQUE2QixDQUFDLFFBQVEsQ0FBQyxDQUFBO1FBQ3ZDLE9BQU8sUUFBUSxDQUFBO0lBQ25CLENBQUM7SUFFRCwwQkFBMEIsQ0FDdEIsU0FBcUMsRUFDckMsVUFBa0I7UUFFbEIsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLFNBQVMsQ0FBQTtRQUNoQyxJQUFJLENBQUMsVUFBVSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDbkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFBO1FBQzNDLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUM1QyxJQUFJLE9BQU8sYUFBYSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxTQUFTLENBQ2YsMkJBQTJCLFVBQVUsNEJBQTRCLE1BQU0sQ0FBQyxJQUFJLENBQ3hFLFVBQVUsQ0FDYjtpQkFDSSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUNqQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FDckIsQ0FBQTtRQUNMLENBQUM7UUFDRCxJQUFJLENBQUM7WUFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUE7UUFDMUMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDYixNQUFNLE9BQU8sR0FDVCxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ2xFLE1BQU0sSUFBSSxLQUFLLENBQ1gsY0FBYyxVQUFVLHlDQUF5QyxPQUFPLEVBQUUsQ0FDN0UsQ0FBQTtRQUNMLENBQUM7SUFDTCxDQUFDO0lBRUQsZUFBZSxDQUNYLE9BQXVDLEVBQ3ZDLFlBQW9COztRQUVwQixNQUFNLE9BQU8sR0FBRyxNQUFBLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSwwQ0FBRyxZQUFZLENBQUMsQ0FBQTtRQUNsRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLG9DQUFvQyxZQUFZLEdBQUcsQ0FBQyxDQUFBO1FBQ3hFLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FDUixNQUFBLE1BQUEsT0FBTyxDQUFDLE1BQU0sbUNBQUksTUFBQSxNQUFBLE9BQU8sQ0FBQyxVQUFVLDBDQUFFLGdCQUFnQiwwQ0FBRSxNQUFNLG1DQUFJLENBQUMsQ0FBQTtRQUN2RSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQ3BDLE1BQU0sT0FBTyxHQUFHLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3pDLElBQUksR0FBRyxFQUFFLENBQUM7WUFDTixTQUFTLENBQUMsR0FBRyxDQUFDO2lCQUNULElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDUixJQUFJLEdBQUc7b0JBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQTs7b0JBQzNCLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsR0FBRyxDQUFDLENBQUE7WUFDeEQsQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7UUFDN0IsQ0FBQzthQUFNLENBQUM7WUFDSixPQUFPLENBQUMsS0FBSyxDQUFDLHlCQUF5QixZQUFZLFlBQVksQ0FBQyxDQUFBO1FBQ3BFLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQTtJQUNsQixDQUFDO0lBRUssU0FBUyxDQUFDLFVBQWtCOztZQUM5QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUNsRCxJQUFJLFNBQVM7Z0JBQUUsT0FBTyxTQUFTLENBQUE7WUFFL0IsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUN4QyxJQUFJLENBQUMsR0FBRztnQkFBRSxPQUFNO1lBRWhCLE1BQU0sT0FBTyxHQUFHLElBQUksT0FBTyxDQUN2QixDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtnQkFDaEIsTUFBTSxHQUFHLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQTtnQkFDdkIsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUE7Z0JBQ2IsR0FBRyxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUU7b0JBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQTtnQkFDaEIsQ0FBQyxDQUFDLENBQUE7Z0JBQ0YsR0FBRyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUU7O29CQUMvQixPQUFPLENBQUMsS0FBSyxDQUNULHlCQUF5QixVQUFVLEdBQUcsRUFDdEMsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sMENBQUcsVUFBVSxDQUFDLENBQ2pDLENBQUE7b0JBQ0QsTUFBTSxFQUFFLENBQUE7Z0JBQ1osQ0FBQyxDQUFDLENBQUE7WUFDTixDQUFDLENBQ0osQ0FBQTtZQUNELElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQTtZQUN6QyxPQUFPLE9BQU8sQ0FBQTtRQUNsQixDQUFDO0tBQUE7SUFFRCxXQUFXLENBQUMsVUFBa0I7O1FBQzFCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ3JELElBQUksU0FBUztZQUFFLE9BQU8sU0FBUyxDQUFBO1FBRS9CLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDckIsTUFBTSxLQUFLLEdBQUcsTUFBQSxJQUFJLENBQUMsTUFBTSwwQ0FBRyxVQUFVLENBQUMsQ0FBQTtRQUN2QyxJQUFJLENBQUMsS0FBSztZQUFFLE9BQU07UUFFbEIsSUFBSSxLQUFLLENBQUMsR0FBRztZQUFFLE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQTtRQUUvQixJQUFJLE9BQU8sS0FBSyxDQUFDLFVBQVUsS0FBSyxRQUFRO1lBQUUsT0FBTTtRQUNoRCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUNoRSxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU07UUFFbkIsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUM1QixJQUFJLEVBQUUsS0FBSyxDQUFDLFFBQVE7U0FDdkIsQ0FBQyxDQUFBO1FBQ0YsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNyQyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDeEMsT0FBTyxHQUFHLENBQUE7SUFDZCxDQUFDO0lBNEJELGlCQUFpQixDQUNiLFFBQXdDLEVBQ3hDLE9BT2tCLFNBQVM7O1FBUTNCLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDL0IsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQ3pCLE1BQUEsUUFBUSxDQUFDLFVBQVUsbUNBQUksQ0FBQyxFQUN4QixRQUFRLENBQUMsYUFBYSxDQUN6QixDQUFBO1FBQ0wsQ0FBQztRQUNELE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQTtRQUNoQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFBO1FBQ2hFLElBQUksU0FBUztZQUFFLE9BQU8sU0FBUyxDQUFBO1FBRS9CLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDckIsTUFBTSxVQUFVLEdBQUcsTUFBQSxJQUFJLENBQUMsV0FBVywwQ0FBRyxlQUFlLENBQUMsQ0FBQTtRQUN0RCxJQUFJLENBQUMsVUFBVTtZQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLGVBQWUsR0FBRyxDQUFDLENBQUE7UUFFcEUsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDN0MsTUFBTSxVQUFVLEdBQUcsTUFBQSxVQUFVLENBQUMsVUFBVSxtQ0FBSSxDQUFDLENBQUE7UUFDN0MsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FDckIsVUFBVSxFQUNWLFVBQVUsR0FBRyxVQUFVLENBQUMsVUFBVSxDQUNyQyxDQUFBO1FBQ0QsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUN0QixJQUFJLEVBQ0osbUJBQW1CLENBQ2YsTUFBQSxJQUFJLGFBQUosSUFBSSxjQUFKLElBQUksR0FDQSxNQUFBLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxlQUFlLENBQUMsMENBQ3pDLGFBQWEsbUNBQ25CLFNBQVMsQ0FDaEIsQ0FDSixDQUFBO1FBQ0QsSUFBSSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDcEQsT0FBTyxJQUFJLENBQUE7SUFDZixDQUFDO0lBRUQseUJBQXlCLENBQ3JCLGVBQXVCOztRQUV2QixPQUFPLENBQUMsTUFBQSxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsbUNBQUksRUFBRSxDQUFDLENBQUMsSUFBSSxDQUNuQyxRQUFRLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEtBQUssZUFBZSxDQUN0RCxDQUFBO0lBQ0wsQ0FBQztJQUVELFNBQVMsQ0FDTCxPQUFtQixFQUNuQixVQUFrQixFQUNsQixTQUFTLEdBQUcsQ0FBQyxFQUNiLGNBQWMsR0FBRyxDQUFDLEVBQ2xCLG1CQUE0Qjs7UUFFNUIsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNyQixNQUFNLGFBQWEsR0FDZixNQUFBLE1BQUEsSUFBSSxDQUFDLE1BQU0sMENBQUcsU0FBUyxFQUFFLFVBQVUsQ0FBQyxjQUFjLEVBQUUsVUFBVSxDQUMxRCxtQkFBbUIsYUFBbkIsbUJBQW1CLGNBQW5CLG1CQUFtQixHQUFJLFVBQVUsQ0FDcEMsbUNBQUksQ0FBQyxDQUFDLENBQUE7UUFDWCxNQUFNLFFBQVEsR0FBRyxNQUFBLElBQUksQ0FBQyxTQUFTLDBDQUFHLGFBQWEsQ0FBQyxDQUFBO1FBQ2hELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNaLE1BQU0sSUFBSSxLQUFLLENBQ1gsaUJBQ0ksbUJBQW1CLGFBQW5CLG1CQUFtQixjQUFuQixtQkFBbUIsR0FBSSxVQUMzQixvQkFBb0IsY0FBYyxhQUFhLFNBQVMsR0FBRyxDQUM5RCxDQUFBO1FBQ0wsQ0FBQztRQUVELE1BQU0sZUFBZSxHQUFHLE1BQUEsUUFBUSxDQUFDLFVBQVUsbUNBQUksQ0FBQyxDQUFBO1FBQ2hELE1BQU0sVUFBVSxHQUFHLE1BQUEsSUFBSSxDQUFDLFdBQVcsMENBQUcsZUFBZSxDQUFDLENBQUE7UUFDdEQsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsZUFBZSxHQUFHLENBQUMsQ0FBQTtRQUNwRSxDQUFDO1FBQ0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUMvQixlQUFlLEVBQ2YsUUFBUSxDQUFDLGFBQWEsQ0FDekIsQ0FBQTtRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRTtZQUMxQixVQUFVLEVBQUUsVUFBVSxDQUFDLFVBQVU7WUFDakMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVO1lBQy9CLEtBQUssRUFBRSxRQUFRLENBQUMsS0FBSztTQUN4QixDQUFDLENBQUE7SUFDTixDQUFDO0lBRUQsWUFBWSxDQUFDLEVBQ1QsY0FBYyxFQUNkLFNBQVMsR0FBRyxDQUFDLEVBQ2IsY0FBYyxHQUFHLENBQUMsRUFDbEIsZUFBZSxHQUFHLFVBQVUsRUFDNUIsYUFBYSxHQUFHLFFBQVEsRUFDeEIsb0JBQW9CLEdBQUcsWUFBWSxNQVFuQyxFQUFFO1FBQ0YsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQTtRQUNsRSxJQUFJLENBQUM7WUFDRCxNQUFNLEVBQUUsVUFBVSxFQUFFLEdBQUcsU0FBUyxDQUFBO1lBQ2hDLElBQUksQ0FBQyxVQUFVO2dCQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLENBQUMsQ0FBQTtZQUN4RCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQ3pDLFNBQVMsRUFDVCxjQUFjLENBQ2pCLENBQUE7WUFDRCxNQUFNLFVBQVUsR0FBeUI7Z0JBQ3JDLENBQUMsZUFBZSxDQUFDLEVBQUUsTUFBTTthQUM1QixDQUFBO1lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxhQUFhLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDaEQsVUFBVSxDQUFDLGFBQWEsQ0FBQyxHQUFHLE1BQU0sQ0FBQTtZQUN0QyxDQUFDO1lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxVQUFVLENBQUMsb0JBQW9CLENBQUMsR0FBRyxNQUFNLENBQUE7WUFDN0MsQ0FBQztZQUNELE1BQU0sT0FBTyxHQUFHLElBQUksVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1lBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQ1AsZUFBZSxFQUNmLGtCQUFrQixDQUNkLElBQUksQ0FBQyxpQkFBaUIsQ0FDbEIsSUFBSSxDQUFDLDBCQUEwQixDQUMzQixTQUFTLEVBQ1QsZUFBZSxDQUNsQixDQUNKLENBQ0osQ0FDSixDQUFBO1lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxhQUFhLENBQUMsS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDaEQsT0FBTyxDQUFDLEdBQUcsQ0FDUCxhQUFhLEVBQ2Isa0JBQWtCLENBQ2QsSUFBSSxDQUFDLGlCQUFpQixDQUNsQixJQUFJLENBQUMsMEJBQTBCLENBQzNCLFNBQVMsRUFDVCxhQUFhLENBQ2hCLENBQ0osQ0FDSixDQUNKLENBQUE7WUFDTCxDQUFDO1lBQ0QsSUFBSSxPQUFPLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxPQUFPLENBQUMsR0FBRyxDQUNQLG9CQUFvQixFQUNwQixrQkFBa0IsQ0FDZCxJQUFJLENBQUMsaUJBQWlCLENBQ2xCLElBQUksQ0FBQywwQkFBMEIsQ0FDM0IsU0FBUyxFQUNULG9CQUFvQixDQUN2QixDQUNKLENBQ0osQ0FDSixDQUFBO1lBQ0wsQ0FBQztZQUNELE9BQU8sSUFBSSxXQUFXLENBQUM7Z0JBQ25CLHVCQUF1QixFQUFFLGNBQWM7Z0JBQ3ZDLE9BQU87Z0JBQ1AsUUFBUTtnQkFDUixXQUFXLEVBQUUsZUFBZTtnQkFDNUIsU0FBUyxFQUFFLGFBQWE7Z0JBQ3hCLEtBQUssRUFBRSxvQkFBb0I7YUFDOUIsQ0FBQyxDQUFBO1FBQ04sQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDYixNQUFNLE9BQU8sR0FDVCxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ2xFLE1BQU0sSUFBSSxLQUFLLENBQ1gsdUJBQXVCLGNBQWMsYUFBYSxTQUFTLE1BQU0sT0FBTyxFQUFFLENBQzdFLENBQUE7UUFDTCxDQUFDO0lBQ0wsQ0FBQztDQUNKO0FBRUQsU0FBUyxhQUFhLENBQUMsSUFBaUIsRUFBRSxhQUFxQjtJQUMzRCxRQUFRLGFBQWEsRUFBRSxDQUFDO1FBQ3BCLEtBQUssSUFBSTtZQUNMLE9BQU8sSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDOUIsS0FBSyxJQUFJO1lBQ0wsT0FBTyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUMvQixLQUFLLElBQUk7WUFDTCxPQUFPLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQy9CLEtBQUssSUFBSTtZQUNMLE9BQU8sSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDaEMsS0FBSyxJQUFJO1lBQ0wsT0FBTyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNoQztZQUNJLE9BQU8sSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDckMsQ0FBQztBQUNMLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLElBQXFCO0lBQzlDLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sSUFBSSxDQUFBO0lBRXpDLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFDWCxLQUFLLE1BQU07WUFDUCxPQUFPLElBQUksQ0FBQTtRQUNmLEtBQUssT0FBTztZQUNSLE9BQU8sSUFBSSxDQUFBO1FBQ2YsS0FBSyxPQUFPO1lBQ1IsT0FBTyxJQUFJLENBQUE7UUFDZixLQUFLLFFBQVE7WUFDVCxPQUFPLElBQUksQ0FBQTtRQUNmLEtBQUssUUFBUTtZQUNULE9BQU8sSUFBSSxDQUFBO1FBQ2Y7WUFDSSxPQUFPLHNCQUFzQixDQUFDLEtBQUssQ0FBQTtJQUMzQyxDQUFDO0lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFBO0FBQ2hELENBQUM7QUFFRCxTQUFTLGtCQUFrQixDQUFDLElBQWE7SUFDckMsSUFBSSxJQUFJLFlBQVksWUFBWTtRQUFFLE9BQU8sSUFBSSxDQUFBO0lBRTdDLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQTtBQUN4RCxDQUFDO0FBRUQsU0FBUyxTQUFTLENBQUMsR0FBVztJQUMxQixPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQ3pCLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxFQUFFLENBQUE7UUFDdkIsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUE7UUFDYixHQUFHLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFBO1FBQ2hELEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7SUFDdEQsQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDIn0=