diff --git a/bin/build_parser_wasm.sh b/bin/build_parser_wasm.sh new file mode 100755 index 000000000..5ae81eb83 --- /dev/null +++ b/bin/build_parser_wasm.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Copyright (c) 2026 The xterm.js authors. All rights reserved. +# @license MIT +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +if [[ ! -f src/common/parser/wasm/transition_table.h ]]; then + npm run build + node bin/gen_parser_transition_table.mjs +fi + +WASM_DIR=src/common/parser/wasm +OUT="$WASM_DIR/parser.wasm" + +clang --target=wasm32-unknown-unknown -O2 -nostdlib -fuse-ld=lld \ + -Wl,--no-entry \ + -Wl,--export-memory \ + -Wl,--export=reset \ + -Wl,--export=scan \ + -Wl,--export=probe_action \ + -Wl,--export=set_state \ + -Wl,--export=sync_params_from \ + -Wl,--export=export_params_to \ + -Wl,--export=get_params_len \ + -Wl,--export=get_subparams_len \ + -Wl,--export=get_subparams_ptr \ + -Wl,--export=get_subparams_idx_ptr \ + -Wl,--export=get_input_ptr \ + -Wl,--export=get_kinds_ptr \ + -Wl,--export=get_starts_ptr \ + -Wl,--export=get_lengths_ptr \ + -Wl,--export=get_aux_ptr \ + -Wl,--export=get_param_starts_ptr \ + -Wl,--export=get_param_counts_ptr \ + -Wl,--export=get_params_ptr \ + -Wl,--export=get_state_ptr \ + -Wl,--export=get_header_ptr \ + -Wl,--initial-memory=67108864 \ + -Wl,--max-memory=67108864 \ + "$WASM_DIR/parser.c" -o "$OUT" + +node bin/embed_parser_wasm.mjs + +echo "Built $OUT" diff --git a/bin/embed_parser_wasm.mjs b/bin/embed_parser_wasm.mjs new file mode 100644 index 000000000..8e92a3792 --- /dev/null +++ b/bin/embed_parser_wasm.mjs @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname, '..'); +const wasm = readFileSync(join(root, 'src/common/parser/wasm/parser.wasm')); +const b64 = wasm.toString('base64'); + +const out = `/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ +/** Base64-encoded parser.wasm (generated by bin/build_parser_wasm.sh) */ +export const PARSER_WASM_BASE64 = '${b64}';\n`; + +writeFileSync(join(root, 'src/common/parser/wasm/parser.wasm.embed.ts'), out); +console.info(`Embedded parser.wasm (${wasm.length} bytes)`); diff --git a/bin/gen_parser_transition_table.mjs b/bin/gen_parser_transition_table.mjs new file mode 100644 index 000000000..c41f25729 --- /dev/null +++ b/bin/gen_parser_transition_table.mjs @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +// @ts-check +import { writeFileSync } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname, '..'); + +// Import compiled transition table +const { VT500_TRANSITION_TABLE } = await import(join(root, 'out/common/parser/EscapeSequenceParser.js')); + +const table = VT500_TRANSITION_TABLE.table; +let out = '/* Auto-generated by bin/gen_parser_transition_table.mjs - do not edit */\n'; +out += `#ifndef PARSER_TRANSITION_TABLE_H\n#define PARSER_TRANSITION_TABLE_H\n\n`; +out += `#include \n\n`; +out += `#define PARSER_TABLE_SIZE ${table.length}\n\n`; +out += `static const uint16_t PARSER_TRANSITION_TABLE[PARSER_TABLE_SIZE] = {\n`; +for (let i = 0; i < table.length; i++) { + if (i % 16 === 0) out += ' '; + out += `0x${table[i].toString(16)}`; + out += i < table.length - 1 ? ', ' : ''; + if (i % 16 === 15) out += '\n'; +} +if (table.length % 16 !== 0) out += '\n'; +out += `};\n\n#endif\n`; + +const headerPath = join(root, 'src/common/parser/wasm/transition_table.h'); +writeFileSync(headerPath, out); +console.info(`Wrote ${headerPath} (${table.length} entries)`); diff --git a/package.json b/package.json index 43e569d02..3bc844c5d 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "start": "node demo/start", "dev": "concurrently -k -p [{name}] -n tsc,esbuild,esbuild-demo-client,esbuild-demo-server,server -c blue,yellow,cyan,green,magenta \"npm:tsc-watch\" \"npm:esbuild-watch\" \"npm:esbuild-demo-client-watch\" \"npm:esbuild-demo-server-watch\" \"npm:start\"", "build": "npm run tsc", + "build:parser-wasm": "bash bin/build_parser_wasm.sh", "watch": "npm run tsc-watch", "tsc": "tsgo -b ./tsconfig.all.json", "tsc-watch": "tsgo -b -w ./tsconfig.all.json --preserveWatchOutput", diff --git a/src/common/parser/EscapeSequenceParser.test.ts b/src/common/parser/EscapeSequenceParser.test.ts index f684da2c8..2762b9899 100644 --- a/src/common/parser/EscapeSequenceParser.test.ts +++ b/src/common/parser/EscapeSequenceParser.test.ts @@ -77,10 +77,10 @@ class TestEscapeSequenceParser extends EscapeSequenceParser { public get realParams(): IParams { return this._params; } - public get collect(): string { + public get collectStr(): string { return this.identToString(this._collect); } - public set collect(value: string) { + public set collectStr(value: string) { this._collect = 0; for (let i = 0; i < value.length; ++i) { this._collect <<= 8; @@ -248,19 +248,19 @@ describe('EscapeSequenceParser', () => { assert.equal(parser.currentState, ParserState.GROUND); assert.equal(parser.osc, ''); assert.deepEqual(parser.params, [0]); - assert.equal(parser.collect, ''); + assert.equal(parser.collectStr, ''); }); it('reset states', () => { parser.currentState = 124; parser.osc = '#'; parser.params = [123]; - parser.collect = '#'; + parser.collectStr = '#'; parser.reset(); assert.equal(parser.currentState, ParserState.GROUND); assert.equal(parser.osc, ''); assert.deepEqual(parser.params, [0]); - assert.equal(parser.collect, ''); + assert.equal(parser.collectStr, ''); }); }); describe('state transitions and actions', () => { @@ -327,11 +327,11 @@ describe('EscapeSequenceParser', () => { for (state in states) { parser.currentState = state; parser.params = [23]; - parser.collect = '#'; + parser.collectStr = '#'; parse(parser, '\x1b'); assert.equal(parser.currentState, ParserState.ESCAPE); assert.deepEqual(parser.params, [0]); - assert.equal(parser.collect, ''); + assert.equal(parser.collectStr, ''); parser.reset(); } }); @@ -383,7 +383,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.ESCAPE; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.ESCAPE_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -419,7 +419,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.ESCAPE_INTERMEDIATE; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.ESCAPE_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -442,21 +442,21 @@ describe('EscapeSequenceParser', () => { // C0 parser.currentState = ParserState.ESCAPE; parser.params = [123]; - parser.collect = '#'; + parser.collectStr = '#'; parse(parser, '['); assert.equal(parser.currentState, ParserState.CSI_ENTRY); assert.deepEqual(parser.params, [0]); - assert.equal(parser.collect, ''); + assert.equal(parser.collectStr, ''); parser.reset(); // C1 for (state in states) { parser.currentState = state; parser.params = [123]; - parser.collect = '#'; + parser.collectStr = '#'; parse(parser, '\x9b'); assert.equal(parser.currentState, ParserState.CSI_ENTRY); assert.deepEqual(parser.params, [0]); - assert.equal(parser.collect, ''); + assert.equal(parser.collectStr, ''); parser.reset(); } }); @@ -517,7 +517,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.CSI_ENTRY; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.CSI_PARAM); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -582,7 +582,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.CSI_ENTRY; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.CSI_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -593,7 +593,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.CSI_PARAM; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.CSI_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -619,7 +619,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.CSI_INTERMEDIATE; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.CSI_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -848,7 +848,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.DCS_ENTRY; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.DCS_PARAM); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -930,7 +930,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.DCS_ENTRY; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.DCS_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -941,7 +941,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.DCS_PARAM; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.DCS_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -965,7 +965,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.DCS_INTERMEDIATE; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.DCS_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); @@ -976,7 +976,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.DCS_INTERMEDIATE; parse(parser, '\x20' + chars[i]); assert.equal(parser.currentState, ParserState.DCS_IGNORE); - assert.equal(parser.collect, '\x20'); + assert.equal(parser.collectStr, '\x20'); parser.reset(); } }); @@ -1079,7 +1079,7 @@ describe('EscapeSequenceParser', () => { parser.currentState = ParserState.APC_ENTRY; parse(parser, collect[i]); assert.equal(parser.currentState, ParserState.APC_INTERMEDIATE); - assert.equal(parser.collect, collect[i]); + assert.equal(parser.collectStr, collect[i]); parser.reset(); } }); diff --git a/src/common/parser/EscapeSequenceParser.ts b/src/common/parser/EscapeSequenceParser.ts index a0c97b610..6256aec48 100644 --- a/src/common/parser/EscapeSequenceParser.ts +++ b/src/common/parser/EscapeSequenceParser.ts @@ -11,6 +11,8 @@ import { Params } from './Params'; import { OscParser } from './OscParser'; import { DcsParser } from './DcsParser'; import { ApcParser } from './ApcParser'; +import { parseWithWasmScanner } from './EscapeSequenceParserWasm'; +import { WasmEscapeScanner } from './WasmEscapeScanner'; /** * VT commands done by the parser @@ -269,6 +271,9 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP protected _params: Params; protected _collect: number; + public get collect(): number { return this._collect; } + public set collect(value: number) { this._collect = value; } + // handler lookup containers protected _printHandler: PrintHandlerType; protected _executeHandlers: { [flag: number]: ExecuteHandlerType }; @@ -297,6 +302,8 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP chunkPos: 0 }; + protected _scanCache: { opIndex: number, stateBeforeScan?: number } = { opIndex: 0 }; + constructor( protected readonly _transitions: TransitionTable = VT500_TRANSITION_TABLE ) { @@ -494,12 +501,15 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP */ public reset(): void { this.currentState = this.initialState; + WasmEscapeScanner.initSync(); + WasmEscapeScanner.reset(); this._oscParser.reset(); this._dcsParser.reset(); this._apcParser.reset(); this._params.resetZdm(); this._collect = 0; this.precedingJoinState = 0; + this._scanCache.opIndex = 0; // abort pending continuation from async handler // Here the RESET type indicates, that the next parse call will // ignore any saved stack, instead continues sync with next codepoint from GROUND @@ -572,363 +582,6 @@ export class EscapeSequenceParser extends Disposable implements IEscapeSequenceP * ``` */ public parse(data: Uint32Array, length: number, promiseResult?: boolean): void | Promise { - let code: number; - let transition: number; - let start = 0; - let handlerResult: void | boolean | Promise; - - // resume from async handler - if (this._parseStack.state) { - // allow sync parser reset even in continuation mode - // Note: can be used to recover parser from improper continuation error below - if (this._parseStack.state === ParserStackType.RESET) { - this._parseStack.state = ParserStackType.NONE; - start = this._parseStack.chunkPos + 1; // continue with next codepoint in GROUND - } else { - if (promiseResult === undefined || this._parseStack.state === ParserStackType.FAIL) { - /** - * Reject further parsing on improper continuation after pausing. This is a really bad - * condition with screwed up execution order and prolly messed up terminal state, - * therefore we exit hard with an exception and reject any further parsing. - * - * Note: With `Terminal.write` usage this exception should never occur, as the top level - * calls are guaranteed to handle async conditions properly. If you ever encounter this - * exception in your terminal integration it indicates, that you injected data chunks to - * `InputHandler.parse` or `EscapeSequenceParser.parse` synchronously without waiting for - * continuation of a running async handler. - * - * It is possible to get rid of this error by calling `reset`. But dont rely on that, as - * the pending async handler still might mess up the terminal later. Instead fix the - * faulty async handling, so this error will not be thrown anymore. - */ - this._parseStack.state = ParserStackType.FAIL; - throw new Error('improper continuation due to previous async handler, giving up parsing'); - } - - // we have to resume the old handler loop if: - // - return value of the promise was `false` - // - handlers are not exhausted yet - const handlers = this._parseStack.handlers; - let handlerPos = this._parseStack.handlerPos - 1; - switch (this._parseStack.state) { - case ParserStackType.CSI: - if (promiseResult === false && handlerPos > -1) { - for (; handlerPos >= 0; handlerPos--) { - handlerResult = (handlers as CsiHandlerType[])[handlerPos](this._params); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._parseStack.handlerPos = handlerPos; - return handlerResult; - } - } - } - this._parseStack.handlers = []; - break; - case ParserStackType.ESC: - if (promiseResult === false && handlerPos > -1) { - for (; handlerPos >= 0; handlerPos--) { - handlerResult = (handlers as EscHandlerType[])[handlerPos](); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._parseStack.handlerPos = handlerPos; - return handlerResult; - } - } - } - this._parseStack.handlers = []; - break; - case ParserStackType.DCS: - code = data[this._parseStack.chunkPos]; - handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a, promiseResult); - if (handlerResult) { - return handlerResult; - } - if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - break; - case ParserStackType.OSC: - code = data[this._parseStack.chunkPos]; - handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a, promiseResult); - if (handlerResult) { - return handlerResult; - } - if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - break; - case ParserStackType.APC: - code = data[this._parseStack.chunkPos]; - handlerResult = this._apcParser.end(code !== 0x18 && code !== 0x1a, promiseResult); - if (handlerResult) { - return handlerResult; - } - if (code === 0x1b) this._parseStack.transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - break; - } - // cleanup before continuing with the main sync loop - this._parseStack.state = ParserStackType.NONE; - start = this._parseStack.chunkPos + 1; - this.precedingJoinState = 0; - this.currentState = this._parseStack.transition & TableAccess.TRANSITION_STATE_MASK; - } - } - - // continue with main sync loop - - // process input string - for (let i = start; i < length; ++i) { - code = data[i]; - - // EXE fast-path: common control bytes (0x00-0x17) in non-payload states - if (code < 0x18 && this.currentState <= ParserState.CSI_IGNORE) { - (this._executeHandlersArr[code] ?? this._executeHandlerFb)(code); - this.precedingJoinState = 0; - continue; - } - - // CSI fast-path: collapse ESC [ into a single entry, parse params+final in a tight loop - if (code === 0x1b - && this.currentState < ParserState.OSC_STRING - && i + 2 < length && data[i + 1] === 0x5b - ) { - this._params.resetZdm(); - this._collect = 0; - let k = i + 2; - let ch = data[k]; - if (ch >= 0x3c && ch <= 0x3f) { - this._collect = ch; - k++; - } - let csiDone = false; - for (; k < length; k++) { - ch = data[k]; - if (ch >= 0x30 && ch <= 0x39) { - this._params.addDigit(ch - 48); - } else if (ch === 0x3b) { - this._params.addParam(0); - } else if (ch === 0x3a) { - this._params.addSubParam(-1); - } else if (ch >= 0x40 && ch <= 0x7e) { - const handlers = this._csiHandlers[this._collect << 8 | ch]; - let j = handlers ? handlers.length - 1 : -1; - for (; j >= 0; j--) { - handlerResult = handlers[j](this._params); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - transition = ParserAction.CSI_DISPATCH << TableAccess.TRANSITION_ACTION_SHIFT | ParserState.GROUND; - this._preserveStack(ParserStackType.CSI, handlers, j, transition, k); - return handlerResult; - } - } - if (j < 0) { - this._csiHandlerFb(this._collect << 8 | ch, this._params); - } - this.precedingJoinState = 0; - i = k; - this.currentState = ParserState.GROUND; - csiDone = true; - break; - } else { - break; - } - } - if (!csiDone) { - i = k - 1; - this.currentState = ParserState.CSI_PARAM; - } - continue; - } - - // normal transition & action lookup - transition = this._transitions.table[ - this.currentState << TableAccess.INDEX_STATE_SHIFT | - (code < NON_ASCII_PRINTABLE ? code : NON_ASCII_PRINTABLE) - ]; - switch (transition >> TableAccess.TRANSITION_ACTION_SHIFT) { - case ParserAction.PRINT: - // Note: 0x20 (SP) is included, 0x7F (DEL) is excluded - let c = i; - const l4 = length - 4; - while (c < l4 - && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE) - && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE) - && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE) - && data[++c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE) - ) {} - if (c >= l4) { - while (c < length && data[c] >= 0x20 && (data[c] <= 0x7e || data[c] >= NON_ASCII_PRINTABLE)) { - c++; - } - } - this._printHandler(data, i, c); - i = c - 1; - break; - case ParserAction.EXECUTE: - if (this._executeHandlers[code]) this._executeHandlers[code](); - else this._executeHandlerFb(code); - this.precedingJoinState = 0; - break; - case ParserAction.IGNORE: - break; - case ParserAction.ERROR: - const inject: IParsingState = this._errorHandler( - { - position: i, - code, - currentState: this.currentState, - collect: this._collect, - params: this._params, - abort: false - }); - if (inject.abort) return; - // inject values: currently not implemented - break; - case ParserAction.CSI_DISPATCH: - // Trigger CSI Handler - const handlers = this._csiHandlers[this._collect << 8 | code]; - let j = handlers ? handlers.length - 1 : -1; - for (; j >= 0; j--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing - handlerResult = handlers[j](this._params); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._preserveStack(ParserStackType.CSI, handlers, j, transition, i); - return handlerResult; - } - } - if (j < 0) { - this._csiHandlerFb(this._collect << 8 | code, this._params); - } - this.precedingJoinState = 0; - break; - case ParserAction.PARAM: - // inner loop: digits (0x30 - 0x39) and ; (0x3b) and : (0x3a) - do { - switch (code) { - case 0x3b: - this._params.addParam(0); // ZDM - break; - case 0x3a: - this._params.addSubParam(-1); - break; - default: // 0x30 - 0x39 - this._params.addDigit(code - 48); - } - } while (++i < length && (code = data[i]) > 0x2f && code < 0x3c); - i--; - break; - case ParserAction.COLLECT: - this._collect <<= 8; - this._collect |= code; - break; - case ParserAction.ESC_DISPATCH: - const handlersEsc = this._escHandlers[this._collect << 8 | code]; - let jj = handlersEsc ? handlersEsc.length - 1 : -1; - for (; jj >= 0; jj--) { - // true means success and to stop bubbling - // a promise indicates an async handler that needs to finish before progressing - handlerResult = handlersEsc[jj](); - if (handlerResult === true) { - break; - } else if (handlerResult instanceof Promise) { - this._preserveStack(ParserStackType.ESC, handlersEsc, jj, transition, i); - return handlerResult; - } - } - if (jj < 0) { - this._escHandlerFb(this._collect << 8 | code); - } - this.precedingJoinState = 0; - break; - case ParserAction.CLEAR: - this._params.resetZdm(); - this._collect = 0; - break; - case ParserAction.DCS_HOOK: - this._dcsParser.hook(this._collect << 8 | code, this._params); - break; - case ParserAction.DCS_PUT: - // inner loop - exit DCS_PUT: 0x18, 0x1a, 0x1b, 0x7f, 0x80 - 0x9f - // unhook triggered by: 0x1b, 0x9c (success) and 0x18, 0x1a (abort) - for (let j = i + 1; ; ++j) { - if (j >= length || (code = data[j]) === 0x18 || code === 0x1a || code === 0x1b || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { - this._dcsParser.put(data, i, j); - i = j - 1; - break; - } - } - break; - case ParserAction.DCS_UNHOOK: - handlerResult = this._dcsParser.unhook(code !== 0x18 && code !== 0x1a); - if (handlerResult) { - this._preserveStack(ParserStackType.DCS, [], 0, transition, i); - return handlerResult; - } - if (code === 0x1b) transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - this.precedingJoinState = 0; - break; - case ParserAction.OSC_START: - this._oscParser.start(); - break; - case ParserAction.OSC_PUT: - // inner loop: 0x20 (SP) included, 0x7F (DEL) included - for (let j = i + 1; ; j++) { - if (j >= length || (code = data[j]) < 0x20 || (code > 0x7f && code < NON_ASCII_PRINTABLE)) { - this._oscParser.put(data, i, j); - i = j - 1; - break; - } - } - break; - case ParserAction.OSC_END: - handlerResult = this._oscParser.end(code !== 0x18 && code !== 0x1a); - if (handlerResult) { - this._preserveStack(ParserStackType.OSC, [], 0, transition, i); - return handlerResult; - } - if (code === 0x1b) transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - this.precedingJoinState = 0; - break; - case ParserAction.APC_START: - this._apcParser.start(this._collect << 8 | code); - break; - case ParserAction.APC_PUT: - // inner loop - exit APC_PUT: 0x18, 0x1a, 0x1b, 0x9c - // allowed: 00/08 .. 00/13, 02/00 .. 07/14 + NON_ASCII_PRINTABLE - for (let j = i + 1; ; ++j) { - if (j < length && ( - (data[j] >= 0x20 && data[j] < 0x7f) || (data[j] >= 0x08 && data[j] < 0x0e) || data[j] >= NON_ASCII_PRINTABLE - )) continue; - this._apcParser.put(data, i, j); - i = j - 1; - break; - } - break; - case ParserAction.APC_END: - handlerResult = this._apcParser.end(code !== 0x18 && code !== 0x1a); - if (handlerResult) { - this._preserveStack(ParserStackType.APC, [], 0, transition, i); - return handlerResult; - } - if (code === 0x1b) transition |= ParserState.ESCAPE; - this._params.resetZdm(); - this._collect = 0; - this.precedingJoinState = 0; - break; - } - this.currentState = transition & TableAccess.TRANSITION_STATE_MASK; - } + return parseWithWasmScanner(this as unknown as import('./EscapeSequenceParserWasm').IWasmParseHost, data, length, promiseResult, this._scanCache); } } diff --git a/src/common/parser/EscapeSequenceParserWasm.ts b/src/common/parser/EscapeSequenceParserWasm.ts new file mode 100644 index 000000000..449e8d65f --- /dev/null +++ b/src/common/parser/EscapeSequenceParserWasm.ts @@ -0,0 +1,349 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ParserState } from './Constants'; +import { Params } from './Params'; +import { Op, ScanResult } from './ScanTypes'; +import { WasmEscapeScanner } from './WasmEscapeScanner'; +import { + CsiHandlerType, + EscHandlerType, + IParams, + IParsingState, + IParserStackState, + ParserStackType, + ResumableHandlersType +} from './Types'; + +export interface IWasmParseHost { + currentState: number; + collect: number; + precedingJoinState: number; + readonly _params: Params; + readonly _parseStack: IParserStackState; + readonly _csiHandlers: { [ident: number]: CsiHandlerType[] | undefined }; + readonly _escHandlers: { [ident: number]: EscHandlerType[] | undefined }; + readonly _executeHandlers: { [flag: number]: (() => void) | undefined }; + readonly _executeHandlersArr: Array<((code: number) => void) | undefined>; + _csiHandlerFb(ident: number, params: IParams): void; + _escHandlerFb(ident: number): void; + _executeHandlerFb(code: number): void; + _printHandler(data: Uint32Array, start: number, end: number): void; + _oscParser: { start(): void; put(data: Uint32Array, start: number, end: number): void; end(success: boolean, promiseResult?: boolean): void | Promise }; + _dcsParser: { hook(ident: number, params: IParams): void; put(data: Uint32Array, start: number, end: number): void; unhook(success: boolean, promiseResult?: boolean): void | Promise }; + _apcParser: { start(ident: number): void; put(data: Uint32Array, start: number, end: number): void; end(success: boolean, promiseResult?: boolean): void | Promise }; + _preserveStack(state: ParserStackType, handlers: ResumableHandlersType, handlerPos: number, transition: number, chunkPos: number): void; + _errorHandler(state: IParsingState): IParsingState; +} + +let wasmReady = false; + +function ensureWasm(): void { + if (!wasmReady) { + WasmEscapeScanner.initSync(); + wasmReady = true; + } +} + +function loadParams(host: IWasmParseHost, scan: ScanResult, opIndex: number): void { + const start = scan.paramStarts[opIndex] ?? 0; + const count = scan.paramCounts[opIndex] ?? 0; + if (count === 0) { + host._params.resetZdm(); + return; + } + let idx = start; + host._params.resetZdm(); + for (let p = 0; p < count; p++) { + const main = scan.params[idx++] | 0; + if (p === 0) { + host._params.params[0] = main; + host._params.length = 1; + } else { + host._params.addParam(main); + } + while (idx < scan.params.length && (scan.params[idx] & 0x80000000) !== 0) { + const sv = scan.params[idx++] & 0x7FFFFFFF; + host._params.addSubParam(sv === 0x7FFFFFFF ? -1 : sv); + } + } +} + +export function parseWithWasmScanner( + host: IWasmParseHost, + data: Uint32Array, + length: number, + promiseResult: boolean | undefined, + scanCache: { scan?: ScanResult; data?: Uint32Array; opIndex: number; stateBeforeScan?: number } +): void | Promise { + ensureWasm(); + + // Resume async handler dispatch without rescanning + if (host._parseStack.state) { + return resumeWasmParse(host, data, length, promiseResult, scanCache); + } + + const stateBeforeScan = host.currentState; + scanCache.stateBeforeScan = stateBeforeScan; + WasmEscapeScanner.syncParserState(host.currentState, host.collect, host._params); + const scan = WasmEscapeScanner.scan(data, length); + scanCache.scan = scan; + scanCache.data = data; + scanCache.opIndex = 0; + + host.currentState = WasmEscapeScanner.currentState; + host.collect = WasmEscapeScanner.collect; + + return dispatchScanOps(host, data, scan, 0, scanCache, promiseResult, stateBeforeScan); +} + +function resumeWasmParse( + host: IWasmParseHost, + data: Uint32Array, + length: number, + promiseResult: boolean | undefined, + scanCache: { scan?: ScanResult; data?: Uint32Array; opIndex: number; stateBeforeScan?: number } +): void | Promise { + if (host._parseStack.state === ParserStackType.RESET) { + host._parseStack.state = ParserStackType.NONE; + scanCache.opIndex = host._parseStack.chunkPos + 1; + host._parseStack.chunkPos = 0; + if (!scanCache.scan || scanCache.data !== data) { + return parseWithWasmScanner(host, data, length, promiseResult, scanCache); + } + return dispatchScanOps(host, data, scanCache.scan, scanCache.opIndex, scanCache, promiseResult, scanCache.stateBeforeScan ?? host.currentState); + } + + if (promiseResult === undefined || host._parseStack.state === ParserStackType.FAIL) { + host._parseStack.state = ParserStackType.FAIL; + throw new Error('improper continuation due to previous async handler, giving up parsing'); + } + + const handlers = host._parseStack.handlers; + let handlerPos = host._parseStack.handlerPos - 1; + let handlerResult: void | boolean | Promise; + const scan = scanCache.scan; + const opIndex = scanCache.opIndex; + + if (!scan) { + throw new Error('missing scan cache on wasm parser resume'); + } + + switch (host._parseStack.state) { + case ParserStackType.CSI: + if (promiseResult === false && handlerPos > -1) { + for (; handlerPos >= 0; handlerPos--) { + handlerResult = (handlers as CsiHandlerType[])[handlerPos](host._params); + if (handlerResult === true) break; + if (handlerResult instanceof Promise) { + host._parseStack.handlerPos = handlerPos; + return handlerResult; + } + } + } + host._parseStack.handlers = []; + scanCache.opIndex = opIndex + 1; + break; + case ParserStackType.ESC: + if (promiseResult === false && handlerPos > -1) { + for (; handlerPos >= 0; handlerPos--) { + handlerResult = (handlers as EscHandlerType[])[handlerPos](); + if (handlerResult === true) break; + if (handlerResult instanceof Promise) { + host._parseStack.handlerPos = handlerPos; + return handlerResult; + } + } + } + host._parseStack.handlers = []; + scanCache.opIndex = opIndex + 1; + break; + case ParserStackType.DCS: { + const code = data[host._parseStack.chunkPos]; + handlerResult = host._dcsParser.unhook(code !== 0x18 && code !== 0x1a, promiseResult); + if (handlerResult) return handlerResult; + if (code === 0x1b) host.currentState = ParserState.ESCAPE; + host._params.resetZdm(); + host.collect = 0; + scanCache.opIndex = opIndex + 1; + break; + } + case ParserStackType.OSC: { + const code = data[host._parseStack.chunkPos]; + handlerResult = host._oscParser.end(code !== 0x18 && code !== 0x1a, promiseResult); + if (handlerResult) return handlerResult; + if (code === 0x1b) host.currentState = ParserState.ESCAPE; + host._params.resetZdm(); + host.collect = 0; + scanCache.opIndex = opIndex + 1; + break; + } + case ParserStackType.APC: { + const code = data[host._parseStack.chunkPos]; + handlerResult = host._apcParser.end(code !== 0x18 && code !== 0x1a, promiseResult); + if (handlerResult) return handlerResult; + if (code === 0x1b) host.currentState = ParserState.ESCAPE; + host._params.resetZdm(); + host.collect = 0; + scanCache.opIndex = opIndex + 1; + break; + } + } + + host._parseStack.state = ParserStackType.NONE; + host.precedingJoinState = 0; + return dispatchScanOps(host, data, scan, scanCache.opIndex, scanCache, promiseResult, scanCache.stateBeforeScan ?? host.currentState); +} + +function dispatchScanOps( + host: IWasmParseHost, + data: Uint32Array, + scan: ScanResult, + fromOp: number, + scanCache: { scan?: ScanResult; data?: Uint32Array; opIndex: number }, + promiseResult: boolean | undefined, + stateBeforeScan: number +): void | Promise { + let handlerResult: void | boolean | Promise; + + for (let o = fromOp; o < scan.opCount; o++) { + scanCache.opIndex = o; + const kind = scan.kinds[o]; + const start = scan.starts[o]; + const len = scan.lengths[o]; + const aux = scan.aux[o]; + const chunkPos = (kind === Op.Csi || kind === Op.Esc) ? len : start; + + switch (kind) { + case Op.Print: + host._printHandler(data, start, start + len); + break; + case Op.Execute: { + const code = aux; + if (code < 0x18) { + const exe = host._executeHandlersArr[code]; + if (exe) exe(code); + else host._executeHandlerFb(code); + } else if (host._executeHandlers[code]) { + host._executeHandlers[code]!(); + } else { + host._executeHandlerFb(code); + } + host.precedingJoinState = 0; + break; + } + case Op.Csi: { + host.collect = aux >> 8; + loadParams(host, scan, o); + const handlers = host._csiHandlers[aux]; + let j = handlers ? handlers.length - 1 : -1; + for (; j >= 0; j--) { + handlerResult = handlers![j](host._params); + if (handlerResult === true) break; + if (handlerResult instanceof Promise) { + host._preserveStack(ParserStackType.CSI, handlers!, j, 0, chunkPos); + return handlerResult; + } + } + if (j < 0) host._csiHandlerFb(aux, host._params); + host.precedingJoinState = 0; + break; + } + case Op.Esc: { + host.collect = aux >> 8; + loadParams(host, scan, o); + const handlersEsc = host._escHandlers[aux]; + let jj = handlersEsc ? handlersEsc.length - 1 : -1; + for (; jj >= 0; jj--) { + handlerResult = handlersEsc![jj](); + if (handlerResult === true) break; + if (handlerResult instanceof Promise) { + host._preserveStack(ParserStackType.ESC, handlersEsc!, jj, 0, chunkPos); + return handlerResult; + } + } + if (jj < 0) host._escHandlerFb(aux); + host.precedingJoinState = 0; + break; + } + case Op.OscStart: + host._oscParser.start(); + break; + case Op.OscPut: + if (len > 0) host._oscParser.put(data, start, start + len); + break; + case Op.OscEnd: { + const term = aux; + handlerResult = host._oscParser.end(term !== 0x18 && term !== 0x1a); + if (handlerResult) { + host._preserveStack(ParserStackType.OSC, [], 0, 0, start); + return handlerResult; + } + if (term === 0x1b) host.currentState = ParserState.ESCAPE; + host._params.resetZdm(); + host.collect = 0; + host.precedingJoinState = 0; + break; + } + case Op.DcsHook: { + host.collect = aux >> 8; + loadParams(host, scan, o); + host._dcsParser.hook(aux, host._params); + break; + } + case Op.DcsPut: + if (len > 0) host._dcsParser.put(data, start, start + len); + break; + case Op.DcsUnhook: { + const term = aux; + handlerResult = host._dcsParser.unhook(term !== 0x18 && term !== 0x1a); + if (handlerResult) { + host._preserveStack(ParserStackType.DCS, [], 0, 0, start); + return handlerResult; + } + host._params.resetZdm(); + host.collect = 0; + host.precedingJoinState = 0; + break; + } + case Op.ApcStart: + host._apcParser.start(aux); + break; + case Op.ApcPut: + if (len > 0) host._apcParser.put(data, start, start + len); + break; + case Op.ApcEnd: { + const term = aux; + handlerResult = host._apcParser.end(term !== 0x18 && term !== 0x1a); + if (handlerResult) { + host._preserveStack(ParserStackType.APC, [], 0, 0, start); + return handlerResult; + } + host._params.resetZdm(); + host.collect = 0; + host.precedingJoinState = 0; + break; + } + case Op.Error: { + WasmEscapeScanner.exportParamsTo(host._params); + const inject = host._errorHandler({ + position: start, + code: aux & 0xFFFF, + currentState: aux >> 16, + collect: WasmEscapeScanner.collect, + params: host._params, + abort: false + }); + if (inject.abort) return; + break; + } + } + } + + scanCache.opIndex = scan.opCount; + host.currentState = WasmEscapeScanner.currentState; + host.collect = WasmEscapeScanner.collect; + WasmEscapeScanner.exportParamsTo(host._params); +} diff --git a/src/common/parser/ScanTypes.ts b/src/common/parser/ScanTypes.ts new file mode 100644 index 000000000..9df9989a4 --- /dev/null +++ b/src/common/parser/ScanTypes.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +export const Op = { + Print: 0, + Execute: 1, + Esc: 2, + Csi: 3, + Osc: 4, + Dcs: 5, + Apc: 6, + DcsHook: 7, + DcsPut: 8, + DcsUnhook: 9, + OscStart: 10, + OscPut: 11, + OscEnd: 12, + ApcStart: 13, + ApcPut: 14, + ApcEnd: 15, + Error: 16 +} as const; + +export type OpKind = typeof Op[keyof typeof Op]; + +export type ScanResult = { + kinds: Uint8Array; + starts: Uint32Array; + lengths: Uint32Array; + aux: Uint32Array; + params: Uint32Array; + paramStarts: Uint32Array; + paramCounts: Uint16Array; + opCount: number; +}; diff --git a/src/common/parser/WasmEscapeScanner.test.ts b/src/common/parser/WasmEscapeScanner.test.ts new file mode 100644 index 000000000..e2ab2b6bd --- /dev/null +++ b/src/common/parser/WasmEscapeScanner.test.ts @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { StringToUtf32 } from '../input/TextDecoder'; +import { Op } from './ScanTypes'; +import { WasmEscapeScanner } from './WasmEscapeScanner'; + +describe('WasmEscapeScanner', () => { + before(() => { + WasmEscapeScanner.initSync(); + }); + + beforeEach(() => { + WasmEscapeScanner.reset(); + }); + + it('scans hello with SGR sequences', () => { + const input = 'hello\x1b[31mred\x1b[0m'; + const data = new Uint32Array(input.length); + const len = new StringToUtf32().decode(input, data); + const scan = WasmEscapeScanner.scan(data, len); + + assert.equal(scan.opCount, 4); + assert.deepEqual(Array.from(scan.kinds), [Op.Print, Op.Csi, Op.Print, Op.Csi]); + assert.deepEqual(Array.from(scan.starts), [0, 0, 10, 1]); + // CSI/ESC: lengths hold final-byte index; print ops use run length + assert.deepEqual(Array.from(scan.lengths), [5, 9, 3, 16]); + assert.deepEqual(Array.from(scan.aux), [0, 'm'.charCodeAt(0), 0, 'm'.charCodeAt(0)]); + assert.deepEqual(Array.from(scan.paramStarts), [0, 0, 0, 1]); + assert.deepEqual(Array.from(scan.paramCounts), [0, 1, 0, 1]); + assert.deepEqual(Array.from(scan.params), [31, 0]); + }); +}); diff --git a/src/common/parser/WasmEscapeScanner.ts b/src/common/parser/WasmEscapeScanner.ts new file mode 100644 index 000000000..fca504f3d --- /dev/null +++ b/src/common/parser/WasmEscapeScanner.ts @@ -0,0 +1,207 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Params } from './Params'; +import { Op, ScanResult } from './ScanTypes'; +import { PARSER_WASM_BASE64 } from './wasm/parser.wasm.embed'; + +export { Op }; + +const WASM_IMPORTS = { + env: { + memory: new WebAssembly.Memory({ initial: 1024, maximum: 1024 }) + } +}; + +let wasmModule: WebAssembly.Instance | undefined; +let wasmExports: { + memory: WebAssembly.Memory; + reset: () => void; + scan: (length: number) => number; + set_state: (state: number, collect: number) => void; + get_input_ptr: () => number; + get_kinds_ptr: () => number; + get_starts_ptr: () => number; + get_lengths_ptr: () => number; + get_aux_ptr: () => number; + get_param_starts_ptr: () => number; + get_param_counts_ptr: () => number; + get_params_ptr: () => number; + get_state_ptr: () => number; + get_header_ptr: () => number; + sync_params_from: (srcPtr: number, len: number) => void; + export_params_to: (dstPtr: number, maxLen: number) => void; + get_params_len: () => number; + get_subparams_len: () => number; + get_subparams_ptr: () => number; + get_subparams_idx_ptr: () => number; +}; + +async function initWasm(): Promise { + if (wasmModule) return; + const bytes = Uint8Array.from(atob(PARSER_WASM_BASE64), c => c.charCodeAt(0)); + const mod = await WebAssembly.instantiate(bytes, WASM_IMPORTS); + wasmModule = mod.instance; + wasmExports = wasmModule.exports as typeof wasmExports; +} + +function ensureWasm(): typeof wasmExports { + if (!wasmExports) { + throw new Error('WasmEscapeScanner not initialized. Call WasmEscapeScanner.init() first.'); + } + return wasmExports; +} + +export class WasmEscapeScanner { + private static _initPromise: Promise | undefined; + private static _syncReady = false; + + public static init(): Promise { + if (!this._initPromise) { + this._initPromise = initWasm().then(() => { + this._syncReady = true; + wasmExports.reset(); + }); + } + return this._initPromise; + } + + /** Synchronous init for unit tests (Node supports sync instantiate). */ + public static initSync(): void { + if (this._syncReady) return; + const binary = globalThis.atob(PARSER_WASM_BASE64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i); + const mod = new WebAssembly.Module(bytes); + wasmModule = new WebAssembly.Instance(mod, WASM_IMPORTS); + wasmExports = wasmModule.exports as typeof wasmExports; + wasmExports.reset(); + this._syncReady = true; + } + + public static reset(): void { + ensureWasm().reset(); + } + + public static get currentState(): number { + const mem = new Uint32Array(ensureWasm().memory.buffer); + const statePtr = ensureWasm().get_state_ptr() >> 2; + return mem[statePtr]; + } + + public static set currentState(value: number) { + const ex = ensureWasm(); + const mem = new Uint32Array(ex.memory.buffer); + const statePtr = ex.get_state_ptr() >> 2; + ex.set_state(value, mem[statePtr + 1]); + } + + public static get collect(): number { + const mem = new Uint32Array(ensureWasm().memory.buffer); + return mem[(ensureWasm().get_state_ptr() >> 2) + 1]; + } + + public static set collect(value: number) { + const ex = ensureWasm(); + ex.set_state(memState(ex), value); + } + + public static syncParserState(currentState: number, collect: number, params: Params): void { + const ex = ensureWasm(); + ex.set_state(currentState, collect); + if (params.length === 0) { + ex.sync_params_from(ex.get_params_ptr(), 0); + return; + } + const mem = ex.memory.buffer; + const paramsPtr = ex.get_params_ptr(); + const view = new Int32Array(mem, paramsPtr, params.length); + for (let i = 0; i < params.length; i++) { + view[i] = params.params[i]; + } + ex.sync_params_from(paramsPtr, params.length); + } + + public static exportParamsTo(params: Params): void { + const ex = ensureWasm(); + const len = ex.get_params_len(); + params.reset(); + if (len === 0) { + params.resetZdm(); + return; + } + const mem = ex.memory.buffer; + const dstPtr = ex.get_params_ptr(); + ex.export_params_to(dstPtr, len); + const pView = new Int32Array(mem, dstPtr, len); + const subLen = ex.get_subparams_len(); + const subView = subLen > 0 ? new Int32Array(mem, ex.get_subparams_ptr(), subLen) : undefined; + const idxView = new Uint16Array(mem, ex.get_subparams_idx_ptr(), len); + + params.resetZdm(); + params.params[0] = pView[0]; + params.length = 1; + if (subView && len > 0) { + const start0 = idxView[0] >> 8; + const end0 = idxView[0] & 0xFF; + for (let k = start0; k < end0; k++) { + params.addSubParam(subView[k]); + } + } + for (let i = 1; i < len; i++) { + params.addParam(pView[i]); + if (subView) { + const start = idxView[i] >> 8; + const end = idxView[i] & 0xFF; + for (let k = start; k < end; k++) { + params.addSubParam(subView[k]); + } + } + } + } + + public static scan(data: Uint32Array, length: number): ScanResult { + const ex = ensureWasm(); + const inputPtr = ex.get_input_ptr(); + const mem = ex.memory.buffer; + const inputView = new Uint32Array(mem, inputPtr, length); + inputView.set(data.subarray(0, length)); + + const opCount = ex.scan(length); + if (opCount < 0) { + throw new Error('Wasm parser op buffer overflow'); + } + + const count = opCount; + const kinds = new Uint8Array(mem, ex.get_kinds_ptr(), count); + const starts = new Uint32Array(mem, ex.get_starts_ptr(), count); + const lengths = new Uint32Array(mem, ex.get_lengths_ptr(), count); + const aux = new Uint32Array(mem, ex.get_aux_ptr(), count); + const paramStarts = new Uint32Array(mem, ex.get_param_starts_ptr(), count); + const paramCounts = new Uint16Array(mem, ex.get_param_counts_ptr(), count); + + const headerPtr = ex.get_header_ptr() >> 2; + const headerView = new Uint32Array(mem, ex.get_header_ptr(), 3); + const paramsLen = headerView[2]; + + const params = new Uint32Array(mem, ex.get_params_ptr(), paramsLen); + + return { + kinds: kinds.slice(), + starts: starts.slice(), + lengths: lengths.slice(), + aux: aux.slice(), + params: params.slice(), + paramStarts: paramStarts.slice(), + paramCounts: paramCounts.slice(), + opCount: count + }; + } +} + +function memState(ex: typeof wasmExports): number { + const mem = new Uint32Array(ex.memory.buffer); + return mem[ex.get_state_ptr() >> 2]; +} diff --git a/src/common/parser/wasm/parser.c b/src/common/parser/wasm/parser.c new file mode 100644 index 000000000..88cfdb23d --- /dev/null +++ b/src/common/parser/wasm/parser.c @@ -0,0 +1,441 @@ +/* Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT */ + +#include "parser.h" +#include "transition_table.h" +#include + +/* Place scratch memory above static data (transition table ~8.5KB in linear memory 0) */ +#define MEM_BASE 65536 +#define MEM_STATE MEM_BASE +/* ParserWasmState is ~2.3KB; keep header and op buffers past it */ +#define MEM_HEADER (MEM_STATE + 2048) +#define MEM_KINDS (MEM_HEADER + 64) +#define MEM_STARTS (MEM_KINDS + PARSER_MAX_OPS) +#define MEM_LENGTHS (MEM_STARTS + PARSER_MAX_OPS * 4) +#define MEM_AUX (MEM_LENGTHS + PARSER_MAX_OPS * 4) +#define MEM_PARAM_STARTS (MEM_AUX + PARSER_MAX_OPS * 4) +#define MEM_PARAM_COUNTS (MEM_PARAM_STARTS + PARSER_MAX_OPS * 4) +#define MEM_PARAMS_ARENA (MEM_PARAM_COUNTS + PARSER_MAX_OPS * 2) /* uint16 param counts */ +#define MEM_INPUT_BASE (MEM_PARAMS_ARENA + PARSER_MAX_PARAMS * 4) + +static ParserWasmState *state(void) { return (ParserWasmState *)(uintptr_t)MEM_STATE; } +static ParserScanHeader *header(void) { return (ParserScanHeader *)(uintptr_t)MEM_HEADER; } +static uint8_t *kinds(void) { return (uint8_t *)(uintptr_t)MEM_KINDS; } +static uint32_t *starts(void) { return (uint32_t *)(uintptr_t)MEM_STARTS; } +static uint32_t *lengths(void) { return (uint32_t *)(uintptr_t)MEM_LENGTHS; } +static uint32_t *aux(void) { return (uint32_t *)(uintptr_t)MEM_AUX; } +static uint32_t *param_starts(void) { return (uint32_t *)(uintptr_t)MEM_PARAM_STARTS; } +static uint16_t *param_counts(void) { return (uint16_t *)(uintptr_t)MEM_PARAM_COUNTS; } +static int32_t *params_arena(void) { return (int32_t *)(uintptr_t)MEM_PARAMS_ARENA; } +static uint32_t *input(void) { return (uint32_t *)(uintptr_t)MEM_INPUT_BASE; } + +static uint32_t transition_lookup(uint32_t st, uint32_t code) { + uint32_t idx = code < PARSER_NON_ASCII_PRINTABLE ? code : PARSER_NON_ASCII_PRINTABLE; + return PARSER_TRANSITION_TABLE[st << PARSER_TABLE_INDEX_STATE_SHIFT | idx]; +} + +static void params_reset_zdm(ParserWasmState *s) { + s->params_len = 1; + s->subparams_len = 0; + s->reject_digits = 0; + s->reject_sub_digits = 0; + s->digit_is_sub = 0; + s->subparams_idx[0] = 0; + s->params[0] = 0; +} + +static void params_reset(ParserWasmState *s) { + s->params_len = 0; + s->subparams_len = 0; + s->reject_digits = 0; + s->reject_sub_digits = 0; + s->digit_is_sub = 0; +} + +static void params_add_param(ParserWasmState *s, int32_t value) { + s->digit_is_sub = 0; + if (s->params_len >= PARSER_PARAMS_MAX_LEN) { + s->reject_digits = 1; + return; + } + s->subparams_idx[s->params_len] = (uint16_t)(s->subparams_len << 8 | s->subparams_len); + if (value < 0) value = 0; + if (value > 0x7FFFFFFF) value = 0x7FFFFFFF; + s->params[s->params_len++] = value; +} + +static void params_add_subparam(ParserWasmState *s, int32_t value) { + s->digit_is_sub = 1; + if (!s->params_len) return; + if (s->reject_digits || s->subparams_len >= PARSER_SUBPARAMS_MAX_LEN) { + s->reject_sub_digits = 1; + return; + } + if (value < 0) value = -1; + if (value > 0x7FFFFFFF) value = 0x7FFFFFFF; + s->subparams[s->subparams_len++] = value; + s->subparams_idx[s->params_len - 1]++; +} + +static void params_add_digit(ParserWasmState *s, int32_t digit) { + uint32_t len; + if (s->reject_digits) return; + len = s->digit_is_sub ? s->subparams_len : s->params_len; + if (!len) return; + if (s->digit_is_sub && s->reject_sub_digits) return; + int32_t *store = s->digit_is_sub ? s->subparams : s->params; + int32_t cur = store[len - 1]; + store[len - 1] = cur >= 0 ? (cur * 10 + digit > 0x7FFFFFFF ? 0x7FFFFFFF : cur * 10 + digit) : digit; +} + +static void copy_params_to_arena(uint32_t op_idx, ParserWasmState *s) { + uint32_t start = header()->params_arena_len; + param_starts()[op_idx] = start; + param_counts()[op_idx] = (uint16_t)s->params_len; + for (uint32_t i = 0; i < s->params_len; i++) { + if (header()->params_arena_len >= PARSER_MAX_PARAMS) return; + params_arena()[header()->params_arena_len++] = s->params[i]; + uint16_t idx = s->subparams_idx[i]; + uint32_t sub_start = idx >> 8; + uint32_t sub_end = idx & 0xFF; + for (uint32_t k = sub_start; k < sub_end; k++) { + if (header()->params_arena_len >= PARSER_MAX_PARAMS) return; + int32_t sv = s->subparams[k]; + uint32_t encoded = 0x80000000u | (uint32_t)(sv < 0 ? 0x7FFFFFFF : sv); + params_arena()[header()->params_arena_len++] = encoded; + } + } +} + +static int emit_op(uint8_t kind, uint32_t start, uint32_t length, uint32_t aux_val, ParserWasmState *s) { + uint32_t idx = header()->op_count; + if (idx >= PARSER_MAX_OPS) return -1; + kinds()[idx] = kind; + starts()[idx] = start; + lengths()[idx] = length; + aux()[idx] = aux_val; + if (kind == OP_CSI || kind == OP_ESC || kind == OP_DCS_HOOK) { + uint32_t input_pos = start; + copy_params_to_arena(idx, s); + lengths()[idx] = input_pos; + starts()[idx] = param_starts()[idx]; + } else { + param_starts()[idx] = 0; + param_counts()[idx] = 0; + } + header()->op_count++; + return (int)idx; +} + +static int is_printable(uint32_t code) { + return (code >= 0x20 && code <= 0x7e) || code >= PARSER_NON_ASCII_PRINTABLE; +} + +__attribute__((export_name("reset"))) +void reset(void) { + ParserWasmState *s = state(); + s->current_state = PARSER_STATE_GROUND; + s->collect = 0; + s->preceding_join_state = 0; + s->osc_start = 0; + s->dcs_start = 0; + s->apc_start = 0; + params_reset_zdm(s); + header()->op_count = 0; + header()->input_len = 0; + header()->params_arena_len = 0; +} + +__attribute__((export_name("get_input_ptr"))) +uint32_t get_input_ptr(void) { return MEM_INPUT_BASE; } + +__attribute__((export_name("get_kinds_ptr"))) +uint32_t get_kinds_ptr(void) { return MEM_KINDS; } + +__attribute__((export_name("get_starts_ptr"))) +uint32_t get_starts_ptr(void) { return MEM_STARTS; } + +__attribute__((export_name("get_lengths_ptr"))) +uint32_t get_lengths_ptr(void) { return MEM_LENGTHS; } + +__attribute__((export_name("get_aux_ptr"))) +uint32_t get_aux_ptr(void) { return MEM_AUX; } + +__attribute__((export_name("get_param_starts_ptr"))) +uint32_t get_param_starts_ptr(void) { return MEM_PARAM_STARTS; } + +__attribute__((export_name("get_param_counts_ptr"))) +uint32_t get_param_counts_ptr(void) { return MEM_PARAM_COUNTS; } + +__attribute__((export_name("get_params_ptr"))) +uint32_t get_params_ptr(void) { return MEM_PARAMS_ARENA; } + +__attribute__((export_name("get_state_ptr"))) +uint32_t get_state_ptr(void) { return MEM_STATE; } + +__attribute__((export_name("get_header_ptr"))) +uint32_t get_header_ptr(void) { return MEM_HEADER; } + +__attribute__((export_name("set_state"))) +void set_state(uint32_t current_state, uint32_t collect) { + state()->current_state = current_state; + state()->collect = collect; +} + +__attribute__((export_name("export_params_to"))) +void export_params_to(uint32_t dst_ptr, uint32_t max_len) { + ParserWasmState *s = state(); + int32_t *dst = (int32_t *)(uintptr_t)dst_ptr; + uint32_t n = s->params_len < max_len ? s->params_len : max_len; + for (uint32_t i = 0; i < n; i++) { + dst[i] = s->params[i]; + } +} + +__attribute__((export_name("get_params_len"))) +uint32_t get_params_len(void) { + return state()->params_len; +} + +__attribute__((export_name("get_subparams_len"))) +uint32_t get_subparams_len(void) { + return state()->subparams_len; +} + +__attribute__((export_name("get_subparams_ptr"))) +uint32_t get_subparams_ptr(void) { + return (uint32_t)(uintptr_t)state()->subparams; +} + +__attribute__((export_name("get_subparams_idx_ptr"))) +uint32_t get_subparams_idx_ptr(void) { + return (uint32_t)(uintptr_t)state()->subparams_idx; +} + +__attribute__((export_name("sync_params_from"))) +void sync_params_from(uint32_t src_ptr, uint32_t len) { + ParserWasmState *s = state(); + const int32_t *src = (const int32_t *)(uintptr_t)src_ptr; + s->params_len = len > PARSER_PARAMS_MAX_LEN ? PARSER_PARAMS_MAX_LEN : len; + for (uint32_t i = 0; i < s->params_len; i++) { + s->params[i] = src[i]; + } + s->subparams_len = 0; + s->reject_digits = 0; + s->reject_sub_digits = 0; + s->digit_is_sub = 0; +} + +__attribute__((export_name("probe_action"))) +uint32_t probe_action(uint32_t state_id, uint32_t code) { + uint32_t tr = transition_lookup(state_id, code); + return tr >> PARSER_TABLE_ACTION_SHIFT; +} + +__attribute__((export_name("scan"))) +int32_t scan(uint32_t length) { + ParserWasmState *s = state(); + ParserScanHeader *h = header(); + h->op_count = 0; + h->params_arena_len = 0; + h->input_len = length; + uint32_t i = 0; + uint32_t code; + uint32_t transition; + uint32_t action; + uint32_t print_start; + + while (i < length) { + code = input()[i]; + + if (code < 0x18 && s->current_state <= PARSER_STATE_CSI_PARAM + 2) { + if (emit_op(OP_EXECUTE, i, 0, code, s) < 0) return -1; + s->preceding_join_state = 0; + i++; + continue; + } + + if (code == 0x1b && s->current_state < PARSER_STATE_OSC_STRING && i + 2 < length && input()[i + 1] == 0x5b) { + params_reset_zdm(s); + s->collect = 0; + uint32_t k = i + 2; + uint32_t ch = input()[k]; + if (ch >= 0x3c && ch <= 0x3f) { + s->collect = ch; + k++; + } + int csi_done = 0; + for (; k < length; k++) { + ch = input()[k]; + if (ch >= 0x30 && ch <= 0x39) { + params_add_digit(s, ch - 48); + } else if (ch == 0x3b) { + params_add_param(s, 0); + } else if (ch == 0x3a) { + params_add_subparam(s, -1); + } else if (ch >= 0x40 && ch <= 0x7e) { + uint32_t ident = (s->collect << 8) | ch; + if (emit_op(OP_CSI, k, 0, ident, s) < 0) return -1; + s->preceding_join_state = 0; + i = k; + s->current_state = PARSER_STATE_GROUND; + csi_done = 1; + break; + } else { + break; + } + } + if (!csi_done) { + i = k - 1; + s->current_state = PARSER_STATE_CSI_PARAM; + } + i++; + continue; + } + + transition = transition_lookup(s->current_state, code); + action = transition >> PARSER_TABLE_ACTION_SHIFT; + { + uint32_t next_state = transition & PARSER_TABLE_STATE_MASK; + switch (action) { + case 1: /* ERROR - report state before transition (matches TS parser) */ + if (emit_op(OP_ERROR, i, 0, (s->current_state << 16) | code, s) < 0) return -1; + s->current_state = next_state; + break; + default: + s->current_state = next_state; + break; + } + } + + switch (action) { + case PARSER_ACTION_PRINT: { + print_start = i; + uint32_t c = i; + uint32_t l4 = length > 4 ? length - 4 : 0; + while (c < l4 && is_printable(input()[c]) && is_printable(input()[c + 1]) && + is_printable(input()[c + 2]) && is_printable(input()[c + 3])) { + c += 4; + } + while (c < length && is_printable(input()[c])) c++; + if (emit_op(OP_PRINT, print_start, c - print_start, 0, s) < 0) return -1; + i = c - 1; + break; + } + case PARSER_ACTION_EXECUTE: + if (emit_op(OP_EXECUTE, i, 0, code, s) < 0) return -1; + s->preceding_join_state = 0; + break; + case PARSER_ACTION_IGNORE: + break; + case 1: /* ERROR - handled above */ + break; + case PARSER_ACTION_CSI_DISPATCH: { + uint32_t ident = (s->collect << 8) | code; + if (emit_op(OP_CSI, i, 0, ident, s) < 0) return -1; + s->preceding_join_state = 0; + break; + } + case 8: /* PARAM */ + do { + switch (code) { + case 0x3b: params_add_param(s, 0); break; + case 0x3a: params_add_subparam(s, -1); break; + default: params_add_digit(s, code - 48); break; + } + } while (++i < length && (code = input()[i]) > 0x2f && code < 0x3c); + i--; + break; + case 9: /* COLLECT */ + s->collect <<= 8; + s->collect |= code; + break; + case PARSER_ACTION_ESC_DISPATCH: { + uint32_t ident = (s->collect << 8) | code; + if (emit_op(OP_ESC, i, 0, ident, s) < 0) return -1; + s->preceding_join_state = 0; + break; + } + case 11: /* CLEAR */ + params_reset_zdm(s); + s->collect = 0; + break; + case 4: /* OSC_START */ + if (emit_op(OP_OSC_START, i, 0, 0, s) < 0) return -1; + s->osc_start = i + 1; + break; + case 5: /* OSC_PUT */ + for (uint32_t j = i + 1; ; j++) { + if (j >= length || (code = input()[j]) < 0x20 || + (code > 0x7f && code < PARSER_NON_ASCII_PRINTABLE)) { + if (j > i && emit_op(OP_OSC_PUT, i, j - i, 0, s) < 0) return -1; + i = j - 1; + break; + } + } + break; + case PARSER_ACTION_OSC_END: { + if (emit_op(OP_OSC_END, i, 0, code, s) < 0) return -1; + s->osc_term = code; + if (code == 0x1b) s->current_state = PARSER_STATE_ESCAPE; + params_reset_zdm(s); + s->collect = 0; + s->preceding_join_state = 0; + break; + } + case 12: /* DCS_HOOK */ + s->dcs_hook_ident = (s->collect << 8) | code; + if (emit_op(OP_DCS_HOOK, i, 0, s->dcs_hook_ident, s) < 0) return -1; + s->dcs_start = i + 1; + break; + case 13: /* DCS_PUT */ + for (uint32_t j = i + 1; ; j++) { + if (j >= length || (code = input()[j]) == 0x18 || code == 0x1a || code == 0x1b || + (code > 0x7f && code < PARSER_NON_ASCII_PRINTABLE)) { + if (j > i && emit_op(OP_DCS_PUT, i, j - i, 0, s) < 0) return -1; + i = j - 1; + break; + } + } + break; + case PARSER_ACTION_DCS_UNHOOK: { + if (emit_op(OP_DCS_UNHOOK, i, 0, code, s) < 0) return -1; + if (code == 0x1b) s->current_state = PARSER_STATE_ESCAPE; + params_reset_zdm(s); + s->collect = 0; + s->preceding_join_state = 0; + break; + } + case 15: /* APC_START */ + s->apc_hook_ident = (s->collect << 8) | code; + if (emit_op(OP_APC_START, i, 0, s->apc_hook_ident, s) < 0) return -1; + s->apc_start = i + 1; + break; + case 16: /* APC_PUT */ + for (uint32_t j = i + 1; ; j++) { + if (j < length && ( + (input()[j] >= 0x20 && input()[j] < 0x7f) || + (input()[j] >= 0x08 && input()[j] < 0x0e) || + input()[j] >= PARSER_NON_ASCII_PRINTABLE + )) continue; + if (j > i && emit_op(OP_APC_PUT, i, j - i, 0, s) < 0) return -1; + i = j - 1; + break; + } + break; + case PARSER_ACTION_APC_END: { + if (emit_op(OP_APC_END, i, 0, code, s) < 0) return -1; + if (code == 0x1b) s->current_state = PARSER_STATE_ESCAPE; + params_reset_zdm(s); + s->collect = 0; + s->preceding_join_state = 0; + break; + } + default: + break; + } + i++; + } + return (int32_t)h->op_count; +} diff --git a/src/common/parser/wasm/parser.h b/src/common/parser/wasm/parser.h new file mode 100644 index 000000000..c13a29153 --- /dev/null +++ b/src/common/parser/wasm/parser.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ +#ifndef PARSER_WASM_H +#define PARSER_WASM_H + +#include + +#define PARSER_NON_ASCII_PRINTABLE 0xA0 +#define PARSER_TABLE_ACTION_SHIFT 8 +#define PARSER_TABLE_STATE_MASK 255 +#define PARSER_TABLE_INDEX_STATE_SHIFT 8 + +#define OP_PRINT 0 +#define OP_EXECUTE 1 +#define OP_ESC 2 +#define OP_CSI 3 +#define OP_OSC 4 +#define OP_DCS 5 +#define OP_APC 6 +#define OP_DCS_HOOK 7 +#define OP_DCS_PUT 8 +#define OP_DCS_UNHOOK 9 +#define OP_OSC_START 10 +#define OP_OSC_PUT 11 +#define OP_OSC_END 12 +#define OP_APC_START 13 +#define OP_APC_PUT 14 +#define OP_APC_END 15 +#define OP_ERROR 16 + +#define PARSER_STATE_GROUND 0 +#define PARSER_STATE_ESCAPE 1 +#define PARSER_STATE_OSC_STRING 8 +#define PARSER_STATE_DCS_PASSTHROUGH 13 +#define PARSER_STATE_APC_PASSTHROUGH 16 +#define PARSER_STATE_CSI_PARAM 4 + +#define PARSER_ACTION_IGNORE 0 +#define PARSER_ACTION_PRINT 2 +#define PARSER_ACTION_EXECUTE 3 +#define PARSER_ACTION_CSI_DISPATCH 7 +#define PARSER_ACTION_ESC_DISPATCH 10 +#define PARSER_ACTION_OSC_END 6 +#define PARSER_ACTION_DCS_UNHOOK 14 +#define PARSER_ACTION_APC_END 17 + +#define PARSER_MAX_OPS 4096 +#define PARSER_MAX_PARAMS 4096 +#define PARSER_PARAMS_MAX_LEN 32 +#define PARSER_SUBPARAMS_MAX_LEN 256 + +typedef struct { + uint32_t current_state; + uint32_t collect; + uint32_t preceding_join_state; + int32_t params[PARSER_PARAMS_MAX_LEN]; + uint32_t params_len; + int32_t subparams[PARSER_SUBPARAMS_MAX_LEN]; + uint32_t subparams_len; + uint16_t subparams_idx[PARSER_PARAMS_MAX_LEN]; + uint32_t reject_digits; + uint32_t reject_sub_digits; + uint32_t digit_is_sub; + uint32_t osc_start; + uint32_t dcs_start; + uint32_t apc_start; + uint32_t dcs_hook_ident; + uint32_t apc_hook_ident; + uint32_t osc_term; +} ParserWasmState; + +typedef struct { + uint32_t op_count; + uint32_t input_len; + uint32_t params_arena_len; +} ParserScanHeader; + +#endif diff --git a/src/common/parser/wasm/parser.wasm b/src/common/parser/wasm/parser.wasm new file mode 100755 index 000000000..19815c944 Binary files /dev/null and b/src/common/parser/wasm/parser.wasm differ diff --git a/src/common/parser/wasm/parser.wasm.embed.ts b/src/common/parser/wasm/parser.wasm.embed.ts new file mode 100644 index 000000000..29e6ddbce --- /dev/null +++ b/src/common/parser/wasm/parser.wasm.embed.ts @@ -0,0 +1,6 @@ +/** + * Copyright (c) 2026 The xterm.js authors. All rights reserved. + * @license MIT + */ +/** Base64-encoded parser.wasm (generated by bin/build_parser_wasm.sh) */ +export const PARSER_WASM_BASE64 = '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ADsBACAEQcCwB2pBADYCAAtBAEEAKAKAkARBAWo2AoCQBCAFIQQLIAQLC8pCAQBBgAgLwkIAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMBCwADAAMAAwADAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgABAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwACAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQEDAQMBAwEDAQMBAwEDAQMBAwEDAQMBAwEDAQMBAwEDAQMBAwEDAQMBAwEDAQMBAwADAQMAAwELAQMBAwEDAQMCCQIJAgkCCQIJAgkCCQIJAgkCCQIJAgkCCQIJAgkCCQAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoJCwAKAAoACgAKAAoACgAKBwAACgAKAwsACggEBwAOCwAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAQAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwAACAQHAA4LAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAAMCAwADAQsCAwIDAgMCAwIJAgkCCQIJAgkCCQIJAgkCCQIJAgkCCQIJAgkCCQIJAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoCAAADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADCQsAAwADAAMAAwADAAMAAwcAAAMAAwMLAAAIBAcADgsAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAwMDAAMBCwMDAwMDAwMDBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkECAQIBAgECAQIBAgECAQIBAgECAQIBAgECQQJBAkECQAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwMAAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwQDBAMEAwADBAMAAwELBAMEAwQDBAMFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQQIBAgECAQIBAgECAQIBAgECAQIBAgECAYABgAGAAYAAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHBAAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwAACAQHAA4LAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABBQMFAwUDBQMFAwUDBQMFAwUDBQMFAwUDBQMFAwUDBQMFAwUDBQMFAwUDBQMFAwUDAAMFAwADAQsFAwUDBQMFAwUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcFAAADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADCQsAAwADAAMAAwADAAMAAwcAAAMAAwMLAAAIBAcADgsAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEGAwYDBgMGAwYDBgMGAwYDBgMGAwYDBgMGAwYDBgMGAwYDBgMGAwYDBgMGAwYDBgMAAwYDAAMBCwYDBgMGAwYDBgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwYAAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAADBwAAAwELBwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwAACAQHAA4LAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABCAAIAAgACAAIAAgACAAABggACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAAAYIAAAGAAYIAAgACAAIAAgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQgFCAUIBQADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADCQsAAwADAAMAAwADAAMAAwcAAAMAAwMLAAYIBAcADgsIBQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAAAwkAAAMBCwkACQAJAAkADAkMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkKCAoICggKCAoICggKCAoICggKCAoICggKCQoJCgkKCQ0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDAkAAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAoACgAKAAADCgAAAwELCgAKAAoACgAMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkMCQoICggKCAoICggKCAoICggKCAoICggKCAsACwALAAsADQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MCgAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwAACAQHAA4LAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABCwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsAAAMLAAADAQsLAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAAADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADCQsAAwADAAMAAwADAAMAAwcAAAMAAwMLAAAIBAcADgsLAAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAAAwwAAAMBCwwADAAMAAwADAkMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkMCQwJDAkLAAsACwALAAsACwALAAsACwALAAsACwALAAsACwALAA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDA0MDQwNDAwAAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQAODQ0ADgAODQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwAOCAQHAA4LDQ0AAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABDgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOAA4AAAMOAAADAQsOAA4ADgAOAA8JDwkPCQ8JDwkPCQ8JDwkPCQ8JDwkPCQ8JDwkPCQ8JEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8OAAADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADCQsAAwADAAMAAwADAAMAAwcAAAMAAwMLAAAIBAcADgsAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAPAA8ADwAAAw8AAAMBCw8ADwAPAA8ADwkPCQ8JDwkPCQ8JDwkPCQ8JDwkPCQ8JDwkPCQ8JDwkQDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDxAPEA8QDw8AAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMJCwADAAMAAwADAAMAAwADBwAAAwADAwsAAAgEBwAOCwABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAARAAEAAQABAAEAAQABAAEAAQEBAQEBAQEBAQEBAQABAAEAAQABAAEAAQABAAEAAQAAAREAAAEQAREAAQABAAEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwkLAAMAAwADAAMAAwADAAMHAAADAAMDCwARCAQHAA4LEBAA/gIEbmFtZQAMC3BhcnNlci53YXNtAcgCFQAFcmVzZXQBDWdldF9pbnB1dF9wdHICDWdldF9raW5kc19wdHIDDmdldF9zdGFydHNfcHRyBA9nZXRfbGVuZ3Roc19wdHIFC2dldF9hdXhfcHRyBhRnZXRfcGFyYW1fc3RhcnRzX3B0cgcUZ2V0X3BhcmFtX2NvdW50c19wdHIIDmdldF9wYXJhbXNfcHRyCQ1nZXRfc3RhdGVfcHRyCg5nZXRfaGVhZGVyX3B0cgsJc2V0X3N0YXRlDBBleHBvcnRfcGFyYW1zX3RvDQ5nZXRfcGFyYW1zX2xlbg4RZ2V0X3N1YnBhcmFtc19sZW4PEWdldF9zdWJwYXJhbXNfcHRyEBVnZXRfc3VicGFyYW1zX2lkeF9wdHIREHN5bmNfcGFyYW1zX2Zyb20SDHByb2JlX2FjdGlvbhMEc2NhbhQHZW1pdF9vcAcSAQAPX19zdGFja19wb2ludGVyCQoBAAcucm9kYXRhADgJcHJvZHVjZXJzAQxwcm9jZXNzZWQtYnkBDFVidW50dSBjbGFuZxExOC4xLjMgKDF1YnVudHUxKQAsD3RhcmdldF9mZWF0dXJlcwIrD211dGFibGUtZ2xvYmFscysIc2lnbi1leHQ='; diff --git a/src/common/parser/wasm/transition_table.h b/src/common/parser/wasm/transition_table.h new file mode 100644 index 000000000..e71f0132d --- /dev/null +++ b/src/common/parser/wasm/transition_table.h @@ -0,0 +1,279 @@ +/* Auto-generated by bin/gen_parser_transition_table.mjs - do not edit */ +#ifndef PARSER_TRANSITION_TABLE_H +#define PARSER_TRANSITION_TABLE_H + +#include + +#define PARSER_TABLE_SIZE 4257 + +static const uint16_t PARSER_TRANSITION_TABLE[PARSER_TABLE_SIZE] = { + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0xb01, 0x300, 0x300, 0x300, 0x300, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x100, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x200, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, + 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x301, 0x300, 0x301, 0x300, 0xb01, 0x301, 0x301, 0x301, 0x301, + 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xb09, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0x7, 0xa00, 0xa00, 0xb03, 0xa00, 0x408, 0x7, 0xb0e, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0x1, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, + 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x302, 0x300, 0x302, 0x300, 0xb01, 0x302, 0x302, 0x302, 0x302, + 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, 0x902, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, + 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0xa00, 0x2, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, + 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x300, 0x303, 0x300, 0xb01, 0x303, 0x303, 0x303, 0x303, + 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, + 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x904, 0x904, 0x904, 0x904, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x3, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, + 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x304, 0x300, 0x304, 0x300, 0xb01, 0x304, 0x304, 0x304, 0x304, + 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, + 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x804, 0x6, 0x6, 0x6, 0x6, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x4, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, + 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x305, 0x300, 0x305, 0x300, 0xb01, 0x305, 0x305, 0x305, 0x305, + 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, 0x905, + 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, + 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x700, 0x5, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, + 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x306, 0x300, 0x306, 0x300, 0xb01, 0x306, 0x306, 0x306, 0x306, + 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, + 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x6, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x300, 0x7, 0x300, 0xb01, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x600, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x600, 0x8, 0x600, 0x600, 0x8, 0x8, 0x8, 0x8, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, 0x508, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x600, 0x408, 0x7, 0xb0e, + 0x508, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, + 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x9, 0x300, 0x9, 0x300, 0xb01, 0x9, 0x9, 0x9, 0x9, + 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, + 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x90a, 0x90a, 0x90a, 0x90a, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0x9, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, + 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0x300, 0xa, 0x300, 0xb01, 0xa, 0xa, 0xa, 0xa, + 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, + 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0x80a, 0xb, 0xb, 0xb, 0xb, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xa, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0x300, 0xb, 0x300, 0xb01, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0xb, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, + 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0xc, 0x300, 0xc, 0x300, 0xb01, 0xc, 0xc, 0xc, 0xc, + 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, 0x90c, + 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, + 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc0d, 0xc, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xe00, 0xd0d, 0xe00, 0xe00, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, + 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd0d, 0xd, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0xe00, 0x408, 0x7, 0xb0e, + 0xd0d, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, + 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0x300, 0xe, 0x300, 0xb01, 0xe, 0xe, 0xe, 0xe, + 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xe, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x300, 0xf, 0x300, 0xb01, 0xf, 0xf, 0xf, 0xf, + 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, 0x90f, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, + 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf10, 0xf, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x0, 0x408, 0x7, 0xb0e, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1100, 0x10, 0x1100, 0x1100, 0x10, 0x10, 0x10, 0x10, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, + 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x10, + 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, + 0xb09, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x300, 0x7, 0x300, 0x300, 0xb03, 0x1100, 0x408, 0x7, 0xb0e, + 0x1010 +}; + +#endif