UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

335 lines (331 loc) 30.5 kB
import { TgdConsole } from "./../debug/index.js"; import { TgdShaderFragment, TgdShaderVertex } from "./../shader/index.js"; import { tgdCodeStringify } from "./../shader/index.js"; /** * This class helps to manage a WebGLProgram. * It will report meaninfull errors and help you with * the uniforms. */ export class TgdProgram { constructor(gl, options) { this.gl = gl; this.options = options; const prg = gl.createProgram(); if (!prg) throw new Error("Unable to create WebGLProgram!"); this.name = options.name ?? `TgdProgram#${TgdProgram.id++}`; const { vert, frag } = checkCompatibilityBetweenShaders(options); this.vert = vert; this.frag = frag; const vertShader = this.createShader("VERTEX_SHADER", vert); gl.attachShader(prg, vertShader); const fragShader = this.createShader("FRAGMENT_SHADER", frag); gl.attachShader(prg, fragShader); const { transformFeedback } = options; if (transformFeedback) { const bufferMode = Array.isArray(transformFeedback) ? gl.INTERLEAVED_ATTRIBS : gl[transformFeedback.bufferMode]; const varyings = Array.isArray(transformFeedback) ? transformFeedback : transformFeedback.varyings; gl.transformFeedbackVaryings(prg, varyings, bufferMode); } gl.linkProgram(prg); gl.validateProgram(prg); if (!gl.getProgramParameter(prg, gl.LINK_STATUS) && !gl.isContextLost()) { const info = gl.getProgramInfoLog(prg) ?? ""; console.error(info); const errorLines = getErrorLines(info); const cause = [ logCode("Vertex Shader", vert, errorLines), logCode("Fragment Shader", frag, errorLines), ].join("\n"); throw new Error(cause); } this.program = prg; this.shaders = [vertShader, fragShader]; this.uniformsLocations = this.getUniformsLocations(); gl.detachShader(prg, vertShader); gl.deleteShader(vertShader); gl.detachShader(prg, fragShader); gl.deleteShader(fragShader); } toCode({ indent = "" } = {}) { const lines = [ `function createProgram(gl: WebGL2RenderingContext) {`, ` const prg = gl.createProgram()`, ` const vertexShader = gl.createShader(gl.VERTEX_SHADER)`, ` gl.shaderSource(vertexShader, \`${tgdCodeStringify(this.vert)}\`)`, ` gl.compileShader(vertexShader)`, ` const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)`, ` gl.shaderSource(fragmentShader, \`${tgdCodeStringify(this.frag)}\`)`, ` gl.compileShader(fragmentShader)`, ` gl.attachShader(prg, vertexShader)`, ` gl.attachShader(prg, fragmentShader)`, ` gl.linkProgram(prg)`, ` return prg`, `}`, ]; return lines.map((line) => `${indent}${line}`).join("\n"); } hasAttribute(name) { const { gl, program } = this; const loc = gl.getAttribLocation(program, name); return loc >= 0; } getAttribLocation(name) { const { gl, program } = this; const loc = gl.getAttribLocation(program, name); if (loc < 0) { throw new Error(`Attribute "${name}" not found!`); } return loc; } getUniformLocation(name) { const { uniformsLocations } = this; const names = Object.keys(uniformsLocations); if (name.length === 0) { console.warn(`Uniform "${name}" has not been found: there is no active uniform in this program!`); return 0; } const location = uniformsLocations[name]; if (!location) { console.warn(`No active uniform found with name "${name}"!\nAvailable names are: ${names.sort().join(", ")}.`); } return location; } uniform1f(name, value) { const { gl } = this; gl.uniform1f(this.getUniformLocation(name), value); } uniform2f(name, x, y) { const { gl } = this; gl.uniform2f(this.getUniformLocation(name), x, y); } uniform2fv(name, vec2) { const { gl } = this; gl.uniform2fv(this.getUniformLocation(name), vec2); } uniform3f(name, x, y, z) { const { gl } = this; gl.uniform3f(this.getUniformLocation(name), x, y, z); } uniform3fv(name, vec3) { const { gl } = this; gl.uniform3fv(this.getUniformLocation(name), vec3); } uniform4f(name, x, y, z, w) { const { gl } = this; gl.uniform4f(this.getUniformLocation(name), x, y, z, w); } uniform4fv(name, vec4) { const { gl } = this; gl.uniform4fv(this.getUniformLocation(name), vec4); } uniform1i(name, value) { const { gl } = this; gl.uniform1i(this.getUniformLocation(name), value); } uniform2i(name, x, y) { const { gl } = this; gl.uniform2i(this.getUniformLocation(name), x, y); } uniform3i(name, x, y, z) { const { gl } = this; gl.uniform3i(this.getUniformLocation(name), x, y, z); } uniform4i(name, x, y, z, w) { const { gl } = this; gl.uniform4i(this.getUniformLocation(name), x, y, z, w); } uniform1ui(name, value) { const { gl } = this; gl.uniform1ui(this.getUniformLocation(name), value); } uniform2ui(name, x, y) { const { gl } = this; gl.uniform2ui(this.getUniformLocation(name), x, y); } uniform3ui(name, x, y, z) { const { gl } = this; gl.uniform3ui(this.getUniformLocation(name), x, y, z); } uniform4ui(name, x, y, z, w) { const { gl } = this; gl.uniform4ui(this.getUniformLocation(name), x, y, z, w); } uniformMatrix2fv(name, mat2) { const { gl } = this; gl.uniformMatrix2fv(this.getUniformLocation(name), false, mat2); } uniformMatrix3fv(name, mat3) { const { gl } = this; gl.uniformMatrix3fv(this.getUniformLocation(name), false, mat3); } uniformMatrix4fv(name, mat4) { const { gl } = this; gl.uniformMatrix4fv(this.getUniformLocation(name), false, mat4); } /** * Use the current program. * This is equivalent to `gl.useProgram(program)`. */ use() { const { gl, program } = this; gl.useProgram(program); } delete() { const { gl } = this; for (const shader of this.shaders) gl.deleteShader(shader); gl.deleteProgram(this.program); } debug(caption) { const { gl, program } = this; console.debug(caption ?? this.name); const contextLost = gl.isContextLost(); const items = [ { text: "Context lost: " }, { text: contextLost ? "TRUE" : "FALSE", color: contextLost ? "#0F0" : "#f00", }, "\n", ]; const params = [ [gl.DELETE_STATUS, "Flagged for deletion"], [gl.LINK_STATUS, "Last link operation was successful"], [gl.VALIDATE_STATUS, "Last validation operation was successful"], [gl.ATTACHED_SHADERS, "Number of attached shaders"], [gl.ACTIVE_ATTRIBUTES, "Number of active attribute variables"], [gl.ACTIVE_UNIFORMS, "Number of active uniforms"], ]; for (const [id, label] of params) { items.push(`${label}: `); const param = gl.getProgramParameter(program, id); if (param === true) items.push({ text: "TRUE", color: "#0f0" }); else if (param === false) items.push({ text: "FALSE", color: "#f00" }); else items.push({ text: JSON.stringify(param), color: "#09f" }); items.push("\n"); } TgdConsole.debug(...items); logCode("Vertex Shader", tgdCodeStringify(this.vert)); logCode("Fragment Shader", tgdCodeStringify(this.frag)); } createShader(type, code) { const { gl } = this; const shader = gl.createShader(gl[type]); if (!shader) throw new Error(`Unable to create a WebGLShader of type "${type}"!`); gl.shaderSource(shader, code); gl.compileShader(shader); const info = gl.getShaderInfoLog(shader); if (info) { console.error(`Error in ${type} code:`, info); const errorLines = getErrorLines(info); throw new Error(logCode(type, code, errorLines)); } return shader; } getUniformsLocations() { const { gl, program } = this; const count = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); if (typeof count !== "number") { if (gl.isContextLost()) return {}; throw new Error("Unable to get the number of uniforms in a WebGLProgram!"); } const uniforms = {}; for (let index = 0; index < count; index++) { const uniform = gl.getActiveUniform(program, index); if (!uniform) continue; const location = gl.getUniformLocation(program, uniform.name); if (location === null) { // this.debug() // console.warn( // `Unable to get location for uniform "${uniform.name}" (size: ${uniform.size}, type: ${uniform.type})!` // ) } else { uniforms[uniform.name] = location; } } return uniforms; } } TgdProgram.id = 1; const RX_ERROR_LINE = /^ERROR:[ \t]+([0-9]+):([0-9]+):/g; function getErrorLines(message) { const lines = []; const messages = []; for (const line of message.split("\n")) { RX_ERROR_LINE.lastIndex = -1; const match = RX_ERROR_LINE.exec(line); if (match) { lines.push(Number.parseInt(match[2], 10)); messages.push(line.slice(match[0].length).trim()); } } return { lines, messages }; } function style(background, bold = false) { return `color:#fff;background:${background};font-family:monospace;font-size:80%;font-weight:${bold ? "bolder" : "100"};margin:0;color:${bold ? "#777" : "#fff"}`; } function logCode(title, code, options) { const { lines = [], messages = [] } = options ?? {}; const output = [title]; const codeLines = [`%c${title}`]; const styles = ["font-weight:bolder;font-size:120%"]; let hasError = false; for (const [index, line] of code.split("\n").entries()) { const lineNumber = index + 1; const prefix = `${lineNumber}`.padStart(5, " "); const background = lines.includes(lineNumber) ? "#f00" : "#000"; codeLines.push(`%c${prefix} %c${line}`); output.push(`${prefix} ${line}`); styles.push(style(background, true), style(background, false)); if (lines.includes(lineNumber)) { hasError = true; codeLines.push(`%c${messages[lines.indexOf(lineNumber)]}`); output.push(`##### ${messages[lines.indexOf(lineNumber)]}`); styles.push("color:#f33;background:#333;font-weight:bold"); console.error(); } } console.debug(codeLines.join("\n"), ...styles); return hasError ? output.join("\n") : "No error."; } function checkCompatibilityBetweenShaders({ vert, frag, }) { if (vert instanceof TgdShaderVertex && frag instanceof TgdShaderFragment) { if (!frag.varying || Object.keys(frag.varying).length === 0) { frag.varying = vert.varying; } else { const vertVarying = Object.keys(vert.varying) .sort() .map((key) => ` ${key}:${vert.varying[key]} `) .join("\n"); const fragVarying = Object.keys(frag.varying) .sort() .map((key) => ` ${key}:${frag.varying[key]} `) .join("\n"); if (vertVarying !== fragVarying) { throw new Error(`[TgdProgram] Different varying for vertex and fragments shaders! Vertex shader: ${vertVarying} Fragment shader: ${fragVarying} To avoid such mistake, just don't specify the varyings for the fragment shader, and we will use the same as the vertex shader. `); } } } const vertCode = vert instanceof TgdShaderVertex ? vert.code : tgdCodeStringify(vert); const fragCode = frag instanceof TgdShaderFragment ? frag.code : tgdCodeStringify(frag); return { vert: vertCode, frag: fragCode }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZ3JhbS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9ncmFtL3Byb2dyYW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBa0IsTUFBTSxZQUFZLENBQUE7QUFFdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNoRSxPQUFPLEVBQWUsZ0JBQWdCLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFHM0Q7Ozs7R0FJRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBWW5CLFlBQ29CLEVBQTBCLEVBQ3pCLE9BQTBCO1FBRDNCLE9BQUUsR0FBRixFQUFFLENBQXdCO1FBQ3pCLFlBQU8sR0FBUCxPQUFPLENBQW1CO1FBRTNDLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQTtRQUM5QixJQUFJLENBQUMsR0FBRztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLENBQUMsQ0FBQTtRQUUzRCxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLElBQUksY0FBYyxVQUFVLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQTtRQUMzRCxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLGdDQUFnQyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ2hFLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO1FBQ2hCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO1FBQ2hCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzNELEVBQUUsQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBQ2hDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDN0QsRUFBRSxDQUFDLFlBQVksQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLENBQUE7UUFDaEMsTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQ3JDLElBQUksaUJBQWlCLEVBQUUsQ0FBQztZQUNwQixNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO2dCQUMvQyxDQUFDLENBQUMsRUFBRSxDQUFDLG1CQUFtQjtnQkFDeEIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUN0QyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUE7WUFDbEcsRUFBRSxDQUFDLHlCQUF5QixDQUFDLEdBQUcsRUFBRSxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUE7UUFDM0QsQ0FBQztRQUNELEVBQUUsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDbkIsRUFBRSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUN2QixJQUFJLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsYUFBYSxFQUFFLEVBQUUsQ0FBQztZQUN0RSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFBO1lBQzVDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDbkIsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ3RDLE1BQU0sS0FBSyxHQUFHO2dCQUNWLE9BQU8sQ0FBQyxlQUFlLEVBQUUsSUFBSSxFQUFFLFVBQVUsQ0FBQztnQkFDMUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLElBQUksRUFBRSxVQUFVLENBQUM7YUFDL0MsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDWixNQUFNLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQzFCLENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQTtRQUNsQixJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBQ3ZDLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQTtRQUNwRCxFQUFFLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsQ0FBQTtRQUNoQyxFQUFFLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQzNCLEVBQUUsQ0FBQyxZQUFZLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBQ2hDLEVBQUUsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDL0IsQ0FBQztJQUVELE1BQU0sQ0FBQyxFQUFFLE1BQU0sR0FBRyxFQUFFLEtBQWtDLEVBQUU7UUFDcEQsTUFBTSxLQUFLLEdBQWE7WUFDcEIsc0RBQXNEO1lBQ3RELGtDQUFrQztZQUNsQywwREFBMEQ7WUFDMUQscUNBQXFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSztZQUNyRSxrQ0FBa0M7WUFDbEMsOERBQThEO1lBQzlELHVDQUF1QyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUs7WUFDdkUsb0NBQW9DO1lBQ3BDLHNDQUFzQztZQUN0Qyx3Q0FBd0M7WUFDeEMsdUJBQXVCO1lBQ3ZCLGNBQWM7WUFDZCxHQUFHO1NBQ04sQ0FBQTtRQUNELE9BQU8sS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsR0FBRyxNQUFNLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDN0QsQ0FBQztJQUVELFlBQVksQ0FBQyxJQUFZO1FBQ3JCLE1BQU0sRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQzVCLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDL0MsT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFBO0lBQ25CLENBQUM7SUFFRCxpQkFBaUIsQ0FBQyxJQUFZO1FBQzFCLE1BQU0sRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQzVCLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDL0MsSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDVixNQUFNLElBQUksS0FBSyxDQUFDLGNBQWMsSUFBSSxjQUFjLENBQUMsQ0FBQTtRQUNyRCxDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUE7SUFDZCxDQUFDO0lBRUQsa0JBQWtCLENBQUMsSUFBWTtRQUMzQixNQUFNLEVBQUUsaUJBQWlCLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbEMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFBO1FBQzVDLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNwQixPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxtRUFBbUUsQ0FBQyxDQUFBO1lBQ2pHLE9BQU8sQ0FBQyxDQUFBO1FBQ1osQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3hDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNaLE9BQU8sQ0FBQyxJQUFJLENBQ1Isc0NBQXNDLElBQUksNEJBQTRCLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FDbkcsQ0FBQTtRQUNMLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQTtJQUNuQixDQUFDO0lBRUQsU0FBUyxDQUFDLElBQVksRUFBRSxLQUFhO1FBQ2pDLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbkIsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUE7SUFDdEQsQ0FBQztJQUVELFNBQVMsQ0FBQyxJQUFZLEVBQUUsQ0FBUyxFQUFFLENBQVM7UUFDeEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDckQsQ0FBQztJQUVELFVBQVUsQ0FBQyxJQUFZLEVBQUUsSUFBYTtRQUNsQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3RELENBQUM7SUFFRCxTQUFTLENBQUMsSUFBWSxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsQ0FBUztRQUNuRCxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDeEQsQ0FBQztJQUVELFVBQVUsQ0FBQyxJQUFZLEVBQUUsSUFBYTtRQUNsQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3RELENBQUM7SUFFRCxTQUFTLENBQUMsSUFBWSxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsQ0FBUyxFQUFFLENBQVM7UUFDOUQsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUMzRCxDQUFDO0lBRUQsVUFBVSxDQUFDLElBQVksRUFBRSxJQUFhO1FBQ2xDLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbkIsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdEQsQ0FBQztJQUVELFNBQVMsQ0FBQyxJQUFZLEVBQUUsS0FBYTtRQUNqQyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFBO0lBQ3RELENBQUM7SUFFRCxTQUFTLENBQUMsSUFBWSxFQUFFLENBQVMsRUFBRSxDQUFTO1FBQ3hDLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbkIsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3JELENBQUM7SUFFRCxTQUFTLENBQUMsSUFBWSxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsQ0FBUztRQUNuRCxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDeEQsQ0FBQztJQUVELFNBQVMsQ0FBQyxJQUFZLEVBQUUsQ0FBUyxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsQ0FBUztRQUM5RCxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQzNELENBQUM7SUFFRCxVQUFVLENBQUMsSUFBWSxFQUFFLEtBQWE7UUFDbEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQTtJQUN2RCxDQUFDO0lBRUQsVUFBVSxDQUFDLElBQVksRUFBRSxDQUFTLEVBQUUsQ0FBUztRQUN6QyxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUN0RCxDQUFDO0lBRUQsVUFBVSxDQUFDLElBQVksRUFBRSxDQUFTLEVBQUUsQ0FBUyxFQUFFLENBQVM7UUFDcEQsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBO0lBQ3pELENBQUM7SUFFRCxVQUFVLENBQUMsSUFBWSxFQUFFLENBQVMsRUFBRSxDQUFTLEVBQUUsQ0FBUyxFQUFFLENBQVM7UUFDL0QsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUM1RCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsSUFBWSxFQUFFLElBQWE7UUFDeEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUNuRSxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsSUFBWSxFQUFFLElBQWE7UUFDeEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUNuRSxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsSUFBWSxFQUFFLElBQWE7UUFDeEMsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNuQixFQUFFLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUNuRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsR0FBRztRQUNDLE1BQU0sRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQzVCLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDMUIsQ0FBQztJQUVELE1BQU07UUFDRixNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQ25CLEtBQUssTUFBTSxNQUFNLElBQUksSUFBSSxDQUFDLE9BQU87WUFBRSxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzFELEVBQUUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ2xDLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBZ0I7UUFDbEIsTUFBTSxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDNUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ25DLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQTtRQUN0QyxNQUFNLEtBQUssR0FBZ0M7WUFDdkMsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUU7WUFDMUI7Z0JBQ0ksSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPO2dCQUNwQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU07YUFDdkM7WUFDRCxJQUFJO1NBQ1AsQ0FBQTtRQUNELE1BQU0sTUFBTSxHQUE0QjtZQUNwQyxDQUFDLEVBQUUsQ0FBQyxhQUFhLEVBQUUsc0JBQXNCLENBQUM7WUFDMUMsQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLG9DQUFvQyxDQUFDO1lBQ3RELENBQUMsRUFBRSxDQUFDLGVBQWUsRUFBRSwwQ0FBMEMsQ0FBQztZQUNoRSxDQUFDLEVBQUUsQ0FBQyxnQkFBZ0IsRUFBRSw0QkFBNEIsQ0FBQztZQUNuRCxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsRUFBRSxzQ0FBc0MsQ0FBQztZQUM5RCxDQUFDLEVBQUUsQ0FBQyxlQUFlLEVBQUUsMkJBQTJCLENBQUM7U0FDcEQsQ0FBQTtRQUNELEtBQUssTUFBTSxDQUFDLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUMvQixLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxJQUFJLENBQUMsQ0FBQTtZQUN4QixNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1lBQ2pELElBQUksS0FBSyxLQUFLLElBQUk7Z0JBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7aUJBQzFELElBQUksS0FBSyxLQUFLLEtBQUs7Z0JBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7O2dCQUNqRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUE7WUFDL0QsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNwQixDQUFDO1FBQ0QsVUFBVSxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFBO1FBQzFCLE9BQU8sQ0FBQyxlQUFlLEVBQUUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7UUFDckQsT0FBTyxDQUFDLGlCQUFpQixFQUFFLGdCQUFnQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0lBQzNELENBQUM7SUFFTyxZQUFZLENBQUMsSUFBZ0IsRUFBRSxJQUFZO1FBQy9DLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbkIsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtRQUN4QyxJQUFJLENBQUMsTUFBTTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLElBQUksSUFBSSxDQUFDLENBQUE7UUFFakYsRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDN0IsRUFBRSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUN4QixNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDeEMsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNQLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQTtZQUM3QyxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDdEMsTUFBTSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFBO1FBQ3BELENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQTtJQUNqQixDQUFDO0lBRU8sb0JBQW9CO1FBQ3hCLE1BQU0sRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFBO1FBQzVCLE1BQU0sS0FBSyxHQUFZLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxDQUFBO1FBQzFFLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDNUIsSUFBSSxFQUFFLENBQUMsYUFBYSxFQUFFO2dCQUFFLE9BQU8sRUFBRSxDQUFBO1lBRWpDLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQTtRQUM5RSxDQUFDO1FBRUQsTUFBTSxRQUFRLEdBQTZDLEVBQUUsQ0FBQTtRQUU3RCxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUM7WUFDekMsTUFBTSxPQUFPLEdBQUcsRUFBRSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQTtZQUNuRCxJQUFJLENBQUMsT0FBTztnQkFBRSxTQUFRO1lBRXRCLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQzdELElBQUksUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUNwQixlQUFlO2dCQUNmLGdCQUFnQjtnQkFDaEIsNkdBQTZHO2dCQUM3RyxJQUFJO1lBQ1IsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxDQUFBO1lBQ3JDLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUE7SUFDbkIsQ0FBQzs7QUE3UmMsYUFBRSxHQUFHLENBQUMsQ0FBQTtBQWtTekIsTUFBTSxhQUFhLEdBQUcsa0NBQWtDLENBQUE7QUFFeEQsU0FBUyxhQUFhLENBQUMsT0FBZTtJQUlsQyxNQUFNLEtBQUssR0FBYSxFQUFFLENBQUE7SUFDMUIsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFBO0lBQzdCLEtBQUssTUFBTSxJQUFJLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ3JDLGFBQWEsQ0FBQyxTQUFTLEdBQUcsQ0FBQyxDQUFDLENBQUE7UUFDNUIsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUN0QyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1IsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFBO1lBQ3pDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtRQUNyRCxDQUFDO0lBQ0wsQ0FBQztJQUNELE9BQU8sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUE7QUFDOUIsQ0FBQztBQUVELFNBQVMsS0FBSyxDQUFDLFVBQWtCLEVBQUUsSUFBSSxHQUFHLEtBQUs7SUFDM0MsT0FBTyx5QkFBeUIsVUFBVSxvREFDdEMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQ3RCLG1CQUFtQixJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUE7QUFDL0MsQ0FBQztBQUVELFNBQVMsT0FBTyxDQUFDLEtBQWEsRUFBRSxJQUFZLEVBQUUsT0FBaUQ7SUFDM0YsTUFBTSxFQUFFLEtBQUssR0FBRyxFQUFFLEVBQUUsUUFBUSxHQUFHLEVBQUUsRUFBRSxHQUFHLE9BQU8sSUFBSSxFQUFFLENBQUE7SUFDbkQsTUFBTSxNQUFNLEdBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUNoQyxNQUFNLFNBQVMsR0FBYSxDQUFDLEtBQUssS0FBSyxFQUFFLENBQUMsQ0FBQTtJQUMxQyxNQUFNLE1BQU0sR0FBYSxDQUFDLG1DQUFtQyxDQUFDLENBQUE7SUFDOUQsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFBO0lBQ3BCLEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7UUFDckQsTUFBTSxVQUFVLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQTtRQUM1QixNQUFNLE1BQU0sR0FBRyxHQUFHLFVBQVUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUE7UUFDL0MsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUE7UUFDL0QsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLE1BQU0sT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQTtRQUNqQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLEVBQUUsS0FBSyxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFBO1FBQzlELElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzdCLFFBQVEsR0FBRyxJQUFJLENBQUE7WUFDZixTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssUUFBUSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUE7WUFDMUQsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLFFBQVEsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQzNELE1BQU0sQ0FBQyxJQUFJLENBQUMsNkNBQTZDLENBQUMsQ0FBQTtZQUMxRCxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDbkIsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUMsQ0FBQTtJQUM5QyxPQUFPLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFBO0FBQ3JELENBQUM7QUFFRCxTQUFTLGdDQUFnQyxDQUFDLEVBQ3RDLElBQUksRUFDSixJQUFJLEdBSVA7SUFDRyxJQUFJLElBQUksWUFBWSxlQUFlLElBQUksSUFBSSxZQUFZLGlCQUFpQixFQUFFLENBQUM7UUFDdkUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQTtRQUMvQixDQUFDO2FBQU0sQ0FBQztZQUNKLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztpQkFDeEMsSUFBSSxFQUFFO2lCQUNOLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsTUFBTSxHQUFHLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDO2lCQUMvQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDZixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7aUJBQ3hDLElBQUksRUFBRTtpQkFDTixHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLE1BQU0sR0FBRyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztpQkFDL0MsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ2YsSUFBSSxXQUFXLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUM7OztFQUc5QixXQUFXOzs7RUFHWCxXQUFXOzs7OztDQUtaLENBQUMsQ0FBQTtZQUNVLENBQUM7UUFDTCxDQUFDO0lBQ0wsQ0FBQztJQUNELE1BQU0sUUFBUSxHQUFHLElBQUksWUFBWSxlQUFlLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ3JGLE1BQU0sUUFBUSxHQUFHLElBQUksWUFBWSxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDdkYsT0FBTyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFBO0FBQzdDLENBQUMifQ==