@loaders.gl/las
Version:
Framework-independent loader for the LAS and LAZ formats
4 lines • 1.2 MB
Source Map (JSON)
{
"version": 3,
"sources": ["index.js", "las-loader.js", "lib/parse-las.js", "lib/libs/laz-perf.js", "lib/laslaz-decoder.js", "lib/get-las-schema.js"],
"sourcesContent": ["import { LASLoader as LASWorkerLoader } from \"./las-loader.js\";\nimport { parseLAS } from \"./lib/parse-las.js\";\nexport { LASWorkerLoader };\n/**\n * Loader for the LAS (LASer) point cloud format\n * @note Does not support LAS v1.4\n */\nexport const LASLoader = {\n ...LASWorkerLoader,\n parse: async (arrayBuffer, options) => parseLAS(arrayBuffer, options),\n parseSync: (arrayBuffer, options) => parseLAS(arrayBuffer, options)\n};\n", "// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof \"4.3.2\" !== 'undefined' ? \"4.3.2\" : 'latest';\n/**\n * Loader for the LAS (LASer) point cloud format\n * @note Does not support LAS v1.4\n */\nexport const LASLoader = {\n dataType: null,\n batchType: null,\n name: 'LAS',\n id: 'las',\n module: 'las',\n version: VERSION,\n worker: true,\n extensions: ['las', 'laz'], // LAZ is the \"compressed\" flavor of LAS,\n mimeTypes: ['application/octet-stream'], // TODO - text version?\n text: true,\n binary: true,\n tests: ['LAS'],\n options: {\n las: {\n shape: 'mesh',\n fp64: false,\n skip: 1,\n colorDepth: 8\n }\n }\n};\n", "import { getMeshBoundingBox /* , convertMesh */ } from '@loaders.gl/schema';\nimport { LASFile } from \"./laslaz-decoder.js\";\nimport { getLASSchema } from \"./get-las-schema.js\";\n/**\n * Parsing of .las file\n * @param arrayBuffer\n * @param options\n * @returns LASHeader\n */\nexport function parseLAS(arrayBuffer, options) {\n return parseLASMesh(arrayBuffer, options);\n // This code breaks pointcloud example on the website\n // const mesh = parseLASMesh(arrayBuffer, options);\n // return convertMesh(mesh, options?.las?.shape || 'mesh') as LASMesh | ArrowTable | ColumnarTable;\n}\n/**\n * Parsing of .las file\n * @param arrayBuffer\n * @param options\n * @returns LASHeader\n */\nfunction parseLASMesh(arrayBuffer, options = {}) {\n let pointIndex = 0;\n let positions;\n let colors;\n let intensities;\n let classifications;\n let originalHeader;\n const lasMesh = {\n loader: 'las',\n loaderData: {},\n // shape: 'mesh',\n schema: { fields: [], metadata: {} },\n header: {\n vertexCount: 0,\n boundingBox: [\n [0, 0, 0],\n [0, 0, 0]\n ]\n },\n attributes: {},\n topology: 'point-list',\n mode: 0 // GL.POINTS\n };\n /* eslint-disable max-statements */\n // @ts-ignore Possibly undefined\n parseLASChunked(arrayBuffer, options.las?.skip, (decoder = {}, lasHeader) => {\n if (!originalHeader) {\n originalHeader = lasHeader;\n const total = lasHeader.totalToRead;\n const PositionsType = options.las?.fp64 ? Float64Array : Float32Array;\n positions = new PositionsType(total * 3);\n // laslaz-decoder.js `pointFormatReaders`\n colors = lasHeader.pointsFormatId >= 2 ? new Uint8Array(total * 4) : null;\n intensities = new Uint16Array(total);\n classifications = new Uint8Array(total);\n lasMesh.loaderData = lasHeader;\n lasMesh.attributes = {\n POSITION: { value: positions, size: 3 },\n // non-gltf attributes, use non-capitalized names for now\n intensity: { value: intensities, size: 1 },\n classification: { value: classifications, size: 1 }\n };\n if (colors) {\n lasMesh.attributes.COLOR_0 = { value: colors, size: 4 };\n }\n }\n const batchSize = decoder.pointsCount;\n const { scale: [scaleX, scaleY, scaleZ], offset: [offsetX, offsetY, offsetZ] } = lasHeader;\n const twoByteColor = detectTwoByteColors(decoder, batchSize, options.las?.colorDepth);\n for (let i = 0; i < batchSize; i++) {\n const { position, color, intensity, classification } = decoder.getPoint(i);\n positions[pointIndex * 3] = position[0] * scaleX + offsetX;\n positions[pointIndex * 3 + 1] = position[1] * scaleY + offsetY;\n positions[pointIndex * 3 + 2] = position[2] * scaleZ + offsetZ;\n if (color && colors) {\n if (twoByteColor) {\n colors[pointIndex * 4] = color[0] / 256;\n colors[pointIndex * 4 + 1] = color[1] / 256;\n colors[pointIndex * 4 + 2] = color[2] / 256;\n }\n else {\n colors[pointIndex * 4] = color[0];\n colors[pointIndex * 4 + 1] = color[1];\n colors[pointIndex * 4 + 2] = color[2];\n }\n colors[pointIndex * 4 + 3] = 255;\n }\n intensities[pointIndex] = intensity;\n classifications[pointIndex] = classification;\n pointIndex++;\n }\n const meshBatch = {\n ...lasMesh,\n header: {\n vertexCount: lasHeader.totalRead\n },\n progress: lasHeader.totalRead / lasHeader.totalToRead\n };\n options?.onProgress?.(meshBatch);\n });\n /* eslint-enable max-statements */\n lasMesh.header = {\n vertexCount: originalHeader.totalToRead,\n boundingBox: getMeshBoundingBox(lasMesh?.attributes || {})\n };\n if (lasMesh) {\n lasMesh.schema = getLASSchema(lasMesh.loaderData, lasMesh.attributes);\n }\n return lasMesh;\n}\n/**\n * parse laz data\n * @param rawData\n * @param skip\n * @param onParseData\n * @return parsed point cloud\n */\n/* eslint-enable max-statements */\nexport function parseLASChunked(rawData, skip, onParseData = {}) {\n const dataHandler = new LASFile(rawData);\n try {\n // open data\n dataHandler.open();\n const header = dataHandler.getHeader();\n // start loading\n const Unpacker = dataHandler.getUnpacker();\n const totalToRead = Math.ceil(header.pointsCount / Math.max(1, skip));\n header.totalToRead = totalToRead;\n let totalRead = 0;\n /* eslint-disable no-constant-condition */\n while (true) {\n const chunk = dataHandler.readData(1000 * 100, 0, skip);\n totalRead += chunk.count;\n header.totalRead = totalRead;\n header.versionAsString = chunk.versionAsString;\n header.isCompressed = chunk.isCompressed;\n const unpacker = new Unpacker(chunk.buffer, chunk.count, header);\n // surface unpacker and progress via call back\n // use unpacker.pointsCount and unpacker.getPoint(i) to handle data in app\n onParseData(unpacker, header);\n if (!chunk.hasMoreData || totalRead >= totalToRead) {\n break;\n }\n }\n }\n catch (e) {\n throw e;\n }\n finally {\n dataHandler.close();\n }\n}\n/**\n * @param decoder\n * @param batchSize\n * @param colorDepth\n * @returns boolean\n */\nfunction detectTwoByteColors(decoder = {}, batchSize, colorDepth) {\n let twoByteColor = false;\n switch (colorDepth) {\n case 8:\n twoByteColor = false;\n break;\n case 16:\n twoByteColor = true;\n break;\n case 'auto':\n if (decoder.getPoint(0).color) {\n for (let i = 0; i < batchSize; i++) {\n const { color } = decoder.getPoint(i);\n // eslint-disable-next-line max-depth\n if (color[0] > 255 || color[1] > 255 || color[2] > 255) {\n twoByteColor = true;\n }\n }\n }\n break;\n default:\n // eslint-disable-next-line\n console.warn('las: illegal value for options.las.colorDepth');\n break;\n }\n return twoByteColor;\n}\n", "// @ts-nocheck\n/* eslint-disable */\n/*\n * Last update 2020-07-23\n *\n * Compiled from Howard Butler's laz-perf\n * https://github.com/hobu/laz-perf\n * Under LGPL License\n *\n * To update this file:\n * - git clone https://github.com/hobu/laz-perf\n * - cd laz-perf\n * - echo 'set(CMAKE_CXX_FLAGS \"-s SINGLE_FILE=1 ${CMAKE_CXX_FLAGS}\"' >> emscripten/CMakeLists.txt\n * - mkdir build && cd build\n * - cmake .. -DEMSCRIPTEN=1 -DCMAKE_TOOLCHAIN_FILE=<path-to-emsdk>/emscripten/<emsdk-version>/cmake/Modules/Platform/Emscripten.cmake\n * - VERBOSE=1 make\n *\n * See the laz-perf repository for required dependencies\n *\n * The result should be build/emscripten/laz-perf.asm.js\n * Copy the content of this file in the getModule function below\n */\n// laz-perf.js\nexport default function getModule() {\n var Module = typeof Module !== 'undefined' ? Module : {};\n var moduleOverrides = {};\n var key;\n for (key in Module) {\n if (Module.hasOwnProperty(key)) {\n moduleOverrides[key] = Module[key];\n }\n }\n var arguments_ = [];\n var thisProgram = './this.program';\n var quit_ = function (status, toThrow) {\n throw toThrow;\n };\n var ENVIRONMENT_IS_WEB = false;\n var ENVIRONMENT_IS_WORKER = false;\n var ENVIRONMENT_IS_NODE = false;\n var ENVIRONMENT_IS_SHELL = false;\n ENVIRONMENT_IS_WEB = typeof window === 'object';\n ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';\n ENVIRONMENT_IS_NODE =\n typeof process === 'object' &&\n typeof process.versions === 'object' &&\n typeof process.versions.node === 'string';\n ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;\n var scriptDirectory = '';\n function locateFile(path) {\n if (Module['locateFile']) {\n return Module['locateFile'](path, scriptDirectory);\n }\n return scriptDirectory + path;\n }\n var read_, readAsync, readBinary, setWindowTitle;\n var nodeFS;\n var nodePath;\n if (ENVIRONMENT_IS_NODE) {\n if (ENVIRONMENT_IS_WORKER) {\n scriptDirectory = require('path').dirname(scriptDirectory) + '/';\n }\n else {\n const dirname = typeof __dirname !== 'undefined' ? __dirname : '';\n scriptDirectory = dirname + '/';\n }\n read_ = function shell_read(filename, binary) {\n var ret = tryParseAsDataURI(filename);\n if (ret) {\n return binary ? ret : ret.toString();\n }\n if (!nodeFS)\n nodeFS = require('fs');\n if (!nodePath)\n nodePath = require('path');\n filename = nodePath['normalize'](filename);\n return nodeFS['readFileSync'](filename, binary ? null : 'utf8');\n };\n readBinary = function readBinary(filename) {\n var ret = read_(filename, true);\n if (!ret.buffer) {\n ret = new Uint8Array(ret);\n }\n assert(ret.buffer);\n return ret;\n };\n if (process['argv'].length > 1) {\n thisProgram = process['argv'][1].replace(/\\\\/g, '/');\n }\n arguments_ = process['argv'].slice(2);\n if (typeof module !== 'undefined') {\n module['exports'] = Module;\n }\n process['on']('uncaughtException', function (ex) {\n if (!(ex instanceof ExitStatus)) {\n throw ex;\n }\n });\n process['on']('unhandledRejection', abort);\n quit_ = function (status) {\n process['exit'](status);\n };\n Module['inspect'] = function () {\n return '[Emscripten Module object]';\n };\n }\n else if (ENVIRONMENT_IS_SHELL) {\n if (typeof read != 'undefined') {\n read_ = function shell_read(f) {\n var data = tryParseAsDataURI(f);\n if (data) {\n return intArrayToString(data);\n }\n return read(f);\n };\n }\n readBinary = function readBinary(f) {\n var data;\n data = tryParseAsDataURI(f);\n if (data) {\n return data;\n }\n if (typeof readbuffer === 'function') {\n return new Uint8Array(readbuffer(f));\n }\n data = read(f, 'binary');\n assert(typeof data === 'object');\n return data;\n };\n if (typeof scriptArgs != 'undefined') {\n arguments_ = scriptArgs;\n }\n else if (typeof arguments != 'undefined') {\n arguments_ = arguments;\n }\n if (typeof quit === 'function') {\n quit_ = function (status) {\n quit(status);\n };\n }\n if (typeof print !== 'undefined') {\n if (typeof console === 'undefined')\n console = {};\n console.log = print;\n console.warn = console.error = typeof printErr !== 'undefined' ? printErr : print;\n }\n }\n else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n if (ENVIRONMENT_IS_WORKER) {\n scriptDirectory = self.location.href;\n }\n else if (document.currentScript) {\n scriptDirectory = document.currentScript.src;\n }\n if (scriptDirectory.indexOf('blob:') !== 0) {\n scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/') + 1);\n }\n else {\n scriptDirectory = '';\n }\n {\n read_ = function shell_read(url) {\n try {\n var xhr = new XMLHttpRequest();\n xhr.open('GET', url, false);\n xhr.send(null);\n return xhr.responseText;\n }\n catch (err) {\n var data = tryParseAsDataURI(url);\n if (data) {\n return intArrayToString(data);\n }\n throw err;\n }\n };\n if (ENVIRONMENT_IS_WORKER) {\n readBinary = function readBinary(url) {\n try {\n var xhr = new XMLHttpRequest();\n xhr.open('GET', url, false);\n xhr.responseType = 'arraybuffer';\n xhr.send(null);\n return new Uint8Array(xhr.response);\n }\n catch (err) {\n var data = tryParseAsDataURI(url);\n if (data) {\n return data;\n }\n throw err;\n }\n };\n }\n readAsync = function readAsync(url, onload, onerror) {\n var xhr = new XMLHttpRequest();\n xhr.open('GET', url, true);\n xhr.responseType = 'arraybuffer';\n xhr.onload = function xhr_onload() {\n if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n onload(xhr.response);\n return;\n }\n var data = tryParseAsDataURI(url);\n if (data) {\n onload(data.buffer);\n return;\n }\n onerror();\n };\n xhr.onerror = onerror;\n xhr.send(null);\n };\n }\n setWindowTitle = function (title) {\n document.title = title;\n };\n }\n else {\n }\n var out = Module['print'] || console.log.bind(console);\n var err = Module['printErr'] || console.warn.bind(console);\n for (key in moduleOverrides) {\n if (moduleOverrides.hasOwnProperty(key)) {\n Module[key] = moduleOverrides[key];\n }\n }\n moduleOverrides = null;\n if (Module['arguments'])\n arguments_ = Module['arguments'];\n if (Module['thisProgram'])\n thisProgram = Module['thisProgram'];\n if (Module['quit'])\n quit_ = Module['quit'];\n var STACK_ALIGN = 16;\n function dynamicAlloc(size) {\n var ret = HEAP32[DYNAMICTOP_PTR >> 2];\n var end = (ret + size + 15) & -16;\n HEAP32[DYNAMICTOP_PTR >> 2] = end;\n return ret;\n }\n function getNativeTypeSize(type) {\n switch (type) {\n case 'i1':\n case 'i8':\n return 1;\n case 'i16':\n return 2;\n case 'i32':\n return 4;\n case 'i64':\n return 8;\n case 'float':\n return 4;\n case 'double':\n return 8;\n default: {\n if (type[type.length - 1] === '*') {\n return 4;\n }\n else if (type[0] === 'i') {\n var bits = Number(type.substr(1));\n assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);\n return bits / 8;\n }\n else {\n return 0;\n }\n }\n }\n }\n function warnOnce(text) {\n if (!warnOnce.shown)\n warnOnce.shown = {};\n if (!warnOnce.shown[text]) {\n warnOnce.shown[text] = 1;\n err(text);\n }\n }\n var jsCallStartIndex = 1;\n var functionPointers = new Array(0);\n var funcWrappers = {};\n function dynCall(sig, ptr, args) {\n if (args && args.length) {\n return Module['dynCall_' + sig].apply(null, [ptr].concat(args));\n }\n else {\n return Module['dynCall_' + sig].call(null, ptr);\n }\n }\n var tempRet0 = 0;\n var setTempRet0 = function (value) {\n tempRet0 = value;\n };\n var getTempRet0 = function () {\n return tempRet0;\n };\n var GLOBAL_BASE = 8;\n var wasmBinary;\n if (Module['wasmBinary'])\n wasmBinary = Module['wasmBinary'];\n var noExitRuntime;\n if (Module['noExitRuntime'])\n noExitRuntime = Module['noExitRuntime'];\n function setValue(ptr, value, type, noSafe) {\n type = type || 'i8';\n if (type.charAt(type.length - 1) === '*')\n type = 'i32';\n switch (type) {\n case 'i1':\n HEAP8[ptr >> 0] = value;\n break;\n case 'i8':\n HEAP8[ptr >> 0] = value;\n break;\n case 'i16':\n HEAP16[ptr >> 1] = value;\n break;\n case 'i32':\n HEAP32[ptr >> 2] = value;\n break;\n case 'i64':\n (tempI64 = [\n value >>> 0,\n ((tempDouble = value),\n +Math_abs(tempDouble) >= +1\n ? tempDouble > +0\n ? (Math_min(+Math_floor(tempDouble / +4294967296), +4294967295) | 0) >>> 0\n : ~~+Math_ceil((tempDouble - +(~~tempDouble >>> 0)) / +4294967296) >>> 0\n : 0)\n ]),\n (HEAP32[ptr >> 2] = tempI64[0]),\n (HEAP32[(ptr + 4) >> 2] = tempI64[1]);\n break;\n case 'float':\n HEAPF32[ptr >> 2] = value;\n break;\n case 'double':\n HEAPF64[ptr >> 3] = value;\n break;\n default:\n abort('invalid type for setValue: ' + type);\n }\n }\n var ABORT = false;\n var EXITSTATUS = 0;\n function assert(condition, text) {\n if (!condition) {\n abort('Assertion failed: ' + text);\n }\n }\n function getCFunc(ident) {\n var func = Module['_' + ident];\n assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported');\n return func;\n }\n function ccall(ident, returnType, argTypes, args, opts) {\n var toC = {\n string: function (str) {\n var ret = 0;\n if (str !== null && str !== undefined && str !== 0) {\n var len = (str.length << 2) + 1;\n ret = stackAlloc(len);\n stringToUTF8(str, ret, len);\n }\n return ret;\n },\n array: function (arr) {\n var ret = stackAlloc(arr.length);\n writeArrayToMemory(arr, ret);\n return ret;\n }\n };\n function convertReturnValue(ret) {\n if (returnType === 'string')\n return UTF8ToString(ret);\n if (returnType === 'boolean')\n return Boolean(ret);\n return ret;\n }\n var func = getCFunc(ident);\n var cArgs = [];\n var stack = 0;\n if (args) {\n for (var i = 0; i < args.length; i++) {\n var converter = toC[argTypes[i]];\n if (converter) {\n if (stack === 0)\n stack = stackSave();\n cArgs[i] = converter(args[i]);\n }\n else {\n cArgs[i] = args[i];\n }\n }\n }\n var ret = func.apply(null, cArgs);\n ret = convertReturnValue(ret);\n if (stack !== 0)\n stackRestore(stack);\n return ret;\n }\n var ALLOC_NONE = 3;\n var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;\n function UTF8ArrayToString(heap, idx, maxBytesToRead) {\n var endIdx = idx + maxBytesToRead;\n var endPtr = idx;\n while (heap[endPtr] && !(endPtr >= endIdx))\n ++endPtr;\n if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) {\n return UTF8Decoder.decode(heap.subarray(idx, endPtr));\n }\n else {\n var str = '';\n while (idx < endPtr) {\n var u0 = heap[idx++];\n if (!(u0 & 128)) {\n str += String.fromCharCode(u0);\n continue;\n }\n var u1 = heap[idx++] & 63;\n if ((u0 & 224) == 192) {\n str += String.fromCharCode(((u0 & 31) << 6) | u1);\n continue;\n }\n var u2 = heap[idx++] & 63;\n if ((u0 & 240) == 224) {\n u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;\n }\n else {\n u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63);\n }\n if (u0 < 65536) {\n str += String.fromCharCode(u0);\n }\n else {\n var ch = u0 - 65536;\n str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));\n }\n }\n }\n return str;\n }\n function UTF8ToString(ptr, maxBytesToRead) {\n return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';\n }\n function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n if (!(maxBytesToWrite > 0))\n return 0;\n var startIdx = outIdx;\n var endIdx = outIdx + maxBytesToWrite - 1;\n for (var i = 0; i < str.length; ++i) {\n var u = str.charCodeAt(i);\n if (u >= 55296 && u <= 57343) {\n var u1 = str.charCodeAt(++i);\n u = (65536 + ((u & 1023) << 10)) | (u1 & 1023);\n }\n if (u <= 127) {\n if (outIdx >= endIdx)\n break;\n heap[outIdx++] = u;\n }\n else if (u <= 2047) {\n if (outIdx + 1 >= endIdx)\n break;\n heap[outIdx++] = 192 | (u >> 6);\n heap[outIdx++] = 128 | (u & 63);\n }\n else if (u <= 65535) {\n if (outIdx + 2 >= endIdx)\n break;\n heap[outIdx++] = 224 | (u >> 12);\n heap[outIdx++] = 128 | ((u >> 6) & 63);\n heap[outIdx++] = 128 | (u & 63);\n }\n else {\n if (outIdx + 3 >= endIdx)\n break;\n heap[outIdx++] = 240 | (u >> 18);\n heap[outIdx++] = 128 | ((u >> 12) & 63);\n heap[outIdx++] = 128 | ((u >> 6) & 63);\n heap[outIdx++] = 128 | (u & 63);\n }\n }\n heap[outIdx] = 0;\n return outIdx - startIdx;\n }\n function stringToUTF8(str, outPtr, maxBytesToWrite) {\n return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);\n }\n function lengthBytesUTF8(str) {\n var len = 0;\n for (var i = 0; i < str.length; ++i) {\n var u = str.charCodeAt(i);\n if (u >= 55296 && u <= 57343)\n u = (65536 + ((u & 1023) << 10)) | (str.charCodeAt(++i) & 1023);\n if (u <= 127)\n ++len;\n else if (u <= 2047)\n len += 2;\n else if (u <= 65535)\n len += 3;\n else\n len += 4;\n }\n return len;\n }\n var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;\n function UTF16ToString(ptr, maxBytesToRead) {\n var endPtr = ptr;\n var idx = endPtr >> 1;\n var maxIdx = idx + maxBytesToRead / 2;\n while (!(idx >= maxIdx) && HEAPU16[idx])\n ++idx;\n endPtr = idx << 1;\n if (endPtr - ptr > 32 && UTF16Decoder) {\n return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));\n }\n else {\n var i = 0;\n var str = '';\n while (1) {\n var codeUnit = HEAP16[(ptr + i * 2) >> 1];\n if (codeUnit == 0 || i == maxBytesToRead / 2)\n return str;\n ++i;\n str += String.fromCharCode(codeUnit);\n }\n }\n }\n function stringToUTF16(str, outPtr, maxBytesToWrite) {\n if (maxBytesToWrite === undefined) {\n maxBytesToWrite = 2147483647;\n }\n if (maxBytesToWrite < 2)\n return 0;\n maxBytesToWrite -= 2;\n var startPtr = outPtr;\n var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length;\n for (var i = 0; i < numCharsToWrite; ++i) {\n var codeUnit = str.charCodeAt(i);\n HEAP16[outPtr >> 1] = codeUnit;\n outPtr += 2;\n }\n HEAP16[outPtr >> 1] = 0;\n return outPtr - startPtr;\n }\n function lengthBytesUTF16(str) {\n return str.length * 2;\n }\n function UTF32ToString(ptr, maxBytesToRead) {\n var i = 0;\n var str = '';\n while (!(i >= maxBytesToRead / 4)) {\n var utf32 = HEAP32[(ptr + i * 4) >> 2];\n if (utf32 == 0)\n break;\n ++i;\n if (utf32 >= 65536) {\n var ch = utf32 - 65536;\n str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));\n }\n else {\n str += String.fromCharCode(utf32);\n }\n }\n return str;\n }\n function stringToUTF32(str, outPtr, maxBytesToWrite) {\n if (maxBytesToWrite === undefined) {\n maxBytesToWrite = 2147483647;\n }\n if (maxBytesToWrite < 4)\n return 0;\n var startPtr = outPtr;\n var endPtr = startPtr + maxBytesToWrite - 4;\n for (var i = 0; i < str.length; ++i) {\n var codeUnit = str.charCodeAt(i);\n if (codeUnit >= 55296 && codeUnit <= 57343) {\n var trailSurrogate = str.charCodeAt(++i);\n codeUnit = (65536 + ((codeUnit & 1023) << 10)) | (trailSurrogate & 1023);\n }\n HEAP32[outPtr >> 2] = codeUnit;\n outPtr += 4;\n if (outPtr + 4 > endPtr)\n break;\n }\n HEAP32[outPtr >> 2] = 0;\n return outPtr - startPtr;\n }\n function lengthBytesUTF32(str) {\n var len = 0;\n for (var i = 0; i < str.length; ++i) {\n var codeUnit = str.charCodeAt(i);\n if (codeUnit >= 55296 && codeUnit <= 57343)\n ++i;\n len += 4;\n }\n return len;\n }\n function writeArrayToMemory(array, buffer) {\n HEAP8.set(array, buffer);\n }\n function writeAsciiToMemory(str, buffer, dontAddNull) {\n for (var i = 0; i < str.length; ++i) {\n HEAP8[buffer++ >> 0] = str.charCodeAt(i);\n }\n if (!dontAddNull)\n HEAP8[buffer >> 0] = 0;\n }\n var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;\n function updateGlobalBufferAndViews(buf) {\n buffer = buf;\n Module['HEAP8'] = HEAP8 = new Int8Array(buf);\n Module['HEAP16'] = HEAP16 = new Int16Array(buf);\n Module['HEAP32'] = HEAP32 = new Int32Array(buf);\n Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf);\n Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf);\n Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf);\n Module['HEAPF32'] = HEAPF32 = new Float32Array(buf);\n Module['HEAPF64'] = HEAPF64 = new Float64Array(buf);\n }\n var STACK_BASE = 22384, DYNAMIC_BASE = 5265264, DYNAMICTOP_PTR = 22176;\n var INITIAL_INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 167772160;\n if (Module['buffer']) {\n buffer = Module['buffer'];\n }\n else {\n buffer = new ArrayBuffer(INITIAL_INITIAL_MEMORY);\n }\n INITIAL_INITIAL_MEMORY = buffer.byteLength;\n updateGlobalBufferAndViews(buffer);\n HEAP32[DYNAMICTOP_PTR >> 2] = DYNAMIC_BASE;\n function callRuntimeCallbacks(callbacks) {\n while (callbacks.length > 0) {\n var callback = callbacks.shift();\n if (typeof callback == 'function') {\n callback(Module);\n continue;\n }\n var func = callback.func;\n if (typeof func === 'number') {\n if (callback.arg === undefined) {\n Module['dynCall_v'](func);\n }\n else {\n Module['dynCall_vi'](func, callback.arg);\n }\n }\n else {\n func(callback.arg === undefined ? null : callback.arg);\n }\n }\n }\n var __ATPRERUN__ = [];\n var __ATINIT__ = [];\n var __ATMAIN__ = [];\n var __ATPOSTRUN__ = [];\n var runtimeInitialized = false;\n var runtimeExited = false;\n function preRun() {\n if (Module['preRun']) {\n if (typeof Module['preRun'] == 'function')\n Module['preRun'] = [Module['preRun']];\n while (Module['preRun'].length) {\n addOnPreRun(Module['preRun'].shift());\n }\n }\n callRuntimeCallbacks(__ATPRERUN__);\n }\n function initRuntime() {\n runtimeInitialized = true;\n callRuntimeCallbacks(__ATINIT__);\n }\n function preMain() {\n callRuntimeCallbacks(__ATMAIN__);\n }\n function exitRuntime() {\n runtimeExited = true;\n }\n function postRun() {\n if (Module['postRun']) {\n if (typeof Module['postRun'] == 'function')\n Module['postRun'] = [Module['postRun']];\n while (Module['postRun'].length) {\n addOnPostRun(Module['postRun'].shift());\n }\n }\n callRuntimeCallbacks(__ATPOSTRUN__);\n }\n function addOnPreRun(cb) {\n __ATPRERUN__.unshift(cb);\n }\n function addOnPostRun(cb) {\n __ATPOSTRUN__.unshift(cb);\n }\n var Math_abs = Math.abs;\n var Math_ceil = Math.ceil;\n var Math_floor = Math.floor;\n var Math_min = Math.min;\n var runDependencies = 0;\n var runDependencyWatcher = null;\n var dependenciesFulfilled = null;\n function addRunDependency(id) {\n runDependencies++;\n if (Module['monitorRunDependencies']) {\n Module['monitorRunDependencies'](runDependencies);\n }\n }\n function removeRunDependency(id) {\n runDependencies--;\n if (Module['monitorRunDependencies']) {\n Module['monitorRunDependencies'](runDependencies);\n }\n if (runDependencies == 0) {\n if (runDependencyWatcher !== null) {\n clearInterval(runDependencyWatcher);\n runDependencyWatcher = null;\n }\n if (dependenciesFulfilled) {\n var callback = dependenciesFulfilled;\n dependenciesFulfilled = null;\n callback();\n }\n }\n }\n Module['preloadedImages'] = {};\n Module['preloadedAudios'] = {};\n function abort(what) {\n if (Module['onAbort']) {\n Module['onAbort'](what);\n }\n what += '';\n out(what);\n err(what);\n ABORT = true;\n EXITSTATUS = 1;\n what = 'abort(' + what + '). Build with -s ASSERTIONS=1 for more info.';\n throw what;\n }\n var memoryInitializer = null;\n function hasPrefix(str, prefix) {\n return String.prototype.startsWith ? str.startsWith(prefix) : str.indexOf(prefix) === 0;\n }\n var dataURIPrefix = 'data:application/octet-stream;base64,';\n function isDataURI(filename) {\n return hasPrefix(filename, dataURIPrefix);\n }\n var fileURIPrefix = 'file://';\n var tempDouble;\n var tempI64;\n __ATINIT__.push({\n func: function () {\n globalCtors();\n }\n });\n memoryInitializer =\n 'data:application/octet-stream;base64,AAAAAAAAAAAPDg0MCwoJCA4AAQMGCgoJDQECBAcLCwoMAwQFCAwMCwsGBwgJDQ0MCgoLDA0ODg0JCgsMDQ4PDggJCgsMDQ4PAAECAwQFBgcBAAECAwQFBgIBAAECAwQFAwIBAAECAwQEAwIBAAECAwUEAwIBAAECBgUEAwIBAAEHBgUEAwIBAMgPAAAoDQAAEBAAACAQAADIDwAAUA0AABAQAAAgEAAAEQAKABEREQAAAAAFAAAAAAAACQAAAAALAAAAAAAAAAARAA8KERERAwoHAAEACQsLAAAJBgsAAAsABhEAAAAREREAAAAAAAAAAAAAAAAAAAAACwAAAAAAAAAAEQAKChEREQAKAAACAAkLAAAACQALAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAAwAAAAADAAAAAAJDAAAAAAADAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAANAAAABA0AAAAACQ4AAAAAAA4AAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADwAAAAAPAAAAAAkQAAAAAAAQAAAQAAASAAAAEhISAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAAAASEhIAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAKAAAAAAoAAAAACQsAAAAAAAsAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAAAAAAAADAAAAAAMAAAAAAkMAAAAAAAMAAAMAAAwMTIzNDU2Nzg5QUJDREVGGRJEOwI/LEcUPTMwChsGRktFNw9JDo4XA0AdPGkrNh9KLRwBICUpIQgMFRYiLhA4Pgs0MRhkdHV2L0EJfzkRI0MyQomKiwUEJignDSoeNYwHGkiTE5SVAAAAAAAAAAAASWxsZWdhbCBieXRlIHNlcXVlbmNlAERvbWFpbiBlcnJvcgBSZXN1bHQgbm90IHJlcHJlc2VudGFibGUATm90IGEgdHR5AFBlcm1pc3Npb24gZGVuaWVkAE9wZXJhdGlvbiBub3QgcGVybWl0dGVkAE5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkATm8gc3VjaCBwcm9jZXNzAEZpbGUgZXhpc3RzAFZhbHVlIHRvbyBsYXJnZSBmb3IgZGF0YSB0eXBlAE5vIHNwYWNlIGxlZnQgb24gZGV2aWNlAE91dCBvZiBtZW1vcnkAUmVzb3VyY2UgYnVzeQBJbnRlcnJ1cHRlZCBzeXN0ZW0gY2FsbABSZXNvdXJjZSB0ZW1wb3JhcmlseSB1bmF2YWlsYWJsZQBJbnZhbGlkIHNlZWsAQ3Jvc3MtZGV2aWNlIGxpbmsAUmVhZC1vbmx5IGZpbGUgc3lzdGVtAERpcmVjdG9yeSBub3QgZW1wdHkAQ29ubmVjdGlvbiByZXNldCBieSBwZWVyAE9wZXJhdGlvbiB0aW1lZCBvdXQAQ29ubmVjdGlvbiByZWZ1c2VkAEhvc3QgaXMgZG93bgBIb3N0IGlzIHVucmVhY2hhYmxlAEFkZHJlc3MgaW4gdXNlAEJyb2tlbiBwaXBlAEkvTyBlcnJvcgBObyBzdWNoIGRldmljZSBvciBhZGRyZXNzAEJsb2NrIGRldmljZSByZXF1aXJlZABObyBzdWNoIGRldmljZQBOb3QgYSBkaXJlY3RvcnkASXMgYSBkaXJlY3RvcnkAVGV4dCBmaWxlIGJ1c3kARXhlYyBmb3JtYXQgZXJyb3IASW52YWxpZCBhcmd1bWVudABBcmd1bWVudCBsaXN0IHRvbyBsb25nAFN5bWJvbGljIGxpbmsgbG9vcABGaWxlbmFtZSB0b28gbG9uZwBUb28gbWFueSBvcGVuIGZpbGVzIGluIHN5c3RlbQBObyBmaWxlIGRlc2NyaXB0b3JzIGF2YWlsYWJsZQBCYWQgZmlsZSBkZXNjcmlwdG9yAE5vIGNoaWxkIHByb2Nlc3MAQmFkIGFkZHJlc3MARmlsZSB0b28gbGFyZ2UAVG9vIG1hbnkgbGlua3MATm8gbG9ja3MgYXZhaWxhYmxlAFJlc291cmNlIGRlYWRsb2NrIHdvdWxkIG9jY3VyAFN0YXRlIG5vdCByZWNvdmVyYWJsZQBQcmV2aW91cyBvd25lciBkaWVkAE9wZXJhdGlvbiBjYW5jZWxlZABGdW5jdGlvbiBub3QgaW1wbGVtZW50ZWQATm8gbWVzc2FnZSBvZiBkZXNpcmVkIHR5cGUASWRlbnRpZmllciByZW1vdmVkAERldmljZSBub3QgYSBzdHJlYW0ATm8gZGF0YSBhdmFpbGFibGUARGV2aWNlIHRpbWVvdXQAT3V0IG9mIHN0cmVhbXMgcmVzb3VyY2VzAExpbmsgaGFzIGJlZW4gc2V2ZXJlZABQcm90b2NvbCBlcnJvcgBCYWQgbWVzc2FnZQBGaWxlIGRlc2NyaXB0b3IgaW4gYmFkIHN0YXRlAE5vdCBhIHNvY2tldABEZXN0aW5hdGlvbiBhZGRyZXNzIHJlcXVpcmVkAE1lc3NhZ2UgdG9vIGxhcmdlAFByb3RvY29sIHdyb25nIHR5cGUgZm9yIHNvY2tldABQcm90b2NvbCBub3QgYXZhaWxhYmxlAFByb3RvY29sIG5vdCBzdXBwb3J0ZWQAU29ja2V0IHR5cGUgbm90IHN1cHBvcnRlZABOb3Qgc3VwcG9ydGVkAFByb3RvY29sIGZhbWlseSBub3Qgc3VwcG9ydGVkAEFkZHJlc3MgZmFtaWx5IG5vdCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wAQWRkcmVzcyBub3QgYXZhaWxhYmxlAE5ldHdvcmsgaXMgZG93bgBOZXR3b3JrIHVucmVhY2hhYmxlAENvbm5lY3Rpb24gcmVzZXQgYnkgbmV0d29yawBDb25uZWN0aW9uIGFib3J0ZWQATm8gYnVmZmVyIHNwYWNlIGF2YWlsYWJsZQBTb2NrZXQgaXMgY29ubmVjdGVkAFNvY2tldCBub3QgY29ubmVjdGVkAENhbm5vdCBzZW5kIGFmdGVyIHNvY2tldCBzaHV0ZG93bgBPcGVyYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcwBPcGVyYXRpb24gaW4gcHJvZ3Jlc3MAU3RhbGUgZmlsZSBoYW5kbGUAUmVtb3RlIEkvTyBlcnJvcgBRdW90YSBleGNlZWRlZABObyBtZWRpdW0gZm91bmQAV3JvbmcgbWVkaXVtIHR5cGUATm8gZXJyb3IgaW5mb3JtYXRpb24AAAAAAADgFgAAmRgAAGAQAAAAAAAA4BYAAEIZAABgEAAAAAAAAOAWAAAqGgAASA8AAAAAAAC4FgAANBsAAOAWAACfGgAAMAoAAAAAAADgFgAAaRsAAEgPAAAAAAAA4BYAAIobAABIDwAAAAAAALgWAAAPHAAA4BYAAHwcAABIDwAAAAAAAOAWAACVHAAASA8AAAAAAADgFgAAHh0AAEgPAAAAAAAA4BYAAHcdAABIDwAAAAAAAOAWAACQHQAASA8AAAAAAADgFgAAQh4AAEgPAAAAAAAA4BYAAIceAABgEAAAAAAAAOAWAACkHwAASA8AAAAAAAC4FgAAZyAAAOAWAADkHwAA8AoAAAAAAADgFgAAjyAAAGAQAAAAAAAAuBYAAMMiAADgFgAAAiIAABgLAAAAAAAA4BYAAOEiAABgEAAAAAAAAOAWAADQJAAAGAsAAAAAAADgFgAAkSUAAGAQAAAAAAAA4BYAAIAnAAAYCwAAAAAAAOAWAAA9KAAAYBAAAAAAAADgFgAAJCoAABgLAAAAAAAA4BYAAOkqAABgEAAAAAAAAOAWAADgLAAA8AoAAAAAAADgFgAAui0AAGAQAAAAAAAA4BYAANsvAADwCgAAAAAAAOAWAADTMAAAYBAAAAAAAADgFgAAMDMAAPAKAAAAAAAA4BYAACQ0AABgEAAAAAAAAOAWAAB5NgAA8AoAAAAAAADgFgAAizcAAGAQAAAAAAAA4BYAABw6AABgEAAAAAAAAOAWAACdOgAAYBAAAAAAAADgFgAAXjsAAPAKAAAAAAAA4BYAALU7AABgEAAAAAAAAOAWAADMPAAAGAsAAAAAAADgFgAATz0AAGAQAAAAAAAA4BYAAL4+AAAYCwAAAAAAAOAWAABBPwAAYBAAAAAAAADgFgAAsEAAABgLAAAAAAAA4BYAADNBAABgEAAAAAAAAOAWAACiQgAAGAsAAAAAAADgFgAAJUMAAGAQAAAAAAAA4BYAAJREAAAYCwAAAAAAAOAWAAAXRQAAYBAAAAAAAADgFgAAhkYAABgLAAAAAAAA4BYAAAlHAABgEAAAAAAAALgWAAB4SAAAiBcAAIBIAAAAAAAAIA0AAIgXAACJSAAAAQAAACANAAC4FgAAqkgAAIgXAAC6SAAAAAAAAEgNAACIFwAAy0gAAAEAAABIDQAAuBYAABhMAAC4FgAAN0wAALgWAABWTAAAuBYAAHVMAAC4FgAAlEwAALgWAACzTAAAuBYAANJMAAC4FgAA8UwAALgWAAAQTQAAuBYAAC9NAAC4FgAATk0AALgWAABtTQAAuBYAAIxNAACkFwAAn00AAAAAAAABAAAA8A0AAAAAAAC4FgAA4U0AAKQXAAAHTgAAAAAAAAEAAADwDQAAAAAAAKQXAABJTgAAAAAAAAEAAADwDQAAAAAAAKQXAACITgAAAAAAAAEAAADwDQAAAAAAAKQXAADHTgAAAAAAAAEAAADwDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALgWAADNTwAA4BYAAC1QAAAADwAAAAAAAOAWAADaTwAAEA8AAAAAAAC4FgAA+08AAOAWAAAIUAAA8A4AAAAAAADgFgAAhlAAAOgOAAAAAAAA4BYAAJNQAADoDgAAAAAAAOAWAACjUAAA6A4AAAAAAADgFgAAtVAAADgPAAAAAAAA4BYAAMZQAAA4DwAAAAAAAOAWAADXUAAAAA8AAAAAAADgFgAA+VAAAHgPAAAAAAAA4BYAAB1RAAAADwAAAAAAAOAWAABCUQAAeA8AAAAAAADgFgAAjlEAAAAPAAAAAAAAbBcAALZRAABsFwAAuFEAAGwXAAC7UQAAbBcAAL1RAABsFwAAv1EAAGwXAADBUQAAbBcAAMNRAABsFwAAxVEAAGwXAADHUQAAbBcAAMlRAABsFwAAy1EAAGwXAADNUQAAbBcAAM9RAABsFwAA0VEAAOAWAADTUQAA8A4AAAAAAADgFgAARlIAAOgOAAAAAAAAuBYAAGJSAACkFwAAe1IAAAAAAAABAAAAWBAAAAAAAADgFgAA9FIAAIgQAAAAAAAA4BYAABdTAACYEAAAAAAAALgWAAAuUwAA4BYAAHBTAACIEAAAAAAAAOAWAACSUwAASA8AAAAAAAAAAAAAAAoAAAEAAAACAAAAAwAAAAEAAAAEAAAAAAAAABAKAAABAAAABQAAAAYAAAACAAAABwAAAAAAAAAgCgAACAAAAAkAAAABAAAAAAAAADgKAAAKAAAACwAAAAIAAAABAAAADAAAAA0AAAACAAAAAwAAAAMAAAAAAAAASAoAAAgAAAAOAAAAAQAAAAAAAABYCgAACAAAAA8AAAABAAAAAAAAAIAKAAAIAAAAEAAAAAEAAAAAAAAAcAoAAAgAAAARAAAAAQAAAAAAAACQCgAACAAAABIAAAABAAAAAAAAAKAKAAAIAAAAEwAAAAEAAAAAAAAAsAoAAAgAAAAUAAAAAQAAAAAAAADACgAACAAAABUAAAABAAAAAAAAANAKAAABAAAAFgAAABcAAAAEAAAAGAAAAAAAAADgCgAACAAAABkAAAABAAAAAAAAAPgKAAAFAAAAGgAAABsAAAAAAAAA8AoAAAEAAAAcAAAAHQAAAAAAAAAICwAAAQAAAB4AAAAfAAAABgAAACAAAAAAAAAAIAsAACEAAAAiAAAABwAAAAgAAAAAAAAAGAsAACMAAAAkAAAABwAAAAkAAAAAAAAAMAsAAAEAAAAlAAAAJgAAAAoAAAAnAAAAAAAAAEALAAAoAAAAKQAAAAcAAAALAAAAAAAAAFALAAABAAAAKgAAACsAAAAMAAAALAAAAAAAAABgCwAALQAAAC4AAAAHAAAADQAAAAAAAABwCwAAAQAAAC8AAAAwAAAADgAAADEAAAAAAAAAgAsAADIAAAAzAAAABwAAAA8AAAAAAAAAkAsAAAEAAAA0AAAANQAAABAAAAA2AAAAAAAAAKALAAARAAAANwAAADgAAAAAAAAAsAsAAAEAAAA5AAAAOgAAABIAAAA7AAAAAAAAAMALAAATAAAAPAAAAD0AAAAAAAAA0AsAAAEAAAA+AAAAPwAAABQAAABAAAAAAAAAAOALAAAVAAAAQQAAAEIAAAAAAAAA8AsAAAEAAABDAAAARAAAABYAAABFAAAAAAAAAAAMAAAXAAAARgAAAEcAAAAAAAAAEAwAAAEAAABIAAAASQAAABgAAABKAAAAAAAAACAMAAABAAAASwAAAEwAAAAZAAAATQAAAAAAAAAwDAAAAQAAAE4AAABPAAAAGgAAAFAAAAAAAAAAQAwAABsAAABRAAAAUgAAAAAAAABQDAAAAQAAAFMAAABUAAAAHAAAAFUAAAAAAAAAYAwAAFYAAABXAAAABwAAAB0AAAAAAAAAcAwAAAEAAABYAAAAWQAAAB4AAABaAAAAAAAAAIAMAABbAAAAXAAAAAcAAAAfAAAAAAAAAJAMAAABAAAAXQAAAF4AAAAgAAAAXwAAAAAAAACgDAAAYAAAAGEAAAAHAAAAIQAAAAAAAACwDAAAAQAAAGIAAABjAAAAIgAAAGQAAAAAAAAAwAwAAGUAAABmAAAABwAAACMAAAAAAAAA0AwAAAEAAABnAAAAaAAAACQAAABpAAAAAAAAAOAMAABqAAAAawAAAAcAAAAlAAAAAAAAAPAMAAABAAAAbAAAAG0AAAAmAAAAbgAAAAAAAAAADQAAbwAAAHAAAAAHAAAAJwAAAAAAAAAQDQAAAQAAAHEAAAByAAAAKAAAAHMAAAAoDQAAyA8AACgNAAAIEAAAEBAAACgNAABQDQAAyA8AAFANAAAgEAAAyA8AAFANAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDgAAdAAAAHUAAAB2AAAAdwAAAAIAAAABAAAAAQAAAAEAAAAAAAAAGA8AAHQAAAB4AAAAdgAAAHcAAAACAAAAAgAAAAIAAAACAAAAAAAAACgPAAB5AAAAegAAAAQAAAAAAAAAOA8AAHsAAAB8AAAABQAAAAAAAABIDwAACAAAAH0AAAABAAAAAAAAAFgPAAB7AAAAfgAAAAUAAAAAAAAAaA8AAHsAAAB/AAAABQAAAAAAAAC4DwAAdAAAAIAAAAB2AAAAdwAAAAMAAAAAAAAAiA8AAHQAAACBAAAAdgAAAHcAAAAEAAAAAAAAADgQAAB0AAAAggAAAHYAAAB3AAAAAgAAAAMAAAADAAAAAwAAAAAAAABIEAAAgwAAAIQAAAAGAAAAAAAAAHgQAACFAAAAhgAAAAcAAAABAAAABQAAAAYAAAACAAAAAAAAAKAQAACFAAAAhwAAAAgAAAADAAAABQAAAAYAAAAEAAAA4BcAAAQYAAAAAAAAsBAAAIgAAACJAAAAAQAAAExBU1ppcABvcGVuAGdldFBvaW50AGdldENvdW50AER5bmFtaWNMQVNaaXAAYWRkRmllbGRGbG9hdGluZwBhZGRGaWVsZFNpZ25lZABhZGRGaWVsZFVuc2lnbmVkAE5TdDNfXzIyMF9fc2hhcmVkX3B0cl9wb2ludGVySVBONmxhc3ppcDdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRU5TXzE0ZGVmYXVsdF9kZWxldGVJUzNfRUVOU185YWxsb2NhdG9ySVMzX0VFRUUATlN0M19fMjE0ZGVmYXVsdF9kZWxldGVJTjZsYXN6aXA3c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRQBOU3QzX18yMjBfX3NoYXJlZF9wdHJfcG9pbnRlcklQTjZsYXN6aXAyaW82cmVhZGVyMTBiYXNpY19maWxlSU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRU5TXzE0ZGVmYXVsdF9kZWxldGVJUzdfRUVOU185YWxsb2NhdG9ySVM3X0VFRUUATlN0M19fMjE0ZGVmYXVsdF9kZWxldGVJTjZsYXN6aXAyaW82cmVhZGVyMTBiYXNpY19maWxlSU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFAExBU0YATjZsYXN6aXAxM2ludmFsaWRfbWFnaWNFAGFsbG9jYXRvcjxUPjo6YWxsb2NhdGUoc2l6ZV90IG4pICduJyBleGNlZWRzIG1heGltdW0gc3VwcG9ydGVkIHNpemUARmlsZSBtYWdpYyBpcyBub3QgdmFsaWQATlN0M19fMjEwX19mdW5jdGlvbjZfX2Z1bmNJWk42bGFzemlwMmlvNnJlYWRlcjEwYmFzaWNfZmlsZUlOUzJfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRTExX3ZhbGlkYXRvcnNFdkVVbFJOUzNfNmhlYWRlckVFX05TXzlhbGxvY2F0b3JJU0JfRUVGdlNBX0VFRQBOU3QzX18yMTBfX2Z1bmN0aW9uNl9fYmFzZUlGdlJONmxhc3ppcDJpbzZoZWFkZXJFRUVFAE42bGFzemlwMjFvbGRfc3R5bGVfY29tcHJlc3Npb25FAE42bGFzemlwMTRub3RfY29tcHJlc3NlZEUAVGhlIGZpbGUgc2VlbXMgdG8gaGF2ZSBvbGQgc3R5bGUgY29tcHJlc3Npb24gd2hpY2ggaXMgbm90IHN1cHBvcnRlZABUaGUgZmlsZSBkb2Vzbid0IHNlZW0gdG8gYmUgY29tcHJlc3NlZABaTjZsYXN6aXAyaW82cmVhZGVyMTBiYXNpY19maWxlSU5TXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUUxMV92YWxpZGF0b3JzRXZFVWxSTlMwXzZoZWFkZXJFRV8AbGFzemlwIGVuY29kZWQATjZsYXN6aXAxM25vX2xhc3ppcF92bHJFAE42bGFzemlwMjVsYXN6aXBfZm9ybWF0X3Vuc3VwcG9ydGVkRQBPbmx5IExBU3ppcCBQT0lOVFdJU0UgQ0hVTktFRCBkZWNvbXByZXNzb3IgaXMgc3VwcG9ydGVkAE5vIExBU3ppcCBWTFIgd2FzIGZvdW5kIGluIHRoZSBWTFJzIHNlY3Rpb24ATjZsYXN6aXAyMmNodW5rX3RhYmxlX3JlYWRfZXJyb3JFAENodW5rIHRhYmxlIG9mZnNldCA9PSAtMSBpcyBub3Qgc3VwcG9ydGVkIGF0IHRoaXMgdGltZQBONmxhc3ppcDEzbm90X3N1cHBvcnRlZEUATjZsYXN6aXAyNnVua25vd25fY2h1bmtfdGFibGVfZm9ybWF0RQBjaHVua19zaXplID09IHVpbnQubWF4IGlzIG5vdCBzdXBwb3J0ZWQgYXQgdGhpcyB0aW1lLgBUaGVyZSB3YXMgYSBwcm9ibGVtIHJlYWRpbmcgdGhlIGNodW5rIHRhYmxlAFRoZSBjaHVuayB0YWJsZSB2ZXJzaW9uIG51bWJlciBpcyB1bmtub3duAE42bGFzemlwMTFlbmRfb2ZfZmlsZUUAUmVhY2hlZCBFbmQgb2YgZmlsZQBJbnZhbGlkIG51bWJlciBvZiBzeW1ib2xzAE5TdDNfXzIyMF9fc2hhcmVkX3B0cl9wb2ludGVySVBONmxhc3ppcDhkZWNvZGVyczEwYXJpdGhtZXRpY0lOUzFfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlMxXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVOU18xNGRlZmF1bHRfZGVsZXRlSVM5X0VFTlNfOWFsbG9jYXRvcklTOV9FRUVFAE5TdDNfXzIxNGRlZmF1bHRfZGVsZXRlSU42bGFzemlwOGRlY29kZXJzMTBhcml0aG1ldGljSU5TMV8yaW8xOF9faWZzdHJlYW1fd3JhcHBlcklOUzFfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRUVFRUVFAE42bGFzemlwMTl1bmtub3duX3NjaGVtYV90eXBlRQBUaGUgTEFaIHNjaGVtYSBpcyBub3QgcmVjb2duaXplZABONmxhc3ppcDdmb3JtYXRzMjZkeW5hbWljX2ZpZWxkX2RlY29tcHJlc3NvcklOU184ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlNfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlNfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRUVFRUVFAE42bGFzemlwN2Zvcm1hdHMyMGR5bmFtaWNfZGVjb21wcmVzc29yRQBOU3QzX18yMjBfX3NoYXJlZF9wdHJfcG9pbnRlcklQTjZsYXN6aXA3Zm9ybWF0czI2ZHluYW1pY19maWVsZF9kZWNvbXByZXNzb3JJTlMxXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOUzFfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlMxXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVFRU5TXzE0ZGVmYXVsdF9kZWxldGVJU0NfRUVOU185YWxsb2NhdG9ySVNDX0VFRUUATlN0M19fMjE0ZGVmYXVsdF9kZWxldGVJTjZsYXN6aXA3Zm9ybWF0czI2ZHluYW1pY19maWVsZF9kZWNvbXByZXNzb3JJTlMxXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOUzFfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlMxXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVFRUVFAE42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOU18yaW8xOF9faWZzdHJlYW1fd3JhcHBlcklOU183c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFTlMwXzVmaWVsZElOUzBfM2xhczdwb2ludDEwRU5TMF8yMHN0YW5kYXJkX2RpZmZfbWV0aG9kSVNDX0VFRUVFRQBONmxhc3ppcDdmb3JtYXRzMTBiYXNlX2ZpZWxkRQBOU3QzX18yMjBfX3NoYXJlZF9wdHJfcG9pbnRlcklQTjZsYXN6aXA3Zm9ybWF0czI2ZHluYW1pY19kZWNvbXByZXNzb3JfZmllbGRJTlMxXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOUzFfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlMxXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVOUzJfNWZpZWxkSU5TMl8zbGFzN3BvaW50MTBFTlMyXzIwc3RhbmRhcmRfZGlmZl9tZXRob2RJU0VfRUVFRUVFTlNfMTRkZWZhdWx0X2RlbGV0ZUlTSV9FRU5TXzlhbGxvY2F0b3JJU0lfRUVFRQBOU3QzX18yMTRkZWZhdWx0X2RlbGV0ZUlONmxhc3ppcDdmb3JtYXRzMjZkeW5hbWljX2RlY29tcHJlc3Nvcl9maWVsZElOUzFfOGRlY29kZXJzMTBhcml0aG1ldGljSU5TMV8yaW8xOF9faWZzdHJlYW1fd3JhcHBlcklOUzFfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRUVFRU5TMl81ZmllbGRJTlMyXzNsYXM3cG9pbnQxMEVOUzJfMjBzdGFuZGFyZF9kaWZmX21ldGhvZElTRV9FRUVFRUVFRQBONmxhc3ppcDdmb3JtYXRzMjZkeW5hbWljX2RlY29tcHJlc3Nvcl9maWVsZElOU184ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlNfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlNfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRUVFRU5TMF81ZmllbGRJTlMwXzNsYXM3Z3BzdGltZUVOUzBfMjBzdGFuZGFyZF9kaWZmX21ldGhvZElTQ19FRUVFRUUATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TMV84ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlMxXzJpbzE4X19pZnN0cmVhbV93cmFwcGVySU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFTlMyXzVmaWVsZElOUzJfM2xhczdncHN0aW1lRU5TMl8yMHN0YW5kYXJkX2RpZmZfbWV0aG9kSVNFX0VFRUVFRU5TXzE0ZGVmYXVsdF9kZWxldGVJU0lfRUVOU185YWxsb2NhdG9ySVNJX0VFRUUATlN0M19fMjE0ZGVmYXVsdF9kZWxldGVJTjZsYXN6aXA3Zm9ybWF0czI2ZHluYW1pY19kZWNvbXByZXNzb3JfZmllbGRJTlMxXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOUzFfMmlvMThfX2lmc3RyZWFtX3dyYXBwZXJJTlMxXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVOUzJfNWZpZWxkSU5TMl8zbGFzN2dwc3RpbWVFTlMyXzIwc3RhbmRhcmRfZGlmZl9tZXRob2RJU0VfRUVFRUVFRUUATjZsYXN6aXA3Zm9ybWF0czI2ZHluYW1pY19kZWNvbXByZXNzb3JfZmllbGRJTlNfOGRlY29kZXJzMTBhcml0aG1ldGljSU5TXzJpbzE4X19pZnN0cmVhbV93cmFwcGVySU5TXzdzdHJlYW1zMTNtZW1vcnlfc3RyZWFtRUVFRUVOUzBfNWZpZWxkSU5TMF8zbGFzM3JnYkVOUzBfMjBzdGFuZGFyZF9kaWZmX21ldGhvZElTQ19FRUVFRUUATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TMV84ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlMxXzJpbzE4X19pZnN0cmVhbV93cmFwcGVySU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFTlMyXzVmaWVsZElOUzJfM2xhczNyZ2JFTlMyXzIwc3RhbmRhcmRfZGlmZl9tZXRob2RJU0VfRUVFRUVFTlNfMTRkZWZhdWx0X2RlbGV0ZUlTSV9FRU5TXzlhbGxvY2F0b3JJU0lfRUVFRQBOU3QzX18yMTRkZWZhdWx0X2RlbGV0ZUlONmxhc3ppcDdmb3JtYXRzMjZkeW5hbWljX2RlY29tcHJlc3Nvcl9maWVsZElOUzFfOGRlY29kZXJzMTBhcml0aG1ldGljSU5TMV8yaW8xOF9faWZzdHJlYW1fd3JhcHBlcklOUzFfN3N0cmVhbXMxM21lbW9yeV9zdHJlYW1FRUVFRU5TMl81ZmllbGRJTlMyXzNsYXMzcmdiRU5TMl8yMHN0YW5kYXJkX2RpZmZfbWV0aG9kSVNFX0VFRUVFRUVFAE42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TXzhkZWNvZGVyczEwYXJpdGhtZXRpY0lOU18yaW8xOF9faWZzdHJlYW1fd3JhcHBlcklOU183c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFTlMwXzVmaWVsZElOUzBfM2xhczEwZXh0cmFieXRlc0VOUzBfMjBzdGFuZGFyZF9kaWZmX21ldGhvZElTQ19FRUVFRUUATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TMV84ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlMxXzJpbzE4X19pZnN0cmVhbV93cmFwcGVySU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cmVhbUVFRUVFTlMyXzVmaWVsZElOUzJfM2xhczEwZXh0cmFieXRlc0VOUzJfMjBzdGFuZGFyZF9kaWZmX21ldGhvZElTRV9FRUVFRUVOU18xNGRlZmF1bHRfZGVsZXRlSVNJX0VFTlNfOWFsbG9jYXRvcklTSV9FRUVFAE5TdDNfXzIxNGRlZmF1bHRfZGVsZXRlSU42bGFzemlwN2Zvcm1hdHMyNmR5bmFtaWNfZGVjb21wcmVzc29yX2ZpZWxkSU5TMV84ZGVjb2RlcnMxMGFyaXRobWV0aWNJTlMxXzJpbzE4X19pZnN0cmVhbV93cmFwcGVySU5TMV83c3RyZWFtczEzbWVtb3J5X3N0cm