diff --git a/.gitignore b/.gitignore index 702d7b5..40c7182 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,4 @@ dkms.conf .vscode +build diff --git a/.gitmodules b/.gitmodules index 4ecb2fe..6516c07 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "deps/ckb-c-stdlib"] - path = deps/ckb-c-stdlib - url = https://github.com/nervosnetwork/ckb-c-stdlib.git [submodule "deps/compiler-rt-builtins-riscv"] path = deps/compiler-rt-builtins-riscv url = https://github.com/nervosnetwork/compiler-rt-builtins-riscv.git +[submodule "deps/ckb-c-stdlib"] + path = deps/ckb-c-stdlib + url = https://github.com/nervosnetwork/ckb-c-stdlib diff --git a/Makefile b/Makefile index 056c8d6..6f88b9c 100644 --- a/Makefile +++ b/Makefile @@ -6,106 +6,146 @@ RANLIB := llvm-ranlib-18 UNAME := $(shell uname) ifeq ($(UNAME), Darwin) - CC := clang - LD := ld.lld - AR := llvm-ar - OBJCOPY := llvm-objcopy - RANLIB := llvm-ranlib + CC := clang + LD := ld.lld + AR := llvm-ar + OBJCOPY := llvm-objcopy + RANLIB := llvm-ranlib endif -CFLAGS := --target=riscv64 -march=rv64imc_zba_zbb_zbc_zbs -CFLAGS += -g -Oz \ - -Wall -Werror -Wno-nonnull -Wno-unused-function \ - -fno-builtin-printf -fno-builtin-memcmp \ - -nostdinc -nostdlib \ - -fdata-sections -ffunction-sections - -CFLAGS += -I deps/ckb-c-stdlib/libc -I deps/ckb-c-stdlib -CFLAGS += -I include -I include/c-stdlib -CFLAGS += -I deps/compiler-rt-builtins-riscv/compiler-rt/lib/builtins - -CFLAGS += -Wextra -Wno-sign-compare -Wno-missing-field-initializers -Wundef -Wuninitialized \ - -Wunused -Wno-unused-parameter -Wchar-subscripts -funsigned-char -Wno-unused-function \ - -DCONFIG_VERSION=\"2021-03-27-CKB\" -CFLAGS += -Wno-incompatible-library-redeclaration -Wno-implicit-const-int-float-conversion -Wno-invalid-noreturn - -CFLAGS += -DCKB_DECLARATION_ONLY -CFLAGS += -D__BYTE_ORDER=1234 -D__LITTLE_ENDIAN=1234 -D__ISO_C_VISIBLE=1999 -D__GNU_VISIBLE -CFLAGS += -DCKB_MALLOC_DECLARATION_ONLY -DCKB_PRINTF_DECLARATION_ONLY -DCONFIG_BIGNUM -DCONFIG_STACK_CHECK -# uncomment to dump memory usage -# CFLAGS += -DMEMORY_USAGE +CFLAGS_TARGET = --target=riscv64 -march=rv64imc_zba_zbb_zbc_zbs +CFLAGS_OPTIMIZE = -g -Oz -fdata-sections -ffunction-sections +CFLAGS_WARNNING = -Wno-incompatible-library-redeclaration -Wno-invalid-noreturn -Wno-implicit-const-int-float-conversion +CFLAGS_BASE = $(CFLAGS_TARGET) $(CFLAGS_OPTIMIZE) $(CFLAGS_WARNNING) +CFLAGS_BASE_CKB_C_STDLIB = $(CFLAGS_BASE) \ + -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib \ + -DCKB_MALLOC_DECLARATION_ONLY \ + -DCKB_PRINTF_DECLARATION_ONLY +CFLAGS_BASE_LIBC = $(CFLAGS_BASE) \ + -I libc \ + -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib \ + -DCKB_MALLOC_DECLARATION_ONLY \ + -DCKB_PRINTF_DECLARATION_ONLY +CFLAGS_BASE_NNCP = $(CFLAGS_BASE) \ + -I libc \ + -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib \ + -DCKB_MALLOC_DECLARATION_ONLY \ + -DCKB_PRINTF_DECLARATION_ONLY \ + -DCKB_DECLARATION_ONLY +CFLAGS_BASE_SRC = $(CFLAGS_BASE) \ + -I libc \ + -I deps/nncp \ + -I deps/quickjs \ + -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib \ + -DCKB_MALLOC_DECLARATION_ONLY \ + -DCKB_PRINTF_DECLARATION_ONLY \ + -DCKB_DECLARATION_ONLY \ + -DCONFIG_BIGNUM \ + -fno-builtin-printf +CFLAGS_BASE_QUICKJS = $(CFLAGS_BASE) \ + -I libc \ + -I deps/ckb-c-stdlib/libc \ + -I deps/ckb-c-stdlib \ + -DCKB_MALLOC_DECLARATION_ONLY \ + -DCKB_PRINTF_DECLARATION_ONLY \ + -DCKB_DECLARATION_ONLY \ + -DCONFIG_BIGNUM -DEMSCRIPTEN \ + -DCONFIG_VERSION=\"2021-03-27-CKB\" LDFLAGS := -static --gc-sections LDFLAGS += -Ldeps/compiler-rt-builtins-riscv/build -lcompiler-rt -OBJDIR=build - -QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o \ - $(OBJDIR)/cutils.o $(OBJDIR)/mocked.o $(OBJDIR)/std_module.o $(OBJDIR)/ckb_module.o $(OBJDIR)/ckb_cell_fs.o \ - $(OBJDIR)/libbf.o $(OBJDIR)/cmdopt.o - -STD_OBJS=$(OBJDIR)/string_impl.o $(OBJDIR)/malloc_impl.o $(OBJDIR)/math_impl.o \ - $(OBJDIR)/math_log_impl.o $(OBJDIR)/math_pow_impl.o $(OBJDIR)/printf_impl.o $(OBJDIR)/stdio_impl.o \ - $(OBJDIR)/locale_impl.o - +all: out build/ckb-js-vm -all: build/ckb-js-vm +out: + mkdir -p build + mkdir -p build/bytecode + mkdir -p build/ckb-c-stdlib + mkdir -p build/libc + mkdir -p build/nncp + mkdir -p build/src + mkdir -p build/quickjs deps/compiler-rt-builtins-riscv/build/libcompiler-rt.a: - cd deps/compiler-rt-builtins-riscv && make - -build/ckb-js-vm: $(STD_OBJS) $(QJS_OBJS) $(OBJDIR)/impl.o deps/compiler-rt-builtins-riscv/build/libcompiler-rt.a - $(LD) $(LDFLAGS) -o $@ $^ - cp $@ $@.debug - $(OBJCOPY) --strip-debug --strip-all $@ - ls -lh build/ckb-js-vm - -$(OBJDIR)/%.o: quickjs/%.c - @echo build $< - @$(CC) $(CFLAGS) -c -o $@ $< - -$(OBJDIR)/%.o: include/c-stdlib/src/%.c - @echo build $< - @$(CC) $(CFLAGS) -c -o $@ $< - -$(OBJDIR)/%.o: include/%.c - @echo build $< - @$(CC) $(CFLAGS) -c -o $@ $< - -$(OBJDIR)/impl.o: deps/ckb-c-stdlib/libc/src/impl.c - @echo build $< - @$(CC) $(filter-out -DCKB_DECLARATION_ONLY, $(CFLAGS)) -c -o $@ $< + cd deps/compiler-rt-builtins-riscv && make + +build/ckb-js-vm: build/ckb-c-stdlib/impl.o \ + build/libc/ckb_cell_fs.o \ + build/libc/ctype.o \ + build/libc/fenv.o \ + build/libc/locale.o \ + build/libc/malloc.o \ + build/libc/math.o \ + build/libc/math_log.o \ + build/libc/math_pow.o \ + build/libc/printf.o \ + build/libc/stdio.o \ + build/libc/stdlib.o \ + build/libc/string.o \ + build/libc/sys_time.o \ + build/libc/time.o \ + build/nncp/cmdopt.o \ + build/quickjs/quickjs.o \ + build/quickjs/libregexp.o \ + build/quickjs/libunicode.o \ + build/quickjs/cutils.o \ + build/quickjs/libbf.o \ + build/quickjs/repl.o \ + build/quickjs/qjscalc.o \ + build/src/ckb_module.o \ + build/src/qjs.o \ + build/src/std_module.o \ + deps/compiler-rt-builtins-riscv/build/libcompiler-rt.a + $(LD) $(LDFLAGS) -o $@ $^ + cp $@ $@.debug + $(OBJCOPY) --strip-debug --strip-all $@ + ls -lh build/ckb-js-vm + +build/ckb-c-stdlib/%.o: deps/ckb-c-stdlib/libc/src/%.c + @echo build $< + @$(CC) $(CFLAGS_BASE_CKB_C_STDLIB) -c -o $@ $< + +build/libc/%.o: libc/src/%.c + @echo build $< + @$(CC) $(CFLAGS_BASE_LIBC) -DCKB_DECLARATION_ONLY -c -o $@ $< + +build/nncp/%.o: deps/nncp/%.c + @echo build $< + @$(CC) $(CFLAGS_BASE_NNCP) -c -o $@ $< + +build/src/%.o: src/%.c + @echo build $< + @$(CC) $(CFLAGS_BASE_SRC) -c -o $@ $< + +build/quickjs/%.o: deps/quickjs/%.c + @echo build $< + @$(CC) $(CFLAGS_BASE_QUICKJS) -c -o $@ $< test: - make -f tests/examples/Makefile - make -f tests/basic/Makefile - cd tests/ckb_js_tests && make all + make -f tests/examples/Makefile + make -f tests/basic/Makefile + cd tests/ckb_js_tests && make all benchmark: - make -f tests/benchmark/Makefile + make -f tests/benchmark/Makefile clean: - rm -f build/*.o - rm -f build/ckb-js-vm - rm -f build/ckb-js-vm.debug - cd tests/ckb_js_tests && make clean - make -C deps/compiler-rt-builtins-riscv clean + rm -rf build + cd tests/ckb_js_tests && make clean + make -C deps/compiler-rt-builtins-riscv clean STYLE := "{BasedOnStyle: Google, TabWidth: 4, IndentWidth: 4, UseTab: Never, SortIncludes: false, ColumnLimit: 120}" fmt: - clang-format-18 -i -style=$(STYLE) \ - quickjs/ckb_module.c \ - quickjs/ckb_module.h \ - quickjs/mocked.c \ - quickjs/mocked.h \ - quickjs/qjs.c \ - quickjs/std_module.c \ - quickjs/std_module.h + clang-format-18 -i -style=$(STYLE) src/* install: - wget 'https://github.com/nervosnetwork/ckb-standalone-debugger/releases/download/v0.119.0/ckb-debugger-linux-x64.tar.gz' - tar zxvf ckb-debugger-linux-x64.tar.gz - mv ckb-debugger ~/.cargo/bin/ckb-debugger - make -f tests/ckb_js_tests/Makefile install-lua + wget 'https://github.com/nervosnetwork/ckb-standalone-debugger/releases/download/v0.119.0/ckb-debugger-linux-x64.tar.gz' + tar zxvf ckb-debugger-linux-x64.tar.gz + mv ckb-debugger ~/.cargo/bin/ckb-debugger + make -f tests/ckb_js_tests/Makefile install-lua .phony: all clean diff --git a/build/.gitignore b/build/.gitignore deleted file mode 100644 index 72e8ffc..0000000 --- a/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/deps/nncp/Changelog b/deps/nncp/Changelog new file mode 100644 index 0000000..e1b4c2b --- /dev/null +++ b/deps/nncp/Changelog @@ -0,0 +1,37 @@ +2024-06-05: + +- Windows fixes +- single libnc_cuda library for cuda 11 and 12 + +2023-10-21: + +- use a larger transformer model + +2021-06-01: + +- more hyperparameter tuning +- preprocessor fixes + +2021-04-24: + +- use new LibNC library with CUDA and BF16 support +- merged Transformer, LSTM and preprocessor into nncp +- Transformer: added GEGLU activation +- use integer-only operations in the preprocessor + +2019-11-16: + +- nncp: added the "-seg_len" option to specify the interval in symbols + between each parameter update +- nncp: use rms_norm instead of layer_norm +- trfcp: improved the positional encoding +- trfcp: use GeLU instead of ReLU + +2019-06-29: + +- improved arithmetic coder + +2019-05-08: + +- nncp: added -n_embed_out parameter +- preprocess: suppressed "/tmp/word1.txt" file diff --git a/deps/nncp/Makefile b/deps/nncp/Makefile new file mode 100644 index 0000000..aa982b5 --- /dev/null +++ b/deps/nncp/Makefile @@ -0,0 +1,39 @@ +# +# Makefile for nncp +# Copyright (c) 2018-2021 Fabrice Bellard +# +#CONFIG_WIN32=y + +ifdef CONFIG_WIN32 +CROSS_PREFIX=x86_64-w64-mingw32- +EXE=.exe +LIBEXT=.lib +DLLEXT=.dll +else +LIBEXT=.a +DLLEXT=.so +endif + +HOST_CC=gcc +CC=$(CROSS_PREFIX)gcc +CXX=$(CROSS_PREFIX)g++ +AR=$(CROSS_PREFIX)ar +CFLAGS_VERSION:=-DCONFIG_VERSION=\"$(shell cat VERSION)\" +CFLAGS=-O3 -Wall -Wpointer-arith -g -fno-math-errno -fno-trapping-math -MMD -Wno-format-truncation $(CFLAGS_VERSION) -DLIBNC_CONFIG_FULL +LDFLAGS=-Wl,-rpath='$$ORIGIN/' +PROGS=nncp$(EXE) +LIBS+=-lm -lpthread + +all: $(PROGS) + +clean: + rm -f *.o *.d $(PROGS) + +nncp$(EXE): nncp.o cmdopt.o cp_utils.o arith.o preprocess.o cutils.o \ + libnc$(DLLEXT) + $(CC) $(LDFLAGS) -o $@ $^ -lz $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +-include $(wildcard *.d) diff --git a/deps/nncp/VERSION b/deps/nncp/VERSION new file mode 100644 index 0000000..e56349d --- /dev/null +++ b/deps/nncp/VERSION @@ -0,0 +1 @@ +2024-06-05 diff --git a/deps/nncp/arith.c b/deps/nncp/arith.c new file mode 100644 index 0000000..67635ed --- /dev/null +++ b/deps/nncp/arith.c @@ -0,0 +1,310 @@ +/* + * Arithmetic coder + * + * Copyright (c) 2018-2021 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "arith.h" + +#define RANGE_MIN_BITS 16 +#define RANGE_MIN ((0xff << (RANGE_MIN_BITS - 8)) + 1) +#define RANGE_MAX (0xff << RANGE_MIN_BITS) + +//#define DUMP_PUT_BIT +//#define DUMP_GET_BIT + +void put_bit_init(PutBitState *s, uint8_t *buf, int buf_size, + PutBitWriteFunc *write_func, void *opaque) +{ + s->low = 0; + s->range = RANGE_MAX; + s->current_byte = 0xff; + s->n_bytes = 0; + s->buf = buf; + s->buf_size = buf_size; + s->idx = 0; + s->write_func = write_func; + s->opaque = opaque; + s->byte_count = 0; + assert(PROB_UNIT <= RANGE_MIN); +} + +static void put_byte(PutBitState *s, int v) +{ + s->buf[s->idx++] = v; + if (unlikely(s->idx == s->buf_size)) { + s->byte_count += s->idx; + s->write_func(s->opaque, s->buf, s->idx); + s->idx = 0; + } +} + +/* 0 <= v <= 0x1fe. The current output stream contains n_bytes with: + current_byte, then (n_bytes - 1) x 0xff. The first byte cannot be + 0xff. + */ +static void put_val(PutBitState *s, int v) +{ + uint32_t carry, b; + +#ifdef DUMP_PUT_BIT + printf(" out=%d\n", v); +#endif + if (v == 0xff) { + s->n_bytes++; + } else { + if (s->n_bytes > 0) { + carry = v >> 8; + put_byte(s, s->current_byte + carry); + b = (0xff + carry) & 0xff; + while (s->n_bytes > 1) { + put_byte(s, b); + s->n_bytes--; + } + } + s->n_bytes = 1; + s->current_byte = v; + } +} + +static void put_val_flush(PutBitState *s) +{ + if (s->n_bytes > 0) { + put_val(s, 0); + } +} + +static void put_bit_renorm(PutBitState *s) +{ + uint32_t v; + /* after renormalisation: + 0 <= low <= RANGE_MAX + RANGE_MIN <= range <= RANGE_MAX + In the worst case before normalisation: + low_max = 2 * RANGE_MAX hence v <= 0x1fe + */ + while (s->range < RANGE_MIN) { + v = s->low >> RANGE_MIN_BITS; + put_val(s, v); + s->low = (s->low & ((1 << RANGE_MIN_BITS) - 1)) << 8; + s->range <<= 8; + } +} + +/* 0 < prob0 < PROB_UNIT */ +void put_bit(PutBitState *s, int prob0, int bit) +{ + int range0; + + assert(s->range >= RANGE_MIN); + range0 = ((uint64_t)s->range * prob0) >> PROB_UNIT_BITS; + assert(range0 > 0); + assert(range0 < s->range); +#if defined(DUMP_PUT_BIT) + { + static int count; + printf("%d: range=%d b=%d range0=%d low=%d\n", + count++, s->range, bit, range0, s->low); + } +#endif + if (!bit) { + s->range = range0; + } else { + s->low += range0; + s->range -= range0; + } + + put_bit_renorm(s); +} + +void put_bit_raw(PutBitState *s, int bit) +{ + int range0; + + assert(s->range >= RANGE_MIN); + range0 = s->range >> 1; + if (!bit) { + s->range = range0; + } else { + s->low += range0; + s->range -= range0; + } + + put_bit_renorm(s); +} + +/* return the minimum number of bits to be able to correctly decode */ +int64_t put_bit_flush(PutBitState *s) +{ + int n, val, mask; + + /* force larger range */ + if (s->range < (1 << RANGE_MIN_BITS)) { + put_val(s, s->low >> RANGE_MIN_BITS); + s->low = (s->low & ((1 << RANGE_MIN_BITS) - 1)) << 8; + s->range <<= 8; + } + + /* largest n such as 2^n <= range */ + n = 0; + while ((1 << (n + 1)) <= s->range) + n++; + assert(n >= RANGE_MIN_BITS && n <= (RANGE_MIN_BITS + 7)); + + val = s->low; + mask = (1 << n) - 1; + if ((val & mask) != 0) + val = (val + (1 << n)) & ~mask; + assert(val >= s->low && val < s->low + s->range); + + put_val(s, val >> RANGE_MIN_BITS); + put_val_flush(s); + if (s->idx > 0) { + s->byte_count += s->idx; + s->write_func(s->opaque, s->buf, s->idx); + s->idx = 0; + } + return (s->byte_count - 1) * 8 + (RANGE_MIN_BITS + 8 - n); +} + +/* return the approximate number of written bits */ +int64_t put_bit_get_bit_count(PutBitState *s) +{ + int n; + n = 0; + while ((1 << (n + 1)) <= s->range) + n++; + return (s->byte_count + s->idx + s->n_bytes) * 8 + (RANGE_MIN_BITS + 7 - n); +} + +/****************************************/ + +static void refill(GetBitState *s) +{ + s->range <<= 8; + s->low <<= 8; + if (s->idx >= s->buf_len) { + if (!s->read_func || s->eof_reached) + goto zero_pad; + s->buf_len = s->read_func(s->opaque, s->buf, s->buf_size); + s->idx = 0; + if (s->buf_len == 0) { + s->eof_reached = TRUE; + zero_pad: + s->byte_count++; + return; /* pad with zeros */ + } else { + s->byte_count += s->buf_len; + } + } +#ifdef DUMP_GET_BIT + printf(" in=%d\n", s->buf[s->idx]); +#endif + s->low += s->buf[s->idx++]; +} + +void get_bit_init(GetBitState *s, uint8_t *buf, size_t buf_size, + GetBitReadFunc *read_func, void *opaque) +{ + int i; + s->buf_size = buf_size; + s->buf = buf; + s->read_func = read_func; + s->opaque = opaque; + if (read_func) { + s->buf_len = 0; + } else { + /* prefilled buffer */ + s->buf_len = s->buf_size; + } + s->byte_count = s->buf_len; + s->eof_reached = FALSE; + s->range = 0; + s->low = 0; + s->idx = 0; + for(i = 0; i <= RANGE_MIN_BITS; i += 8) { + refill(s); + } + s->range = RANGE_MAX; +} + +/* 0 < prob0 < PROB_UNIT */ +int get_bit(GetBitState *s, int prob0) +{ + int b, range0; + + assert(s->range >= RANGE_MIN); + range0 = ((uint64_t)s->range * prob0) >> PROB_UNIT_BITS; + assert(range0 > 0); + assert(range0 < s->range); + b = s->low >= range0; +#ifdef DUMP_GET_BIT + { + static int count; + printf("%d: range=%d b=%d range0=%d low=%d\n", count++, s->range, b, range0, s->low); + } +#endif + if (b) { + s->low -= range0; + s->range -= range0; + } else { + s->range = range0; + } + while (s->range < RANGE_MIN) + refill(s); + return b; +} + +/* no context */ +int get_bit_raw(GetBitState *s) +{ + int b, range0; + range0 = s->range >> 1; + b = s->low >= range0; + if (b) { + s->low -= range0; + s->range -= range0; + } else { + s->range = range0; + } + if (s->range < RANGE_MIN) + refill(s); + return b; +} + +/* return the approximate number of read bits */ +int64_t get_bit_get_bit_count(GetBitState *s) +{ + int n; + n = 0; + while ((1 << (n + 1)) <= s->range) + n++; + return (s->byte_count - s->buf_len + s->idx) * 8 - n - 1; +} diff --git a/deps/nncp/arith.h b/deps/nncp/arith.h new file mode 100644 index 0000000..56c822e --- /dev/null +++ b/deps/nncp/arith.h @@ -0,0 +1,74 @@ +/* + * Arithmetic coder + * + * Copyright (c) 2018-2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef ARITH_H +#define ARITH_H + +#define PROB_UNIT_BITS 15 +#define PROB_UNIT (1 << PROB_UNIT_BITS) + +typedef void PutBitWriteFunc(void *opaque, const uint8_t *buf, size_t buf_size); + +typedef struct { + uint32_t range; + uint32_t low; + uint8_t current_byte; + uint32_t n_bytes; + uint8_t *buf; + size_t buf_size; + size_t idx; /* current position in bytes */ + PutBitWriteFunc *write_func; + void *opaque; + uint64_t byte_count; +} PutBitState; + +void put_bit_init(PutBitState *s, uint8_t *buf, int buf_size, + PutBitWriteFunc *write_func, void *opaque); +void put_bit(PutBitState *s, int prob0, int bit); +void put_bit_raw(PutBitState *s, int bit); +int64_t put_bit_flush(PutBitState *s); +int64_t put_bit_get_bit_count(PutBitState *s); + +/* return the number of read bytes */ +typedef ssize_t GetBitReadFunc(void *opaque, uint8_t *buf, size_t buf_size); + +typedef struct { + uint8_t *buf; + int buf_len; + int buf_size; + int idx; + uint32_t low; + uint32_t range; + BOOL eof_reached; + GetBitReadFunc *read_func; + void *opaque; + uint64_t byte_count; +} GetBitState; + +void get_bit_init(GetBitState *s, uint8_t *buf, size_t buf_size, + GetBitReadFunc *read_func, void *opaque); +int get_bit(GetBitState *s, int prob0); +int get_bit_raw(GetBitState *s); +int64_t get_bit_get_bit_count(GetBitState *s); + +#endif /* ARITH_H */ diff --git a/quickjs/cmdopt.c b/deps/nncp/cmdopt.c similarity index 88% rename from quickjs/cmdopt.c rename to deps/nncp/cmdopt.c index bcfc20c..0d83416 100644 --- a/quickjs/cmdopt.c +++ b/deps/nncp/cmdopt.c @@ -1,10 +1,6 @@ -/* - * Copied from https://bellard.org/nncp/nncp-2023-10-21.tar.gz - */ - /* * Yet another command line option parser - * + * * Copyright (c) 2021 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -26,13 +22,12 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" #include #include -#include "my_string.h" -#include "my_assert.h" +#include +#include "cutils.h" + #include "cmdopt.h" typedef struct { @@ -51,14 +46,14 @@ struct CMDOption { static const char *cmd_prog_name; -int ckb_vprintf(const char *format, va_list va); void cmd_error(const char *fmt, ...) { va_list ap; - + va_start(ap, fmt); - printf("%s:", cmd_prog_name); - ckb_vprintf(fmt, ap); + fprintf(stderr, "%s: ", cmd_prog_name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); exit(1); } @@ -68,7 +63,7 @@ static const CMDOptDesc *find_opt(CMDOption *s, const char *opt) int i; size_t opt_len, len; const char *p, *r; - + opt_len = strlen(opt); for(i = 0; i < s->desc_count; i++) { for(d = s->desc_tab[i]; d->opt != NULL; d++) { @@ -107,8 +102,6 @@ static void add_opt(CMDOption *s, const CMDOptDesc *d, cs->optarg = optarg; } -/* See the reason: https://reviews.llvm.org/D103009 */ -#pragma clang optimize off CMDOption *cmdopt_init(const char *prog_name) { CMDOption *s; @@ -118,7 +111,6 @@ CMDOption *cmdopt_init(const char *prog_name) memset(s, 0, sizeof(*s)); return s; } -#pragma clang optimize on void cmdopt_add_desc(CMDOption *s, const CMDOptDesc *desc) { @@ -137,8 +129,8 @@ int cmdopt_parse(CMDOption *s, int argc, const char **argv) param = malloc(sizeof(param[0]) * argc); param_len = 0; - arg_pos = 0; - for(optind = 0; optind < argc; ) { + arg_pos = 1; + for(optind = 1; optind < argc; ) { arg = argv[optind]; if (*arg != '-') { param[param_len++] = arg; @@ -214,7 +206,7 @@ int cmdopt_parse(CMDOption *s, int argc, const char **argv) } printf("\n"); } -#endif +#endif return optind; } @@ -222,12 +214,11 @@ void cmdopt_show_desc(const CMDOptDesc *desc) { const CMDOptDesc *d; int col, pos, opt_width; - size_t len; + size_t len, i; const char *p, *r; - + opt_width = 24; for(d = desc; d->opt != NULL; d++) { - char l[256] = {0}; col = 0; p = d->opt; for(;;) { @@ -237,31 +228,28 @@ void cmdopt_show_desc(const CMDOptDesc *desc) else len = strlen(p); if (p != d->opt) { - strcat(l, " "); + putchar(' '); col++; } - strcat(l, "-"); + putchar('-'); if (len > 1) { - strcat(l, "-"); + putchar('-'); col++; } - memcpy(&l[col+1], p, len); + for(i = 0; i < len; i++) + putchar(p[i]); col += len + 1; - + if (!r) break; p = r + 1; } - + if (d->flags & CMD_HAS_ARG) { - if (d->arg_desc) { - strcat(l, " "); - strcat(l, d->arg_desc); - col += 1 + strlen(d->arg_desc); - } else { - strcat(l, " arg"); - col += 4; - } + if (d->arg_desc) + col += printf(" %s", d->arg_desc); + else + col += printf(" arg"); } if (col < opt_width) { pos = opt_width; @@ -269,19 +257,18 @@ void cmdopt_show_desc(const CMDOptDesc *desc) pos = ((col - opt_width + 8) & ~7) + opt_width; } while (col < pos) { - strcat(l, " "); + putchar(' '); col++; } - strcat(l, d->desc); - printf("%s", l); + printf("%s\n", d->desc); } } static const char *cmdopt_get_internal(CMDOption *s, const char *opt, - BOOL has_arg) + BOOL has_arg, int *pcount) { const CMDOptDesc *d; - int i; + int i, count; d = find_opt(s, opt); if (!d) { @@ -299,29 +286,44 @@ static const char *cmdopt_get_internal(CMDOption *s, const char *opt, strlen(opt) > 1 ? "-" : "", opt); } } - + /* the last option is used */ + count = 0; for(i = s->opt_count - 1; i >= 0; i--) { CMDOpt *cs = &s->opt_tab[i]; if (cs->desc == d) { if (has_arg) { + if (pcount) + *pcount = 1; return cs->optarg; } else { - return ""; + count++; } } } - return NULL; + if (pcount) + *pcount = count; + if (count != 0) + return ""; + else + return NULL; } const char *cmdopt_get(CMDOption *s, const char *opt) { - return cmdopt_get_internal(s, opt, TRUE); + return cmdopt_get_internal(s, opt, TRUE, NULL); } BOOL cmdopt_has(CMDOption *s, const char *opt) { - return (cmdopt_get_internal(s, opt, FALSE) != NULL); + return (cmdopt_get_internal(s, opt, FALSE, NULL) != NULL); +} + +int cmdopt_get_count(CMDOption *s, const char *opt) +{ + int count; + cmdopt_get_internal(s, opt, FALSE, &count); + return count; } int cmdopt_get_int(CMDOption *s, const char *opt, int def_val) @@ -329,7 +331,7 @@ int cmdopt_get_int(CMDOption *s, const char *opt, int def_val) const char *str, *p; double d; int val; - + str = cmdopt_get(s, opt); if (!str) return def_val; @@ -345,7 +347,7 @@ float cmdopt_get_float(CMDOption *s, const char *opt, float def_val) { const char *str, *p; float val; - + str = cmdopt_get(s, opt); if (!str) return def_val; diff --git a/quickjs/cmdopt.h b/deps/nncp/cmdopt.h similarity index 97% rename from quickjs/cmdopt.h rename to deps/nncp/cmdopt.h index ed443fc..fd383a9 100644 --- a/quickjs/cmdopt.h +++ b/deps/nncp/cmdopt.h @@ -48,5 +48,6 @@ const char *cmdopt_get(CMDOption *s, const char *opt); BOOL cmdopt_has(CMDOption *s, const char *opt); int cmdopt_get_int(CMDOption *s, const char *opt, int def_val); float cmdopt_get_float(CMDOption *s, const char *opt, float def_val); +int cmdopt_get_count(CMDOption *s, const char *opt); #endif /* CMDOPT_H */ diff --git a/deps/nncp/cp_utils.c b/deps/nncp/cp_utils.c new file mode 100644 index 0000000..b7c8a6d --- /dev/null +++ b/deps/nncp/cp_utils.c @@ -0,0 +1,754 @@ +/* + * Compression utilities + * + * Copyright (c) 2018-2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#include "cutils.h" +#include "libnc.h" +#include "cp_utils.h" + +void fatal_error(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "Fatal error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(1); +} + +int64_t get_time_ms(void) +{ +#ifdef _WIN32 + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000U); +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000U); +#endif +} + +void fput_u8(FILE *f, uint8_t v) +{ + fputc(v, f); +} + +int fget_u8(FILE *f, uint8_t *pv) +{ + int c; + c = fgetc(f); + if (c < 0) + return -1; + *pv = c; + return 0; +} + +void fput_be16(FILE *f, uint16_t v) +{ + fputc(v >> 8, f); + fputc(v >> 0, f); +} + +int fget_be16(FILE *f, uint16_t *pv) +{ + uint8_t buf[2]; + if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) + return -1; + *pv = (buf[0] << 8) | + (buf[1] << 0); + return 0; +} + +void fput_be32(FILE *f, uint32_t v) +{ + fputc(v >> 24, f); + fputc(v >> 16, f); + fputc(v >> 8, f); + fputc(v >> 0, f); +} + +void fput_be64(FILE *f, uint64_t v) +{ + fput_be32(f, v >> 32); + fput_be32(f, v); +} + +int fget_be32(FILE *f, uint32_t *pv) +{ + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) + return -1; + *pv = get_be32(buf); + return 0; +} + +void fput_le16(FILE *f, uint16_t v) +{ + fputc(v >> 0, f); + fputc(v >> 8, f); +} + +int fget_le16(FILE *f, uint16_t *pv) +{ + uint8_t buf[2]; + if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) + return -1; + *pv = (buf[0] << 0) | + (buf[1] << 8); + return 0; +} + +void fput_le32(FILE *f, uint32_t v) +{ + fputc(v >> 0, f); + fputc(v >> 8, f); + fputc(v >> 16, f); + fputc(v >> 24, f); +} + +int fget_le32(FILE *f, uint32_t *pv) +{ + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) + return -1; + *pv = get_u32(buf); + return 0; +} + +static const uint32_t crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +uint32_t mpegts_crc32(const uint8_t *data, size_t len, uint32_t crc) +{ + size_t i; + + for (i = 0; i < len; i++) + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff]; + return crc; +} + +void fput_sgd_opt(FILE *f, const SGDOptParams *p) +{ + fput_u8(f, p->algo); + switch(p->algo) { + case SGD_OPT_BASIC: + break; + case SGD_OPT_ADAM: + fput_f32(f, p->u.adam.beta1); + fput_f32(f, p->u.adam.beta2); + fput_f32(f, p->u.adam.eps); + fput_f32(f, p->u.adam.gradient_clip); + break; + default: + abort(); + } +} + +int fget_sgd_opt(FILE *f, SGDOptParams *p) +{ + uint8_t v8; + + if (fget_u8(f, &v8)) + return -1; + p->algo = v8; + switch(p->algo) { + case SGD_OPT_BASIC: + break; + case SGD_OPT_ADAM: + if (fget_f32(f, &p->u.adam.beta1)) + return -1; + if (fget_f32(f, &p->u.adam.beta2)) + return -1; + if (fget_f32(f, &p->u.adam.eps)) + return -1; + if (fget_f32(f, &p->u.adam.gradient_clip)) + return -1; + break; + default: + return -1; + } + return 0; +} + +void dump_sgd_opt_params(FILE *f, const SGDOptParams *p) +{ + switch(p->algo) { + case SGD_OPT_BASIC: + fprintf(f, " sgd_opt=%s", + "none"); + break; + case SGD_OPT_ADAM: + fprintf(f, " sgd_opt=%s beta1=%g beta2=%g eps=%g gclip=%g wdecay=%g", + "adam", + p->u.adam.beta1, + p->u.adam.beta2, + p->u.adam.eps, + p->u.adam.gradient_clip, + p->u.adam.weight_decay); + break; + default: + abort(); + } +} + +typedef union { + float f; + uint32_t u32; +} f32; + +void fput_f32(FILE *f, float v) +{ + f32 u; + u.f = v; + fput_be32(f, u.u32); +} + +int fget_f32(FILE *f, float *pv) +{ + f32 u; + if (fget_be32(f, &u.u32)) + return -1; + *pv = u.f; + return 0; +} + +void write_sym(PutBitState *pb, const float *prob_table, int n_symb, int sym) +{ + int start, range, prob0, bit, range0; + float p, p0; + + start = 0; + range = n_symb; + p = 1.0; /* invariant: p=sum(prob_table[start...start + range]) */ + while (range > 1) { + range0 = range >> 1; + p0 = vec_sum_f32(prob_table + start, range0); + prob0 = lrintf(p0 * PROB_UNIT / p); + prob0 = clamp_int(prob0, 1, PROB_UNIT - 1); + bit = sym >= (start + range0); + put_bit(pb, prob0, bit); + if (bit) { + start += range0; + range = range - range0; + p = p - p0; + } else { + p = p0; + range = range0; + } + } +} + +int read_sym(GetBitState *gb, const float *prob_table, int n_symb) +{ + int start, range, prob0, bit, range0; + float p, p0; + + start = 0; + range = n_symb; + p = 1.0; /* invariant: p=sum(prob_table[start...start + range]) */ + while (range > 1) { + range0 = range >> 1; + p0 = vec_sum_f32(prob_table + start, range0); + prob0 = lrintf(p0 * PROB_UNIT / p); + prob0 = clamp_int(prob0, 1, PROB_UNIT - 1); + bit = get_bit(gb, prob0); + if (bit) { + start += range0; + range = range - range0; + p = p - p0; + } else { + p = p0; + range = range0; + } + } + return start; +} + +void create_debug_dir(char *debug_dir, size_t debug_dir_size, + const char *debug_path, const char *prefix) +{ + char name1[1024]; + struct tm *tm; + time_t ti; + + snprintf(name1, sizeof(name1), "%s/%s", debug_path, prefix); +#ifdef _WIN32 + _mkdir(name1); +#else + mkdir(name1, 0777); +#endif + + ti = time(NULL); + tm = localtime(&ti); + snprintf(debug_dir, debug_dir_size, "%s/%04u%02u%02u-%02u%02u%02u", + name1, + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +#ifdef _WIN32 + _mkdir(debug_dir); +#else + mkdir(debug_dir, 0777); +#endif +} + +/**************************************************************/ +/* piece-wise linear interpolation + optional power decay */ +float get_interp_param(const InterpParams *p, int64_t pos) +{ + int i; + float lr, t; + int64_t pos0; + + pos0 = 0; + for(i = 0; i < p->n_steps; i++) { + if (pos < p->pos[i]) { + if (i == 0) + pos0 = 0; + else + pos0 = p->pos[i - 1]; + t = (float)(pos - pos0) / (float)(p->pos[i] - pos0); + lr = p->val[i] + t * (p->val[i + 1] - p->val[i]); + return lr; + } + } + if (p->decay_power == 0.0f || p->n_steps == 0) { + return p->val[p->n_steps]; + } else if (p->decay_power == 0.5f) { + /* special case to be independant of pow() rounding */ + return p->val[p->n_steps] / + sqrtf((float)pos / (float)p->pos[p->n_steps - 1]); + } else { + /* XXX: use libc independant pow() implementation to avoid + rounding differences */ + return p->val[p->n_steps] * + pow((float)pos / (float)p->pos[p->n_steps - 1], -p->decay_power); + } +} + +void dump_interp_param(FILE *f, const InterpParams *p) +{ + int i; + fprintf(f, "%g", p->val[0]); + for(i = 0; i < p->n_steps; i++) { + fprintf(f, ",%" PRIu64 ",%g", + p->pos[i], p->val[i + 1]); + } + if (p->decay_power != 0) { + fprintf(f, ",p%g", p->decay_power); + } +} + +void skip_c(const char **pp, int c) +{ + const char *p; + p = *pp; + if (*p != c) { + fprintf(stderr, "expecting '%c'\n", c); + exit(1); + } + p++; + *pp = p; +} + +void parse_interp_param(InterpParams *p, const char *r) +{ + float lr; + + lr = strtod(r, (char **)&r); + p->n_steps = 0; + p->val[0] = lr; + p->decay_power = 0.0; + if (*r != '\0') { + skip_c(&r, ','); + for(;;) { + if (*r == 'p') { + r++; + p->decay_power = strtod(r, (char **)&r); + if (*r != '\0') + fatal_error("extranous characters"); + break; + } else { + if (p->n_steps >= INTERP_MAX_STEPS) + fatal_error("too many steps"); + p->pos[p->n_steps] = + lrint(strtod(r, (char **)&r)); + + skip_c(&r, ','); + p->val[++p->n_steps] = + strtod(r, (char **)&r); + if (*r == '\0') + break; + skip_c(&r, ','); + } + } + } +} + +#ifdef _WIN32 +void term_init(void) +{ +} +int term_get_key(void) +{ + return 0; +} +#else +static struct termios oldtty; +static int old_fd0_flags; + +static void term_exit(void) +{ + tcsetattr (0, TCSANOW, &oldtty); + fcntl(0, F_SETFL, old_fd0_flags); +} + +void term_init(void) +{ + struct termios tty; + + memset(&tty, 0, sizeof(tty)); + tcgetattr (0, &tty); + oldtty = tty; + old_fd0_flags = fcntl(0, F_GETFL); + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr (0, TCSANOW, &tty); + fcntl(0, F_SETFL, O_NONBLOCK); + + atexit(term_exit); +} + +/* return 0 if no key */ +int term_get_key(void) +{ + uint8_t ch; + if (read(0, &ch, 1) == 1) + return ch; + else + return 0; +} +#endif /* !_WIN32 */ + +#if defined(_WIN32) +/* better than nothing: use system() */ +int exec_cmd(char **argv) +{ + DynBuf dbuf; + int ret; + + dbuf_init(&dbuf); + while (*argv != NULL) { + if (dbuf.size != 0) + dbuf_putc(&dbuf, ' '); + dbuf_putstr(&dbuf, *argv++); + } + dbuf_putc(&dbuf, '\0'); + ret = system((char *)dbuf.buf); + dbuf_free(&dbuf); + return ret; +} + +#else +int exec_cmd(char **argv) +{ + int pid, status, ret, fd_count, i; + + pid = fork(); + if (pid == 0) { + fd_count = sysconf (_SC_OPEN_MAX); + for (i = 3; i < fd_count; i++) + close(i); + + execvp(argv[0], argv); + exit(1); + } else if (pid < 0) { + return 254; + } + + for(;;) { + ret = waitpid(pid, &status, 0); + if (ret == pid && (WIFEXITED(status) || WIFSIGNALED(status))) + break; + } + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } else { + return 255; /* signaled */ + } +} +#endif + +uint8_t *load_file2(size_t *psize, FILE *f) +{ + size_t size, pos; + uint8_t *buf; + + pos = ftell(f); + fseek(f, 0, SEEK_END); + size = ftell(f) - pos; + fseek(f, pos, SEEK_SET); + buf = malloc(size + 1); + if (fread(buf, 1, size, f) != size) { + free(buf); + buf = NULL; + size = 0; + } else { + buf[size] = '\0'; + } + if (psize) + *psize = size; + return buf; +} + +uint8_t *load_file(size_t *psize, const char *filename) +{ + FILE *f; + size_t size; + uint8_t *buf; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + buf = load_file2(&size, f); + if (!buf) { + fprintf(stderr, "%s: I/O error\n", filename); + exit(1); + } + fclose(f); + if (psize) + *psize = size; + return buf; +} + +int get_random_seed(void) +{ + struct timeval tv; + int seed; + + gettimeofday(&tv, NULL); + seed = tv.tv_sec + tv.tv_usec; + return seed; +} + +#define FILE_PUT_BIT_BUF_SIZE 1024 + +struct FilePutBitState { + FILE *f; + uint8_t *buf; + int alloc_buf_len; + int buf_pos; /* in bits */ + int buf_len; /* in bits */ +}; + +FilePutBitState *file_put_bit_init(FILE *f) +{ + FilePutBitState *s; + s = mallocz(sizeof(*s)); + s->f = f; + s->alloc_buf_len = FILE_PUT_BIT_BUF_SIZE + PUT_BITS_FAST_PADDING; + s->buf = mallocz(s->alloc_buf_len); + s->buf_pos = 0; + s->buf_len = FILE_PUT_BIT_BUF_SIZE * 8 - 32; + return s; +} + +void file_put_bits_flush(FilePutBitState *s, BOOL pad) +{ + int len; + + if (pad) { + len = (s->buf_pos + 7) / 8; + if (len > 0) { + fwrite(s->buf, 1, len, s->f); + memset(s->buf, 0, s->alloc_buf_len); + s->buf_pos = 0; + } + } else { + len = s->buf_pos / 8; + if (len > 0) { + uint8_t b; + fwrite(s->buf, 1, len, s->f); + b = s->buf[len]; + memset(s->buf, 0, s->alloc_buf_len); + s->buf_pos = s->buf_pos & 7; + s->buf[0] = b; + } + } +} + +void file_put_bits(FilePutBitState *s, int n, int bits) +{ + put_bits_fast(s->buf, &s->buf_pos, n, bits); + if (s->buf_pos >= s->buf_len) + file_put_bits_flush(s, FALSE); +} + +void file_put_bits_end(FilePutBitState *s) +{ + free(s->buf); + free(s); +} + +/* XXX: untested */ +#if 0 +#define FILE_GET_BIT_BUF_SIZE 1024 + +typedef struct FileGetBitState FileGetBitState; + +struct FileGetBitState { + FILE *f; + uint8_t *buf; + int alloc_buf_len; + int buf_pos; /* in bits */ + int buf_len; /* in bits */ + int read_buf_len; /* in bytes */ +}; + +FileGetBitState *file_get_bit_init(FILE *f) +{ + FileGetBitState *s; + s = mallocz(sizeof(*s)); + s->f = f; + s->alloc_buf_len = FILE_GET_BIT_BUF_SIZE; + s->buf = mallocz(s->alloc_buf_len); + s->buf_pos = 0; + s->buf_len = 0; + s->read_buf_len = 0; + return s; +} + +void file_get_bit_refill(FileGetBitState *s) +{ + int len, pos; + + /* first free as much space as possible */ + if (s->buf_pos >= 8) { + pos = s->buf_pos / 8; + memmove(s->buf, s->buf + pos, s->read_buf_len - pos); + s->read_buf_len -= pos; + s->buf_pos -= pos * 8; + s->buf_len -= pos * 8; + } + len = s->alloc_buf_len - s->read_buf_len; + if (len > 0) { + len = fread(s->buf + s->read_buf_len, 1, len, s->f); + s->read_buf_len += len; + /* pad with zeros in case of EOF */ + len = s->alloc_buf_len - s->read_buf_len; + if (len > 0) { + memset(s->buf + s->read_buf_len, 0, len); + s->read_buf_len += len; + } + } + /* set the length so that we never try to read bits outside the + buffer */ + s->buf_len = (s->read_buf_len - GET_BITS_FAST_PADDING - 4) * 8; +} + +int file_get_bits(FileGetBitState *s, int n) +{ + if (s->buf_pos >= s->buf_len) + file_get_bit_refill(s); + return get_bits_fast(s->buf, &s->buf_pos, n); +} + +void file_get_bits_end(FileGetBitState *s) +{ + free(s->buf); + free(s); +} +#endif diff --git a/deps/nncp/cp_utils.h b/deps/nncp/cp_utils.h new file mode 100644 index 0000000..74c835a --- /dev/null +++ b/deps/nncp/cp_utils.h @@ -0,0 +1,94 @@ +/* + * Compression utilities + * + * Copyright (c) 2018-2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "arith.h" +#include "libnc.h" + +void __attribute__((noreturn, format(printf, 1, 2))) fatal_error(const char *fmt, ...); + +int64_t get_time_ms(void); + +static inline uint64_t get_be64(const uint8_t *d) +{ + return ((uint64_t)get_be32(d) << 32) | get_be32(d + 4); +} + +void fput_u8(FILE *f, uint8_t v); +int fget_u8(FILE *f, uint8_t *pv); +void fput_be16(FILE *f, uint16_t v); +int fget_be16(FILE *f, uint16_t *pv); +void fput_be32(FILE *f, uint32_t v); +int fget_be32(FILE *f, uint32_t *pv); +void fput_le16(FILE *f, uint16_t v); +int fget_le16(FILE *f, uint16_t *pv); +void fput_le32(FILE *f, uint32_t v); +int fget_le32(FILE *f, uint32_t *pv); +void fput_be64(FILE *f, uint64_t v); +void fput_f32(FILE *f, float v); +int fget_f32(FILE *f, float *pv); +uint32_t mpegts_crc32(const uint8_t *data, size_t len, uint32_t crc); +void fput_sgd_opt(FILE *f, const SGDOptParams *p); +int fget_sgd_opt(FILE *f, SGDOptParams *p); +void dump_sgd_opt_params(FILE *f, const SGDOptParams *p); + +void write_sym(PutBitState *pb, const float *prob_table, int n_symb, int sym); +int read_sym(GetBitState *gb, const float *prob_table, int n_symb); + +void create_debug_dir(char *debug_dir, size_t debug_dir_size, + const char *debug_path, const char *prefix); + +#define INTERP_MAX_STEPS 8 + +typedef struct { + int n_steps; + float val[INTERP_MAX_STEPS + 1]; + int64_t pos[INTERP_MAX_STEPS]; + float decay_power; +} InterpParams; + +float get_interp_param(const InterpParams *p, int64_t pos); +void dump_interp_param(FILE *f, const InterpParams *p); +void parse_interp_param(InterpParams *p, const char *r); +void skip_c(const char **pp, int c); + +void term_init(void); +int term_get_key(void); +int exec_cmd(char **argv); + +uint8_t *load_file2(size_t *psize, FILE *f); +uint8_t *load_file(size_t *psize, const char *filename); +int get_random_seed(void); + +typedef struct FilePutBitState FilePutBitState; +FilePutBitState *file_put_bit_init(FILE *f); +void file_put_bits_flush(FilePutBitState *s, BOOL pad); +void file_put_bits(FilePutBitState *s, int n, int bits); +void file_put_bits_end(FilePutBitState *s); + +typedef struct FileGetBitState FileGetBitState; +FileGetBitState *file_get_bit_init(FILE *f); +void file_get_bit_refill(FileGetBitState *s); +int file_get_bits(FileGetBitState *s, int n); +void file_get_bits_end(FileGetBitState *s); + + diff --git a/deps/nncp/cutils.c b/deps/nncp/cutils.c new file mode 100644 index 0000000..70125e4 --- /dev/null +++ b/deps/nncp/cutils.c @@ -0,0 +1,484 @@ +/* + * C utilities + * + * Copyright (c) 2018-2023 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include "cutils.h" + +void pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for(;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +/* strcat and truncate. */ +char *pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +int strstart(const char *str, const char *val, const char **ptr) +{ + const char *p, *q; + p = str; + q = val; + while (*q != '\0') { + if (*p != *q) + return 0; + p++; + q++; + } + if (ptr) + *ptr = p; + return 1; +} + +BOOL has_suffix(const char *str, const char *suffix) +{ + size_t len = strlen(str); + size_t slen = strlen(suffix); + return (len >= slen && !memcmp(str + len - slen, suffix, slen)); +} + +#ifdef _WIN32 +void *memmem(const void *hs1, size_t hs_len, const void *ne1, size_t ne_len) +{ + const uint8_t *hs = hs1; + const uint8_t *ne = ne1; + size_t i, len; + + if (ne_len == 0) + return (void *)hs; + if (ne_len == 1) + return memchr(hs, ne[0], hs_len); + if (ne_len > hs_len) + return NULL; + + /* XXX: inefficient */ + len = hs_len - ne_len; + for(i = 0; i <= len; i++) { + if (memcmp(hs + i, ne, ne_len) == 0) + return (void *)(hs + i); + } + return NULL; +} +#endif + +void *mallocz(size_t size) +{ + return calloc(1, size); +} + +void *memdup(const void *ptr, size_t size) +{ + void *ptr1; + ptr1 = malloc(size); + memcpy(ptr1, ptr, size); + return ptr1; +} + +char *strdup_len(const char *str, size_t len) +{ + char *r; + + r = malloc(len + 1); + memcpy(r, str, len); + r[len] = '\0'; + return r; +} + +void dbuf_init(DynBuf *s) +{ + memset(s, 0, sizeof(*s)); +} + +int __dbuf_realloc(DynBuf *s, size_t new_size) +{ + new_size = max_int(new_size, s->allocated_size + s->allocated_size / 2); + s->buf = realloc(s->buf, new_size); + s->allocated_size = new_size; + return 0; +} + +void dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) +{ + size_t end; + end = offset + len; + dbuf_realloc(s, end); + memcpy(s->buf + offset, data, len); + if (end > s->size) + s->size = end; +} + +void dbuf_put(DynBuf *s, const void *data, size_t len) +{ + dbuf_write(s, s->size, data, len); +} + +int dbuf_put_self(DynBuf *s, size_t offset, size_t len) +{ + if (unlikely((s->size + len) > s->allocated_size)) { + if (dbuf_realloc(s, s->size + len)) + return -1; + } + memcpy(s->buf + s->size, s->buf + offset, len); + s->size += len; + return 0; +} + +void dbuf_putc(DynBuf *s, uint8_t c) +{ + dbuf_write(s, s->size, &c, 1); +} + +void dbuf_putstr(DynBuf *s, const char *str) +{ + dbuf_write(s, s->size, (const uint8_t *)str, strlen(str)); +} + +void dbuf_free(DynBuf *s) +{ + free(s->buf); + memset(s, 0, sizeof(*s)); +} + +void dbuf_printf(DynBuf *s, const char *fmt, ...) +{ + va_list ap; + size_t size; + ssize_t ret; + + dbuf_realloc(s, s->size + 256); /* arbitrary initial size */ + size = s->allocated_size - s->size; + va_start(ap, fmt); + ret = vsnprintf((char *)(s->buf + s->size), size, fmt, ap); + va_end(ap); + if (ret >= size) { + /* not enough space: do it again with the correct size */ + dbuf_realloc(s, s->size + ret + 1); + size = s->allocated_size - s->size; + va_start(ap, fmt); + ret = vsnprintf((char *)(s->buf + s->size), size, fmt, ap); + va_end(ap); + assert(ret < size); + } + s->size += ret; +} + +/* DynBuf32 */ + +void dbuf32_init(DynBuf32 *s) +{ + memset(s, 0, sizeof(*s)); +} + +void dbuf32_init_set(DynBuf32 *s, const uint32_t *buf, size_t len) +{ + s->buf = malloc(sizeof(buf[0]) * len); + memcpy(s->buf, buf, sizeof(buf[0]) * len); + s->len = len; + s->allocated_len = len; +} + +void __dbuf32_realloc(DynBuf32 *s, size_t new_len) +{ + new_len = max_int(new_len, s->allocated_len + s->allocated_len / 2); + s->buf = realloc(s->buf, new_len * sizeof(uint32_t)); + s->allocated_len = new_len; +} + +void dbuf32_put(DynBuf32 *s, const uint32_t *tab, size_t l) +{ + size_t len = s->len; + dbuf32_realloc(s, len + l); + memcpy(s->buf + len, tab, l * sizeof(tab[0])); + s->len = len + l; +} + +void dbuf32_free(DynBuf32 *s) +{ + free(s->buf); + memset(s, 0, sizeof(*s)); +} + +/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes + are output. */ +int unicode_to_utf8(uint8_t *buf, unsigned int c) +{ + uint8_t *q = buf; + + if (c < 0x80) { + *q++ = c; + } else { + if (c < 0x800) { + *q++ = (c >> 6) | 0xc0; + } else { + if (c < 0x10000) { + *q++ = (c >> 12) | 0xe0; + } else { + if (c < 0x00200000) { + *q++ = (c >> 18) | 0xf0; + } else { + if (c < 0x04000000) { + *q++ = (c >> 24) | 0xf8; + } else if (c < 0x80000000) { + *q++ = (c >> 30) | 0xfc; + *q++ = ((c >> 24) & 0x3f) | 0x80; + } else { + return 0; + } + *q++ = ((c >> 18) & 0x3f) | 0x80; + } + *q++ = ((c >> 12) & 0x3f) | 0x80; + } + *q++ = ((c >> 6) & 0x3f) | 0x80; + } + *q++ = (c & 0x3f) | 0x80; + } + return q - buf; +} + +static const unsigned int utf8_min_code[5] = { + 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, +}; + +static const unsigned char utf8_first_code_mask[5] = { + 0x1f, 0xf, 0x7, 0x3, 0x1, +}; + +/* return -1 if error. *pp is not updated in this case. max_len must + be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ +int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) +{ + int l, c, b, i; + + c = *p++; + if (c < 0x80) { + *pp = p; + return c; + } + switch(c) { + case 0xc0 ... 0xdf: + l = 1; + break; + case 0xe0 ... 0xef: + l = 2; + break; + case 0xf0 ... 0xf7: + l = 3; + break; + case 0xf8 ... 0xfb: + l = 4; + break; + case 0xfc ... 0xfd: + l = 5; + break; + default: + return -1; + } + /* check that we have enough characters */ + if (l > (max_len - 1)) + return -1; + c &= utf8_first_code_mask[l - 1]; + for(i = 0; i < l; i++) { + b = *p++; + if (b < 0x80 || b >= 0xc0) + return -1; + c = (c << 6) | (b & 0x3f); + } + if (c < utf8_min_code[l - 1]) + return -1; + *pp = p; + return c; +} + +/* return the string length */ +int utf8_to_utf32(uint32_t **pout_buf, const uint8_t *buf, + size_t buf_len) +{ + const uint8_t *buf_end; + DynBuf32 out_buf; + uint32_t c; + + dbuf32_init(&out_buf); + + buf_end = buf + buf_len; + while (buf < buf_end) { + c = unicode_from_utf8(buf, buf_end - buf, &buf); + if (c == -1) + break; + dbuf32_putc(&out_buf, c); + } + *pout_buf = out_buf.buf; + return out_buf.len; +} + +size_t utf32_to_utf8(uint8_t **pout_buf, const uint32_t *buf, + size_t buf_len) +{ + DynBuf dbuf; + size_t i; + uint32_t c; + uint8_t buf1[6]; + int l; + + dbuf_init(&dbuf); + for(i = 0; i < buf_len; i++) { + c = buf[i]; + l = unicode_to_utf8(buf1, c); + dbuf_put(&dbuf, buf1, l); + } + /* add a trailing '\0' */ + dbuf_putc(&dbuf, '\0'); + *pout_buf = dbuf.buf; + return dbuf.size - 1; +} + +BOOL is_valid_utf8(const uint8_t *buf, size_t buf_len) +{ + const uint8_t *buf_end = buf + buf_len; + int c; + + while (buf < buf_end) { + if (*buf < 0x80) { + buf++; + } else { + c = unicode_from_utf8(buf, buf_end - buf, &buf); + if (c == -1 || + c > 0x10ffff || + (c >= 0xd800 && c <= 0xdfff)) { + return FALSE; + } + } + } + return TRUE; +} + +/* we print at least 3 significant digits with at most 5 chars, except + if larger than 9999T. The value is rounded to zero. */ +char *get_si_prefix(char *buf, int buf_size, uint64_t val) +{ + static const char suffixes[4] = "kMGT"; + uint64_t base; + int i; + + if (val <= 999) { + snprintf(buf, buf_size, "%" PRId64, val); + } else { + base = 1000; + for(i=0;i<4;i++) { + /* Note: we round to 0 */ + if (val < base * 10) { + snprintf(buf, buf_size, "%0.2f%c", + floor((val * 100.0) / base) / 100.0, + suffixes[i]); + break; + } else if (val < base * 100) { + snprintf(buf, buf_size, "%0.1f%c", + floor((val * 10.0) / base) / 10.0, + suffixes[i]); + break; + } else if (val < base * 1000 || (i == 3)) { + snprintf(buf, buf_size, + "%" PRId64 "%c", + val / base, + suffixes[i]); + break; + } + base = base * 1000; + } + } + return buf; +} + +#ifdef _WIN32 +#define PATH_SEP '\\' +#else +#define PATH_SEP '/' +#endif + +static int path_is_absolute(const char *path) +{ + const char *p; + p = strchr(path, ':'); + if (p) + p++; + else + p = path; + return (*p == PATH_SEP); +} + +/* if filename is absolute, just copy it to dest. Otherwise, build a + path to it by considering it is relative to base_path. URL are + supported. */ +void path_combine(char *dest, size_t dest_size, + const char *base_path, const char *filename) +{ + const char *p, *p1; + size_t len; + + if (dest_size <= 0) + return; + if (path_is_absolute(filename)) { + pstrcpy(dest, dest_size, filename); + } else { + p = strchr(base_path, ':'); + if (p) + p++; + else + p = base_path; + p1 = strrchr(base_path, PATH_SEP); + if (p1) + p1++; + else + p1 = base_path; + if (p1 > p) + p = p1; + len = p - base_path; + if (len > dest_size - 1) + len = dest_size - 1; + memcpy(dest, base_path, len); + dest[len] = '\0'; + pstrcat(dest, dest_size, filename); + } +} diff --git a/deps/nncp/cutils.h b/deps/nncp/cutils.h new file mode 100644 index 0000000..c705a5d --- /dev/null +++ b/deps/nncp/cutils.h @@ -0,0 +1,544 @@ +/* + * C utilities + * + * Copyright (c) 2018-2023 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CUTILS_H +#define CUTILS_H + +#include +#include + +#define force_inline inline __attribute__((always_inline)) +#define no_inline __attribute__((noinline)) +#ifndef __unused +#define __unused __attribute__((unused)) +#endif +#define __maybe_unused __attribute__((unused)) +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#ifndef offsetof +#define offsetof(type, field) ((size_t) &((type *)0)->field) +#endif +#define countof(x) (sizeof(x) / sizeof(x[0])) +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +typedef int BOOL; + +#ifndef FALSE +enum { + FALSE = 0, + TRUE = 1, +}; +#endif + +typedef uint8_t BOOL8; + +typedef struct { + uint16_t u16; +} nc_float16_t; + +typedef struct { + uint16_t u16; +} nc_bfloat16_t; + +typedef struct { + uint8_t u8; +} e5m2_t; + +typedef struct { + uint8_t u8; +} e4m3_t; + +#if defined(__x86_64__) +static inline int64_t get_cycles(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} +#elif defined(__i386__) +static inline int64_t get_cycles(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} +#else +#include + +/* in ns */ +static inline int64_t get_cycles(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +} +#endif + +static inline int max_int(int a, int b) +{ + if (a > b) + return a; + else + return b; +} + +static inline int min_int(int a, int b) +{ + if (a < b) + return a; + else + return b; +} + +static inline size_t max_size_t(size_t a, size_t b) +{ + if (a > b) + return a; + else + return b; +} + +static inline size_t min_size_t(size_t a, size_t b) +{ + if (a < b) + return a; + else + return b; +} + +static inline ssize_t max_ssize_t(ssize_t a, ssize_t b) +{ + if (a > b) + return a; + else + return b; +} + +static inline ssize_t min_ssize_t(ssize_t a, ssize_t b) +{ + if (a < b) + return a; + else + return b; +} + +static inline float max_float(float a, float b) +{ + if (a > b) + return a; + else + return b; +} + +static inline float min_float(float a, float b) +{ + if (a < b) + return a; + else + return b; +} + +static inline int clamp_int(int val, int min_val, int max_val) +{ + if (val < min_val) + return min_val; + else if (val > max_val) + return max_val; + else + return val; +} + +static inline int ceil_udiv(int a, int b) +{ + return (a + b - 1) / b; +} + +/* return floor(a / b) with b >= 1 */ +static inline int floor_div(int a, int b) +{ + if (a >= 0) { + return a / b; + } else { + return (a - b + 1) / b; + } +} + +/* return ceil(a / b) with b >= 1 */ +static inline int ceil_div(int a, int b) +{ + if (a >= 0) { + return (a + b - 1) / b; + } else { + return a / b; + } +} + +/* return r = a modulo b (0 <= r <= b - 1 */ +static inline unsigned int mod_int(int a, unsigned int b) +{ + a = a % (int)b; + if (a < 0) + a += b; + return a; +} + +/* b must be a power of two */ +static inline int align_int(int a, int b) +{ + return (a + b - 1) & ~(b - 1); +} + +static inline size_t align_size_t(size_t a, size_t b) +{ + return (a + b - 1) & ~(b - 1); +} + +static inline float clamp_float(float val, float min_val, float max_val) +{ + if (val < min_val) + return min_val; + else if (val > max_val) + return max_val; + else + return val; +} + +typedef union { + uint32_t u32; + float f; +} f32_union; + +static inline uint32_t float_as_uint(float f) +{ + f32_union u; + u.f = f; + return u.u32; +} + +static inline float uint_as_float(uint32_t v) +{ + f32_union u; + u.u32 = v; + return u.f; +} + +/* WARNING: undefined if a = 0 */ +static inline int clz32(unsigned int a) +{ + return __builtin_clz(a); +} + +/* WARNING: undefined if a = 0 */ +static inline int clz64(uint64_t a) +{ + return __builtin_clzll(a); +} + +/* WARNING: undefined if a = 0 */ +static inline int ctz64(uint64_t a) +{ + return __builtin_ctzll(a); +} + +/* WARNING: undefined if a = 0 */ +static inline int ctz32(unsigned int a) +{ + return __builtin_ctz(a); +} + +static inline int floor_log2(uint64_t a) +{ + return 63 - clz64(a); +} + +static inline int ceil_log2(uint64_t a) +{ + if (a <= 1) + return 0; + else + return 64 - clz64(a - 1); +} + +struct __attribute__((packed)) packed_u64 { + uint64_t v; +}; + +struct __attribute__((packed)) packed_u32 { + uint32_t v; +}; + +struct __attribute__((packed)) packed_u16 { + uint16_t v; +}; + +static inline uint64_t get_u64(const uint8_t *tab) +{ + return ((const struct packed_u64 *)tab)->v; +} + +static inline int64_t get_i64(const uint8_t *tab) +{ + return (int64_t)((const struct packed_u64 *)tab)->v; +} + +static inline void put_u64(uint8_t *tab, uint64_t val) +{ + ((struct packed_u64 *)tab)->v = val; +} + +static inline uint32_t get_u32(const uint8_t *tab) +{ + return ((const struct packed_u32 *)tab)->v; +} + +static inline int32_t get_i32(const uint8_t *tab) +{ + return (int32_t)((const struct packed_u32 *)tab)->v; +} + +static inline void put_u32(uint8_t *tab, uint32_t val) +{ + ((struct packed_u32 *)tab)->v = val; +} + +static inline uint32_t get_u16(const uint8_t *tab) +{ + return ((const struct packed_u16 *)tab)->v; +} + +static inline int32_t get_i16(const uint8_t *tab) +{ + return (int16_t)((const struct packed_u16 *)tab)->v; +} + +static inline void put_u16(uint8_t *tab, uint16_t val) +{ + ((struct packed_u16 *)tab)->v = val; +} + +static inline uint32_t get_u8(const uint8_t *tab) +{ + return *tab; +} + +static inline int32_t get_i8(const uint8_t *tab) +{ + return (int8_t)*tab; +} + +static inline void put_u8(uint8_t *tab, uint8_t val) +{ + *tab = val; +} + +static inline uint16_t bswap_16(uint16_t v) +{ + return __builtin_bswap16(v); +} + +static inline uint32_t bswap_32(uint32_t v) +{ + return __builtin_bswap32(v); +} + +static inline uint64_t bswap_64(uint64_t v) +{ + return __builtin_bswap64(v); +} + +static inline uint32_t get_be32(const uint8_t *d) +{ + return bswap_32(get_u32(d)); +} + +static inline void put_be32(uint8_t *d, uint32_t v) +{ + put_u32(d, bswap_32(v)); +} + +#define GET_BITS_FAST_PADDING 3 + +/* Note: n must be such as 1 <= n <= 25. At most 3 bytes can be read + after the last byte of the data */ +static inline int get_bits_fast(const uint8_t *p, int *pindex, int n) +{ + int index; + unsigned int val; + + index = *pindex; + val = get_be32(p + (index >> 3)); + val = (val >> (32 - (index & 7) - n)) & ((1 << n) - 1); + *pindex = index + n; + return val; +} + +#define PUT_BITS_FAST_PADDING 3 + +/* Note: the MSB bits of 'bits' must be zero. PUT_BITS_FAST_PADDING + are read and written after the end of the exact size (in bytes). */ +static inline void put_bits_fast(uint8_t *p, int *pindex, int n, int bits) +{ + int index; + unsigned int val; + index = *pindex; + p += index >> 3; + /* XXX: optimize */ + val = get_be32(p); + val |= bits << (32 - (index & 7) - n); + put_be32(p, val); + index += n; + *pindex = index; +} + +static inline float squaref(float x) +{ + return x * x; +} + +#define DUP8(a) a, a, a, a, a, a, a, a + +void *mallocz(size_t size); +void pstrcpy(char *buf, int buf_size, const char *str); +char *pstrcat(char *buf, int buf_size, const char *s); +int strstart(const char *str, const char *val, const char **ptr); +BOOL has_suffix(const char *str, const char *suffix); +#ifdef _WIN32 +void *memmem(const void *hs1, size_t hs_len, const void *ne1, size_t ne_len); +#endif +void *memdup(const void *ptr, size_t size); +char *strdup_len(const char *str, size_t len); + +static inline void __buf_expand(void **pbuf, int *psize, int count, int elem_size) +{ + int new_size; + if (unlikely(count > *psize)) { + new_size = max_int(*psize + *psize / 2, count); + *pbuf = realloc(*pbuf, new_size * elem_size); + *psize = new_size; + } +} + +#define BUF_EXPAND(pbuf, psize, count) __buf_expand((void **)(pbuf), psize, count, sizeof(**(pbuf))) + +typedef struct { + uint8_t *buf; + size_t size; + size_t allocated_size; +} DynBuf; + +void dbuf_init(DynBuf *s); +int __dbuf_realloc(DynBuf *s, size_t new_size); +static inline int dbuf_realloc(DynBuf *s, size_t new_size) +{ + if (unlikely(new_size > s->allocated_size)) + return __dbuf_realloc(s, new_size); + else + return 0; +} +void dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); +void dbuf_put(DynBuf *s, const void *data, size_t len); +int dbuf_put_self(DynBuf *s, size_t offset, size_t len); +static inline void dbuf_put_u16(DynBuf *s, uint16_t val) +{ + dbuf_put(s, (uint8_t *)&val, 2); +} +static inline void dbuf_put_u32(DynBuf *s, uint32_t val) +{ + dbuf_put(s, (uint8_t *)&val, 4); +} +static inline void dbuf_put_u64(DynBuf *s, uint64_t val) +{ + dbuf_put(s, (uint8_t *)&val, 8); +} +void dbuf_putc(DynBuf *s, uint8_t c); +void dbuf_putstr(DynBuf *s, const char *str); +void __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, const char *fmt, ...); +void dbuf_free(DynBuf *s); + +static inline int dbuf_error(DynBuf *s) +{ + return 0; +} + +typedef struct { + uint32_t *buf; + size_t len; + size_t allocated_len; +} DynBuf32; + +void dbuf32_init(DynBuf32 *s); +void dbuf32_init_set(DynBuf32 *s, const uint32_t *buf, size_t len); + +void __dbuf32_realloc(DynBuf32 *s, size_t new_len); +static inline void dbuf32_realloc(DynBuf32 *s, size_t new_len) +{ + if (unlikely(new_len > s->allocated_len)) + __dbuf32_realloc(s, new_len); +} + +static inline void dbuf32_putc(DynBuf32 *s, uint32_t c) +{ + size_t len = s->len; + dbuf32_realloc(s, len + 1); + s->buf[len++] = c; + s->len = len; +} + +void dbuf32_put(DynBuf32 *s, const uint32_t *tab, size_t len); + +void dbuf32_free(DynBuf32 *s); + +#define UTF8_CHAR_LEN_MAX 6 + +int unicode_to_utf8(uint8_t *buf, unsigned int c); +int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); + +static inline int from_hex(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + return -1; +} + +int utf8_to_utf32(uint32_t **pout_buf, const uint8_t *buf, + size_t buf_len); +size_t utf32_to_utf8(uint8_t **pout_buf, const uint32_t *buf, + size_t buf_len); +BOOL is_valid_utf8(const uint8_t *buf, size_t buf_len); + +char *get_si_prefix(char *buf, int buf_size, uint64_t val); + +void path_combine(char *dest, size_t dest_size, + const char *base_path, const char *filename); + +#endif /* CUTILS_H */ diff --git a/deps/nncp/libnc.h b/deps/nncp/libnc.h new file mode 100644 index 0000000..cfd944f --- /dev/null +++ b/deps/nncp/libnc.h @@ -0,0 +1,638 @@ +/* + * LibNC + * + * Copyright (c) 2018-2023 Fabrice Bellard + * + */ +#ifndef LIBNC_H +#define LIBNC_H + +#include +#include "cutils.h" +#include "list.h" + +/* profiling */ + +typedef enum { + PROF_EVAL, + PROF_GRAD, + PROF_SGD, + PROF_UPDATE, + PROF_WRITE_SYM, + PROF_PROBE, + PROF_TOTAL, + PROF_COUNT, +} ProfEnum; + +#ifdef PROFILE + +extern int64_t prof_cycles[PROF_COUNT]; +extern int64_t prof_samples[PROF_COUNT]; +extern int64_t prof_ops[PROF_COUNT]; + +static inline void prof_start(int idx) +{ + prof_cycles[idx] -= get_cycles(); +} + +static inline void prof_end(int idx) +{ + prof_cycles[idx] += get_cycles(); + prof_samples[idx]++; +} + +static inline void prof_end_ops(int idx, int n_ops) +{ + prof_cycles[idx] += get_cycles(); + prof_ops[idx] += n_ops; + prof_samples[idx]++; +} + +#else + +static inline void prof_start(int idx) +{ +} + +static inline void prof_end(int idx) +{ +} + +static inline void prof_end_ops(int idx, int n_ops) +{ +} + +#endif + +void nc_prof_dump(void); + +/* Automatic Differentiation Engine */ + +typedef struct NCContext NCContext; +typedef struct NCDevice NCDevice; +typedef struct NCTensor NCTensor; +typedef struct NCTensorBuffer NCTensorBuffer; +typedef struct NCNode NCNode; +typedef struct NCLazyTensor NCLazyTensor; +typedef struct NCRNDState NCRNDState; +typedef struct NCSGDOptState NCSGDOptState; + +typedef enum { + NC_TYPE_F32, + NC_TYPE_BF16, + NC_TYPE_F16, + NC_TYPE_I8, + NC_TYPE_I16, + NC_TYPE_I32, + NC_TYPE_U8, + NC_TYPE_U16, + NC_TYPE_U32, + NC_TYPE_E4M3, + NC_TYPE_E5M2, + NC_TYPE_BF8, + NC_TYPE_BF4, + NC_TYPE_BF3, + NC_TYPE_BF8L, + NC_TYPE_BF8C, /* internal format */ + NC_TYPE_COUNT, +} NCTypeEnum; + +extern size_t nc_type_size_table[NC_TYPE_COUNT]; +extern int nc_type_size_log2_table[NC_TYPE_COUNT]; +extern const char *nc_type_name_table[NC_TYPE_COUNT]; + +#define NC_N_DIMS_MAX 8 /* maximum number of axis for tensors */ + +typedef struct NCTensorData { + NCTypeEnum item_type; + size_t item_size; + void *data; + size_t stride; /* in elements */ + size_t n_strides; /* prod(j = 1 ... n_dims, dims[j]); */ + int n_dims; + const size_t *dims; /* n_dims length */ + const size_t *strides; /* n_dims length, strides in bytes */ +} NCTensorData; + +void *nc_malloc(size_t size); +void *nc_mallocz(size_t size); +void nc_free(void *ptr); + +/* return the number of available threads */ +int nc_get_n_available_threads(void); + +NCContext *nc_context_init(int nb_threads); +void nc_context_end(NCContext *m); + +NCDevice *nc_new_cpu_device(NCContext *m); +NCDevice *nc_new_cuda_device(NCContext *m, int device_index); +NCDevice *nc_new_device(NCContext *m, const char *device_name); +void nc_synchronize(NCDevice *d); +/* must be called at the beginning of a new thread to initialize the + device specific data */ +void nc_thread_init(NCDevice *d); + +NCTensorBuffer *nc_new_tensor_buffer(NCDevice *d, size_t size); +NCTensorBuffer *nc_dup_tensor_buffer(const NCTensorBuffer *b); +void nc_free_tensor_buffer(NCTensorBuffer *b); +int64_t nc_tensor_buffer_get_size(NCTensorBuffer *b); +/* return the number of allocated bytes on the device for tensor buffers */ +int64_t nc_get_allocated_memory_size(NCDevice *d); +int64_t nc_get_max_allocated_memory_size(NCDevice *d, BOOL reset); +int64_t nc_get_flop_count(NCContext *m); +/* enable/disable reproducible computation (same results regardless of + the CPU/GPU model and threading configuration). Return the previous + state. Some operations are slower. */ +BOOL nc_set_reproducible(NCContext *m, BOOL enable); + +NCTensor *nc_new_tensor_from_buffer(NCContext *m, + NCTensorBuffer *buffer, NCTypeEnum type, + int n_dims, const size_t *dims, + size_t offset, const size_t *strides, + float scale); +NCTensor *nc_new_tensor(NCDevice *d, NCTypeEnum type, + int n_dims, const size_t *dims); +NCTensor *nc_new_tensor_from_tensor(const NCTensor *x); +NCTensor *nc_new_scalar(NCDevice *d, NCTypeEnum type); +NCTensor *nc_new_tensor_1d(NCDevice *d, NCTypeEnum type, size_t len); +NCTensor *nc_new_tensor_2d(NCDevice *d, NCTypeEnum type, size_t n0, size_t n1); +NCTensor *nc_new_tensor_3d(NCDevice *d, NCTypeEnum type, + size_t n0, size_t n1, size_t n2); +NCTensor *nc_new_tensor_4d(NCDevice *d, NCTypeEnum type, + size_t n0, size_t n1, size_t n2, size_t n3); +NCTensor *nc_new_tensor_nz(NCDevice *d, NCTypeEnum type, + int n_dims, const size_t *dims); +NCTensor *nc_new_tensor_from_tensor_nz(const NCTensor *x); +NCTensor *nc_new_tensor_nz_1d(NCDevice *d, NCTypeEnum type, size_t len); +NCTensor *nc_new_tensor_nz_2d(NCDevice *d, NCTypeEnum type, size_t n0, size_t n1); +NCTensor *nc_new_tensor_nz_3d(NCDevice *d, NCTypeEnum type, + size_t n0, size_t n1, size_t n2); +NCTensor *nc_new_tensor_nz_4d(NCDevice *d, NCTypeEnum type, + size_t n0, size_t n1, size_t n2, size_t n3); +NCTensor *__attribute__((format(printf, 2, 3))) nc_tensor_set_name(NCTensor *x, const char *fmt, ...); +NCTensor *nc_dup_tensor(const NCTensor *x); +void nc_free_tensor(NCTensor *x); +void nc_dump_tensor(const char *name, const NCTensor *x, size_t n); +void nc_dump_tensor_strides(const char *name, const NCTensor *x); +uint32_t nc_tensor_get_hash(const NCTensor *x); +BOOL nc_tensor_isfinite(NCTensor *x); +void nc_dump_tensor_hash(const char *name, const NCTensor *x); +NCNode *nc_get_node(NCTensor *x); +NCTypeEnum nc_tensor_get_item_type(const NCTensor *x); +NCTensorData *nc_tensor_get_data(NCTensorData *sd, const NCTensor *x); +/* Return a pointer to the tensor data. If *pstride is non NULL, + return the stride (in elements) of the first dimension. */ +void *nc_tensor_get_ptr(const NCTensor *x, size_t *pstride); +int nc_tensor_get_n_dims(const NCTensor *x); +size_t nc_tensor_get_dim(const NCTensor *x, int axis); +size_t nc_tensor_get_stride(const NCTensor *x, int axis); +int nc_tensor_get_dims(const NCTensor *x, size_t *dims); +int64_t nc_tensor_get_buffer_size(NCTensor *x); +BOOL nc_same_shape(const NCTensor *x1, const NCTensor *x2); +void nc_tensor_set_zero(NCTensor *y); +void nc_tensor_set_u32(NCTensor *y, uint32_t val); +void nc_tensor_set_f32(NCTensor *y, float val); +NCRNDState *nc_rnd_init(NCDevice *d, uint32_t seed); +void nc_rnd_end(NCRNDState *s); +void nc_tensor_set_rnd_unif(NCTensor *y, float avg, float range, + NCRNDState *rnd_state); +void nc_tensor_set_rnd_gaussian(NCTensor *y, float avg, float sigma, + NCRNDState *rnd_state); +void nc_tensor_set_dropout(NCTensor *y, float prob, NCRNDState *rnd_state); + +void nc_set1_i32(NCTensor *y, int n_dims, const size_t *tab_indexes, + int32_t val); +void nc_set1_i32_1d(NCTensor *y, size_t i0, int32_t val); +void nc_set1_i32_2d(NCTensor *y, size_t i0, size_t i1, int32_t val); +void nc_set1_f32(NCTensor *y, int n_dims, const size_t *tab_indexes, + float val); +void nc_set1_f32_1d(NCTensor *y, size_t i0, float val); + +int32_t nc_get1_i32(const NCTensor *x, int n_dims, const size_t *tab_indexes); +float nc_get1_f32(const NCTensor *x, int n_dims, const size_t *tab_indexes); +float nc_get1_f32_1d(const NCTensor *x, size_t i0); +float nc_get_scalar_f32(const NCTensor *x); +/* same as nc_get_scalar_f32() but free the tensor */ +float nc_tensor_to_scalar_f32(NCTensor *x); + +void nc_tensor_copy(NCTensor *dst, NCTensor *src); +void nc_tensor_copy_slice(NCTensor *dst, NCTensor *src, int axis, + size_t dst_start, size_t dst_end, size_t src_start); +void nc_tensor_convert(NCTensor *dst, NCTensor *src); + +void nc_dump_dims(const char *str, const NCTensor *x); +size_t nc_get_heap_size(NCContext *m); +NCContext *nc_get_tensor_context(const NCTensor *x); +NCTensor *nc_tensor_to_device(NCTensor *x, NCDevice *d); +NCTensor *nc_tensor_to_cpu_device(NCTensor *x); +NCDevice *nc_get_tensor_device(const NCTensor *x); + +/* element wise operations */ +NCTensor *nc_convert(NCTensor *x, NCTypeEnum new_type); +NCTensor *nc_add(NCTensor *x1, NCTensor *x2); +NCTensor *nc_neg(NCTensor *x); +NCTensor *nc_sub(NCTensor *x1, NCTensor *x2); +NCTensor *nc_mul(NCTensor *x1, NCTensor *x2); +NCTensor *nc_div(NCTensor *x1, NCTensor *x2); +NCTensor *nc_recip(NCTensor *x); +NCTensor *nc_min(NCTensor *x1, NCTensor *x2); +NCTensor *nc_max(NCTensor *x1, NCTensor *x2); +/* select x1[i] if z[i] = 0 and x2[i] otherwise */ +NCTensor *nc_select(NCTensor *z, NCTensor *x1, NCTensor *x2); +/* set y[i] = x1[i] if mask[i] = 0 and y[i] = c if mask[i] != 0. If + mask_inv is TRUE, 'mask' is inverted */ +NCTensor *nc_masked_fill(NCTensor *x, NCTensor *mask, float c, BOOL mask_inv); +NCTensor *nc_sigmoid(NCTensor *x); +NCTensor *nc_tanh(NCTensor *x); +NCTensor *nc_relu(NCTensor *x); +NCTensor *nc_sqr_relu(NCTensor *x); +NCTensor *nc_swish(NCTensor *x, float beta); +/* g * swish(x) */ +NCTensor *nc_gated_swish(NCTensor *g, NCTensor *x, float beta); +NCTensor *nc_gelu(NCTensor *x); +/* g * gelu(x) */ +NCTensor *nc_geglu(NCTensor *g, NCTensor *x); +void nc_geglu_bw(NCTensor **pgg, NCTensor **pxg, NCTensor **py, + NCTensor *yg, NCTensor *g, NCTensor *x); +/* x + sin(a*x)^2/(a + eps) */ +NCTensor *nc_snake(NCTensor *x, NCTensor *a, float eps); +NCTensor *nc_log(NCTensor *x); +NCTensor *nc_exp(NCTensor *x); +/* return cp * fg + min(1 - fg, ig) * in */ +NCTensor *nc_lstm_clamped(NCTensor *cp, NCTensor *in, + NCTensor *fg, NCTensor *ig); +/* RWKV attention. + aa, bb, pp =(bs, d) + k, v, result = (bs, s, d) + u, w = (d) + Warning: aa, bb and pp are modified in place +*/ +NCTensor *nc_rwkv_att(NCTensor *aa, NCTensor *bb, NCTensor *pp, + NCTensor *k, NCTensor *v, NCTensor *u, NCTensor *w); +/* return a * (1 - t) + b * t */ +NCTensor *nc_lerp(NCTensor *a, NCTensor *b, NCTensor *t); +/* return y = clamp(x * mult + addend, v_min, v_max) with an integer d_type */ +NCTensor *nc_convert_clamp(NCTensor *x, float mult, float addend, float v_min, float v_max, + NCTypeEnum d_type); +/* other operations */ +NCTensor *nc_new_f32(NCDevice *d, float val); +/* use the same device and type as tensor 'x' */ +NCTensor *nc_new_f32_from_tensor(const NCTensor *x, float val); +NCTensor *nc_reshape(NCTensor *x, int n_dims, const size_t *dims); +NCTensor *nc_reshape_1d(NCTensor *x, size_t n0); +NCTensor *nc_reshape_2d(NCTensor *x, size_t n0, size_t n1); +NCTensor *nc_reshape_3d(NCTensor *x, size_t n0, size_t n1, size_t n2); +NCTensor *nc_reshape_4d(NCTensor *x, size_t n0, size_t n1, size_t n2, + size_t n3); +NCTensor *nc_reshape_5d(NCTensor *x, size_t n0, size_t n1, size_t n2, + size_t n3, size_t n4); +/* duplicate the tensor by adding n_dims dimensions */ +NCTensor *nc_repeat(NCTensor *x, int n_dims, const size_t *dims); +NCTensor *nc_repeat_1d(NCTensor *x, size_t n0); +NCTensor *nc_repeat_2d(NCTensor *x, size_t n0, size_t n1); +/* return y0 + sum over the dimensions > n_dims of 'x'. y0 = NULL + is supported */ +NCTensor *nc_reduce_sum(NCTensor *y0, NCTensor *x, int n_dims); +/* reduce sum on axis. The corresponding dimension is set to 1 */ +NCTensor *nc_reduce_sum_axis(NCTensor *x, int axis); +/* sum all the elements of a tensor */ +NCTensor *nc_sum(NCTensor *x); +/* sum of squares */ +NCTensor *nc_reduce_sum_sqr(NCTensor *x); +/* return the maximum on axis 0 and the corresponding indices of the + maximum element. 'pindices' can be NULL. */ +NCTensor *nc_reduce_max(NCTensor **pindices, NCTensor *x); +NCTensor *nc_cumsum(NCTensor *x); +/* create an alias to tensor 'x1' */ +NCTensor *nc_slice_alias(const NCTensor *x1, int axis, size_t start, size_t end); +NCTensor *nc_slice(NCTensor *x, int axis, size_t start, size_t end); +NCTensor *nc_slice_add(NCTensor *y0, NCTensor *x, int axis, size_t start); +/* concatenation along axis 'axis' */ +NCTensor *nc_concat(NCTensor **inputs, int n_inputs, int axis); +/* shortcut with n_inputs = 2 */ +NCTensor *nc_concat_2(NCTensor *x0, NCTensor *x1, int axis); +/* shortcut for axis = 0 */ +NCTensor *nc_vconcat(NCTensor **inputs, int n_inputs); +/* shortcut for axis = 1 */ +NCTensor *nc_hconcat(NCTensor **inputs, int n_inputs); +/* split along axis 'axis'. If tab_size = NULL, split equally. */ +void nc_split(NCTensor **tab_y, NCTensor *x, int n_outputs, + const size_t *tab_size, int axis); +/* specialized for n_outputs = 2 */ +void nc_split_2(NCTensor **py0, NCTensor **py1, NCTensor *x, + size_t size0, size_t size1, int axis); + +typedef enum { + NC_PAD_ZERO, + NC_PAD_DUP, /* duplicate element */ + /* trim types, dual to padding */ + NC_TRIM_NORMAL = NC_PAD_ZERO, + NC_TRIM_SUM, /* add trimmed elements to the edge */ +} NCPadEnum; + +/* pad (len > 0) or trim (len < 0) the axis 0 of 'x' */ +NCTensor *nc_pad(NCTensor *x, ssize_t left_len, NCPadEnum left_op, + ssize_t right_len, NCPadEnum right_op); +/* shortcut to nc_pad() */ +NCTensor *nc_resize(NCTensor *x, size_t n); +NCTensor *nc_resize_axis(NCTensor *x, int axis, size_t n); +/* can reduce the size or increase it if the corresponding dimension + is 1. -1 indicates to keep the size. */ +NCTensor *nc_resize_alias(NCTensor *x, int n_dims, const size_t *dims); +/* same as nc_reslize_alias but for one axis */ +NCTensor *nc_resize_alias_1(NCTensor *x, int axis, size_t n); +NCTensor *nc_resize_alias_4d(NCTensor *x, size_t n0, size_t n1, size_t n2, size_t n3); + +/* return a new tensor which is a copy of 'x' */ +NCTensor *nc_clone(NCTensor *x); +/* return TRUE is the tensor is stored in contiguous storage elements */ +BOOL nc_tensor_is_contiguous(const NCTensor *x); +/* if x is not contiguous then create a new contiguous tensor and copy + x to it. Otherwise, return 'x'. */ +NCTensor *nc_make_contiguous(NCTensor *x); +/* Return a new tensor sharing the same buffer as 'x' with the permuted + dimensions. axis[i] is the corresponding axis in 'x' */ +NCTensor *nc_permute_alias(NCTensor *x, int n_dims, const int *axis); +NCTensor *nc_permute_alias_4d(NCTensor *x, int a0, int a1, int a2, int a3); +/* same as nc_permute_alias but calls nc_make_contiguous after. */ +NCTensor *nc_permute(NCTensor *x, int n_dims, const int *axis); +NCTensor *nc_permute_3d(NCTensor *x, int a0, int a1, int a2); +NCTensor *nc_permute_4d(NCTensor *x, int a0, int a1, int a2, int a3); +/* special case of nc_permute() */ +NCTensor *nc_transpose(NCTensor *x); +/* enable reproducible results on CPU and GPU. Currently only works with the F32 type */ +#define NC_MATMUL_FLAG_REPRODUCIBLE (1 << 0) +/* return a*b*alpha + c. a and b can be optionally transposed. c can + be NULL. */ +NCTensor *nc_matmul_add2(NCTensor *a, NCTensor *b, NCTensor *c0, + BOOL a_trans, BOOL b_trans, float alpha, int flags); +/* same as nc_matmul_add2 with flags = 0 */ +NCTensor *nc_matmul_add(NCTensor *w, NCTensor *x, NCTensor *c, + BOOL w_trans, BOOL x_trans, float alpha); +/* same as nc_matmul_add with c = NULL, a_trans = FALSE, b_trans = FALSE and alpha = 1 */ +NCTensor *nc_matmul(NCTensor *w, NCTensor *x); +/* return a matrix where each column is the column x[i] of matrix 'w' */ +NCTensor *nc_get_col(NCTensor *w, NCTensor *x); +/* add the vectors 'z' at column number 'x' in matrix 'w'. */ +NCTensor *nc_add_col(NCTensor *z, NCTensor *x, NCTensor *w); +/* select the x-th element in each column of 'w' */ +NCTensor *nc_get_element(NCTensor *w, NCTensor *x); +/* add z to the x-th element in each column of 'w' */ +NCTensor *nc_add_element(NCTensor *z, NCTensor *x, NCTensor *w); +NCTensor *nc_soft_max(NCTensor *x); +/* max(soft_max[i] * mult, 1) converted to int32 */ +NCTensor *nc_soft_max_int(NCTensor *x, float mult); +/* Equivalent to y = log(get_element(x, eout)). It is expected to be + used as nc_index_log(nc_soft_max(x), eout) so that the gradient + computation is optimized. */ +NCTensor *nc_indexed_log(NCTensor *x, NCTensor *eout); +NCTensor *nc_layer_norm(NCTensor *x, float eps); +NCTensor *nc_rms_norm(NCTensor *x, float eps); +/* compute layer_norm(x)*w+b. 'w' and 'b' must be both either != NULL + or NULL. avg_flag = FALSE: rms_norm, avg_flag = TRUE: + layer_norm. */ +NCTensor *nc_fused_layer_norm(NCTensor *x, NCTensor *w, NCTensor *b, + float eps, BOOL avg_flag); +/* shift the column 'i' by 'pos + i * mult' elements and pad with with zeros */ +NCTensor *nc_rel_shift(NCTensor *x, ssize_t pos, ssize_t mult); +/* complex multiplication of complex numbers. packed format: real part + in even indices, imaginary part in odd indices. planar format: real + part in first half of the vector, imaginary part in second half. x2 + is conjugated if 'is_conj' is true. */ +NCTensor *nc_cmul(NCTensor *x1, NCTensor *x2, BOOL is_conj, BOOL is_planar); +NCTensor *nc_cmul_rotpos(NCTensor *x1, NCTensor *x2, BOOL is_conj); +/* x=(N, H, W, C) weight=(K, R, S, C), bias=(K) or NULL, result=(N, P, Q, K) */ +NCTensor *nc_conv_2d(NCTensor *x, NCTensor *weight, NCTensor *bias, + int pad_left, int pad_right, int pad_top, int pad_bottom, + int stride_x, int stride_y, int dil_x, int dil_y); +/* x=(N, H, C) weight=(K, R, C), bias=(K), result=(N, P, K) */ +NCTensor *nc_conv_1d(NCTensor *x, NCTensor *weight, NCTensor *bias, + int pad_left, int pad_right, int stride_x, int dil_x); +/* x=(N, P, Q, K) weight=(K, R, S, C), bias=(C), result=(N, H, W, C) */ +NCTensor *nc_conv_transpose_2d(NCTensor *x, NCTensor *weight, NCTensor *bias, + int pad_left, int pad_right, int pad_top, int pad_bottom, + int stride_x, int stride_y, int dil_x, int dil_y, + int out_pad_x, int out_pad_y); +/* x=(N, P, K) weight=(K, R, C), bias=(C), result=(N, H, C) */ +NCTensor *nc_conv_transpose_1d(NCTensor *x, NCTensor *weight, NCTensor *bias, + int pad_left, int pad_right, + int stride_x, int dil_x, int out_pad_x); + +/* only for testing */ +void nc_conv_force_im2col(NCContext *m, BOOL enable); +NCTensor *nc_im2col(NCTensor *x, int P, int Q, int R, int S, + int pad_x, int pad_y, int stride_x, int stride_y, + int dil_x, int dil_y); +NCTensor *nc_col2im(NCTensor *x, int H, int W, int P, int Q, int R, int S, + int pad_x, int pad_y, int stride_x, int stride_y, + int dil_x, int dil_y); +/* x = (B, H, W, C) w, b = (C). C must be a multiple of num_groups */ +NCTensor *nc_group_norm(NCTensor *x, NCTensor *w, NCTensor *b, + int num_groups, float eps); +/* upsample by duplicating the samples */ +NCTensor *nc_upsample(NCTensor *x, int factor); +/* f8 conversion with automatic scaling */ +typedef struct { + NCTypeEnum type; + int exp_margin; + NCTensor *last_max; + float cur_inv_scale; /* factor when converting to f8 */ + BOOL redo_flag; + BOOL is_first; + char *name; +} NCConvertToF8Context; + +NCConvertToF8Context *nc_convert_to_f8_init(NCDevice *d, NCTypeEnum type, int exp_margin, BOOL redo_flag, const char *name); +void nc_convert_to_f8_update(NCConvertToF8Context *fcs); +void nc_convert_to_f8_end(NCConvertToF8Context *fcs); +NCTensor *nc_convert_to_f8(NCTensor *x, NCConvertToF8Context *fcs); + +/* auto differentiation */ + +/* get_col_index is non NULL in the sparse gradient case */ +typedef void NCParamUpdateFunc(void *opaque, NCTensor *grad, + NCTensor *get_col_index); + +/* add a 'parameter' graph node to 'x' and return 'x'. */ +NCTensor *nc_set_param(NCTensor *x, void *opaque); +/* return a new tensor with its graph removed */ +NCTensor *nc_stop_grad(NCTensor *x); + +/* manipulation of graph nodes */ +NCNode *nc_dup_node(const NCNode *n); +void nc_free_node(NCNode *n); +void nc_combine_nodes(NCContext *m, NCNode **tab_op1, int count, + int axis, int elem_size, const size_t *tab_elem_size); +NCNode *nc_concat_node(NCContext *m, NCNode **inputs, int count, + int axis, const size_t *tab_size); +void nc_concat_optimization(NCContext *m, NCNode **concat_nodes, int count); +void nc_node_set_parent(NCNode *n, int arg_index, const NCNode *n1); +void nc_node_set_arg(NCNode *n, int arg_index, const NCTensor *x); +/* '...' represents n_args 'const NCTensor *' */ +void nc_node_set_args(NCNode *n, int n_args, ...); + +#define NC_BW_KEEP_GRAD_GRAPH (1 << 0) +/* optimize the nc_get_col() gradient */ +#define NC_BW_SPARSE_GRAD (1 << 1) +/* keep the saved arguments so that nc_bacward() can be called again */ +#define NC_BW_KEEP_ARGS (1 << 2) + +void nc_backward(const NCTensor *x, NCTensor *grad, + NCParamUpdateFunc *param_update_func, int flags); +void nc_dump_graph(NCTensor *x); + +/* tensor rematerialization */ + +/* return a new tensor with evaluation graph recording enabled. The + operations generating values from this value are recorded so that + they can be executed again to get the same value e.g. to save + memory for back propagation. Not all operations support this + feature. */ +NCTensor *nc_tensor_enable_eval_graph(NCTensor *x); +/* disable the evaluation graph recording */ +NCTensor *nc_tensor_stop_eval_graph(NCTensor *x); +NCLazyTensor *nc_lazy_tensor_from_tensor(const NCTensor *x); +NCTensor *nc_lazy_tensor_eval2(NCLazyTensor *lt, BOOL dump); +NCTensor *nc_lazy_tensor_eval(NCLazyTensor *lt); +void nc_free_lazy_tensor(NCLazyTensor *lt); + +/* utilities for function parameters */ + +typedef struct { + struct list_head link; + NCTensor **pval; /* pointer to the tensor location */ + char *name; /* parameter name */ + NCTensor *saved_grad; /* debug */ + /* SGD opt data */ + struct SGDOptVarState *sgd_opt; + float lr_mult; /* the global learning rate is multiplied by lr_mult */ + NCConvertToF8Context *fcs; /* only used with FP8 */ +} NCParam; + +typedef struct { + NCContext *ctx; + struct list_head param_list; + BOOL add_graph; +} NCParamList; + +void nc_param_list_init(NCContext *m, NCParamList *pl); +void nc_param_list_set_graph(NCParamList *pl, BOOL add_graph); +NCParam *nc_new_param_str(NCParamList *pl, NCTensor **pval, const char *str); +__attribute__((format(printf, 3, 4))) NCParam *nc_new_param(NCParamList *pl, NCTensor **pval, const char *fmt, ...); +void nc_param_list_end(NCParamList *pl); + +NCParam *nc_find_param(NCParamList *pl, const char *name); +size_t nc_get_param_count(NCParamList *pl); + +/* parameter file handling */ +void nc_save_param_header(FILE *f, const char *config); +void nc_save_param(FILE *f, const NCTensor *v1, const char *name); +void nc_save_coefs(NCParamList *pl, const char *filename); +/* return a pointer to the allocated configuration or NULL if + error. Use nc_free() to free the configuration data. */ +char *nc_load_param_header(FILE *f); +/* return NULL if EOF. 'name' is filled with the saved parameter name. */ +NCTensor *nc_load_param(NCContext *m, FILE *f, char *name, size_t name_size); +void nc_load_coefs(NCParamList *pl, const char *filename); + +/* SGD optimizer */ + +typedef enum { + SGD_OPT_BASIC, + SGD_OPT_ADAM, + SGD_OPT_TEST, +} SGDOptAlgoEnum; + +typedef struct { + SGDOptAlgoEnum algo; + union { + struct { + float beta1; + float beta2; + float eps; + float gradient_clip; /* if != 0, per parameter gradient clipping */ + float weight_decay; + float loss_scale; + } adam; + } u; + float lr; +} SGDOptParams; + +NCSGDOptState *nc_sgd_opt_init(NCContext *m, const SGDOptParams *p); +void nc_sgd_opt_end(NCSGDOptState *s); +void sgd_opt_update_var(void *opaque, NCTensor *yg, NCTensor *get_col_index); + +/* set the SGD optimizer 's' to all parameters of the model */ +void nc_sgd_opt_set_all(NCParamList *param_list, NCSGDOptState *s); + +/* set the SGD optimizer 's' to the variable 'x'. Remove it if s = NULL */ +void nc_sgd_opt_set(NCParam *x, NCSGDOptState *s); +void nc_sgd_opt_update(NCSGDOptState *s); +/* force the learning rate */ +void nc_sgd_opt_set_lr(NCSGDOptState *s, float lr); +float nc_sgd_opt_get_lr(NCSGDOptState *s); +void nc_sgd_opt_set_step(NCSGDOptState *s, int64_t step); + +/* for SGD_OPT_TEST */ +NCTensor *nc_sgd_opt_get_grad(NCParam *p); + +void nc_save_param_opt(FILE *f, const NCParam *p); +void nc_update_param(NCParamList *pl, const char *name, const NCTensor *v); + +/* misc utilities (to be removed) */ + +typedef struct { + uint32_t x, y, z, w, v, d; + /* used by Gaussian generator */ + int idx; + float y1; +} RNDState; + +void rnd_init(RNDState *s, uint32_t seed); +uint32_t rnd_unif_u32(RNDState *s); +float rnd_unif(RNDState *s); +float rnd_gaussian(RNDState *s); +void rnd_unif_vec(float *tab, size_t n, float mu, float range, + RNDState *s); +void rnd_unif_mat(float *tab, size_t stride, size_t h, size_t w, + float mu, float sigma, RNDState *s); + +float vec_sum_f32(const float *tab, size_t n); +float vec_max_f32(const float *tab, size_t n); +float vec_logsumexp_f32(const float *tab, int n); + +typedef struct { + float val; + uint32_t idx; +} NCTopKEntry; + +/* Return the k largest values among prob[0...n_symb-1]. The floating + point numbers are sorted according to their binary + representation. 'tab' must be freed with nc_free(). */ +int nc_topk(NCTopKEntry **ptab, const float *prob, size_t n_symb, int topk); +/* same as nc_topk() but compare against 'dist' and stop returning + values with their sum is larger or equal to 'topp' */ +int nc_topkp(NCTopKEntry **pout_tab, double *psum, + const float *tab, const float *dist, size_t n_symb, + int topk, float topp); + + +/* allocate the whole device memory for this task */ +#define NC_DEVICE_PARAM_FULL_MEM 0 +/* set device specific options */ +int nc_set_device_param(NCDevice *d, int param, int64_t val); +/* use it before nc_new_cuda_device() to make cublasLt optional */ +void nc_set_cublasLt_required(BOOL val); + +/* apply a forward function with custom backward function */ + +typedef NCTensor *NCForwardFunction(NCTensor **inputs, int n_inputs, + NCNode *n, void *opaque); +typedef void NCBackwardFunction(NCTensor **grad_outputs, int n_outputs, + NCTensor *grad, NCTensor **args, int n_args, + void *opaque); +NCTensor *nc_apply(NCTensor **inputs, int n_inputs, + NCForwardFunction *func, NCBackwardFunction *bw_func, + void *opaque); + +#endif /* LIBNC_H */ diff --git a/quickjs/list.h b/deps/nncp/list.h similarity index 98% rename from quickjs/list.h rename to deps/nncp/list.h index 0a1bc5a..9ceddef 100644 --- a/quickjs/list.h +++ b/deps/nncp/list.h @@ -24,10 +24,6 @@ #ifndef LIST_H #define LIST_H -#ifndef NULL -#include -#endif - struct list_head { struct list_head *prev; struct list_head *next; diff --git a/deps/nncp/nncp.c b/deps/nncp/nncp.c new file mode 100644 index 0000000..44aaa68 --- /dev/null +++ b/deps/nncp/nncp.c @@ -0,0 +1,3906 @@ +/* + * Lossless compression with Transformer + * + * Copyright (c) 2018-2021 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "arith.h" +#include "libnc.h" +#include "cp_utils.h" +#include "preprocess.h" +#include "cmdopt.h" + +/************************************************/ +/* model description */ + +typedef struct NNCPModelState NNCPModelState; +typedef struct NNCPModelParams NNCPModelParams; + +typedef struct { + const char *name; + uint8_t model_id; + size_t instance_size; + const CMDOptDesc *model_options; + void (*model_parse_options)(NNCPModelParams *np, CMDOption *co); + void (*model_write_params)(FILE *f, const NNCPModelParams *np); + int (*model_read_params)(FILE *f, NNCPModelParams *np); + void (*model_dump_params)(FILE *f, NNCPModelState *s, + const NNCPModelParams *np); + + void (*model_init)(NNCPModelState *s, const NNCPModelParams *params); + void (*model_end)(NNCPModelState *s); + NCTensor *(*model_eval)(NNCPModelState *s, int output_index, const NCTensor *input); + void (*model_eval_end)(NNCPModelState *s); + float (*model_eval_gradient)(NNCPModelState *s, const NCTensor *expected_output); + void (*model_reset)(NNCPModelState *s); + void (*model_update)(NNCPModelState *s); + void (*model_set_retrain)(NNCPModelState *s, int enabled); + void (*model_set_lr)(NNCPModelState *s, float lr); +} NNCPModelClass; + +//#define DUMP_GRAD_NORM +//#define DUMP_HASH + +#define LN_POST (1 << 0) +#define LN_PRE (1 << 1) +#define LN_FINAL (1 << 2) +#define LN_COEF (1 << 3) +#define LN_RMSNORM (1 << 4) + +#define N_LAYER_MAX 32 + +typedef enum { + FF_ACT_RELU, + FF_ACT_GELU, + FF_ACT_GEGLU, + FF_ACT_GATED_SILU, +} FFActivationEnum; + +typedef struct { + int n_layer; + int d_model; + int n_head; + int d_key; + int d_value; + int d_inner; + int d_pos; + int mem_len; + int attn_len[N_LAYER_MAX]; + uint8_t tied_embed; + uint8_t use_bias; + uint8_t use_w_r; + uint8_t tied_w_r; + uint8_t tied_b_r; + uint8_t query_bias; + uint8_t rotary_pos_embed; + uint8_t ln_flags; + float init_range; + float embed_mult; + FFActivationEnum ff_act; + SGDOptParams sgd_opt; + + float dropout_prob; /* using during retrain */ + float dropout_att_prob; /* using during retrain */ + BOOL use_sparse_grad; +} TransformerModelParams; + +typedef enum { + LSTM_TYPE_NORMAL, + LSTM_TYPE_CLAMPED, + LSTM_TYPE_TIED, + LSTM_TYPE_GRU, +} LSTMTypeEnum; + +typedef struct { + int n_layers; + int n_cells; + int n_cells2; + int n_embed_out; + int n_states; + LSTMTypeEnum lstm_type; + BOOL use_layer_norm; + BOOL full_connect; + SGDOptParams sgd_opt; + int retrain_start; /* in bytes, multiple of block_len */ + int retrain_factor; /* multiplied by 100 */ + float dropout_prob; /* using during retrain */ + float forget_bias; + BOOL use_sparse_grad; +} LSTMParams; + +struct NNCPModelParams { + BOOL use_cuda; + BOOL use_bf16; + BOOL seq_eval; + int batch_size; + int seg_len; + uint32_t seed; + int n_symbols; + + InterpParams block_len; + InterpParams lr; + + uint32_t retrain_period; /* in bytes, retrain happens between blocks */ + uint32_t retrain_len; + BOOL has_retrain_lr; + InterpParams retrain_lr; + + const NNCPModelClass *model_class; + union { + TransformerModelParams trf; + LSTMParams lstm; + } u; +}; + +typedef uint16_t DataSymbol; + +struct NNCPModelState { + const NNCPModelClass *model_class; + + NCRNDState *rnd_state; + NCContext *model; + NCDevice *device; + NCDevice *cpu_device; + + int batch_size; + int seg_len; + uint32_t seed; + int n_symbols; + + InterpParams block_len; + InterpParams lr; + + int retrain_period; + int retrain_buf_size; /* length of the retrain buffer */ + DataSymbol *retrain_buf; + int retrain_pos; /* distance from the previous retrain */ + int retrain_buf_pos; + int retrain_buf_len; + BOOL has_retrain_lr; + InterpParams retrain_lr; + + int64_t train_step; + int64_t retrain_train_step; +}; + +/************************************************/ +/* Transformer model */ + +typedef struct { + NCTensor *w_q, *w_kv; /* self attention matrixes */ + NCTensor *b_q; /* query bias */ + NCTensor *w_o; /* linear output matrix */ + NCTensor *ff1, *ff2, *ff_bias1, *ff_bias2; /* feed forward layer */ + NCTensor *w_r; + NCTensor *b_r; /* query bias for relative position */ + NCTensor *ln_g1, *ln_b1; + NCTensor *ln_g2, *ln_b2; + NCTensor *alpha; /* used with LN_COEF */ + NCTensor *mem_key; /* decoder only: storage for keys */ + NCTensor *mem_value; /* decoder only: storage for values */ + NCTensor *tmp_w_r; /* temporary use */ + NCTensor *tmp_b_r; /* temporary use */ + NCTensor *attn_mask; /* constant */ + NCNode **key_nodes; /* decoder only */ + NCNode **kq_nodes; /* decoder only */ + NCNode **value_nodes; /* decoder only */ + NCNode **va_nodes; /* decoder only */ +} TransformerLayer; + +typedef struct { + NNCPModelState common; + + NCParamList param_list; + int n_layer; + int d_model; + int n_head; + int d_key; + int d_value; + int d_inner; + int d_pos; + int mem_len; + int train_len; + int n_symbols; + uint8_t use_bias; + uint8_t use_w_r; + uint8_t tied_w_r; + uint8_t tied_b_r; + uint8_t query_bias; + uint8_t rotary_pos_embed; + uint8_t ln_flags; + float embed_mult; + TransformerLayer *layers; + NCTensor *ln_g, *ln_b; + NCTensor *embed, *embed_out, *out_bias, *rot_pos_embed; + NCTensor **mem_h; /* n_layer */ + NCTensor **train_h; /* n_layer */ + NCTensor *input; + NCTensor **outputs; + + int n_streams; /* rename */ + int n_states; /* same as train_len -> remove */ + NCSGDOptState *sgd_opt; + BOOL seq_eval; + FFActivationEnum ff_act; + NCTypeEnum param_type; /* F32 or BF16 */ + + BOOL dropout_enabled; + float dropout_prob; + float dropout_att_prob; + BOOL use_sparse_grad; +} TransformerModel; + +static void var_init(NCTensor *x, float range, NCRNDState *rnd_state) +{ + nc_tensor_set_rnd_unif(x, 0, range, rnd_state); +} + +static void layer_norm_init(TransformerModel *s, + NCTensor **pg, NCTensor **pb, + size_t n, int name_idx) +{ + *pg = nc_new_tensor_1d(s->common.device, s->param_type, n); + nc_new_param(&s->param_list, pg, "ln_g_%d", name_idx); + nc_tensor_set_f32(*pg, 1.0f); + *pb = nc_new_tensor_1d(s->common.device, s->param_type, n); + nc_new_param(&s->param_list, pb, "ln_b_%d", name_idx); +} + +static NCTensor *layer_norm(NCTensor *t0, NCTensor *g, NCTensor *b, + int flags) +{ + if (flags & LN_RMSNORM) + t0 = nc_rms_norm(t0, 1e-5); + else + t0 = nc_layer_norm(t0, 1e-5); + return nc_add(nc_mul(t0, nc_dup_tensor(g)), + nc_dup_tensor(b)); +} + +static NCTensor *dropout_mul(NCTensor *x, float prob, NCRNDState *rnd_state) +{ + NCTensor *x1; + if (prob == 0) + return x; + x1 = nc_new_tensor_from_tensor_nz(x); + nc_tensor_set_dropout(x1, prob, rnd_state); + return nc_mul(x, x1); +} + +static int nb_threads = 1; +static BOOL use_cuda; +static BOOL use_encode_only; + +static void trf_init(NNCPModelState *s1, const NNCPModelParams *np) +{ + TransformerModel *s = (TransformerModel *)s1; + const TransformerModelParams *p = &np->u.trf; + NCContext *m = s1->model; + NCDevice *d = s1->device; + int layer_idx, n; + TransformerLayer *tl; + float init_val; + + s->n_layer = p->n_layer; + s->d_model = p->d_model; + s->n_head = p->n_head; + s->d_key = p->d_key; + s->d_value = p->d_value; + s->d_inner = p->d_inner; + s->d_pos = p->d_pos; + s->mem_len = p->mem_len; + s->train_len = np->seg_len; + s->n_symbols = np->n_symbols; + s->use_bias = p->use_bias; + s->use_w_r = p->use_w_r; + s->tied_w_r = p->tied_w_r; + s->tied_b_r = p->tied_b_r; + s->query_bias = p->query_bias; + s->ln_flags = p->ln_flags; + s->rotary_pos_embed = p->rotary_pos_embed; + s->embed_mult = sqrtf(s->d_model) * p->embed_mult; + s->ff_act = p->ff_act; + + s->n_streams = np->batch_size; + s->n_states = np->seg_len; + + s->use_sparse_grad = p->use_sparse_grad; + + nc_param_list_init(m, &s->param_list); + + init_val = p->init_range / sqrtf(s->d_model); + + if (np->use_bf16) + s->param_type = NC_TYPE_BF16; + else + s->param_type = NC_TYPE_F32; + + s->layers = nc_mallocz(sizeof(s->layers[0]) * s->n_layer); + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + tl = &s->layers[layer_idx]; + + tl->attn_mask = nc_new_tensor_2d(s->common.cpu_device, NC_TYPE_I8, + s->train_len + s->mem_len, + s->train_len); + { + int i, j, pos, v; + for(i = 0; i < s->train_len; i++) { + for(j = 0; j < s->mem_len + s->train_len; j++) { + pos = (i + s->mem_len) - j; + v = !(pos >= 0 && pos < p->attn_len[layer_idx]); + nc_set1_i32_2d(tl->attn_mask, j, i, v); + } + } + } + tl->attn_mask = nc_tensor_to_device(tl->attn_mask, d); + + if (!p->rotary_pos_embed) { + if (layer_idx == 0 || !p->tied_b_r) { + tl->b_r = nc_new_tensor_2d(d, s->param_type, + s->train_len + s->mem_len, s->n_head); + nc_new_param(&s->param_list, &tl->b_r, "b_r_%d", layer_idx); + } + if (p->use_w_r && (layer_idx == 0 || !p->tied_w_r)) { + tl->w_r = nc_new_tensor_3d(d, s->param_type, + s->d_key, s->d_pos, s->n_head); + nc_new_param(&s->param_list, &tl->w_r, "w_r_%d", layer_idx); + var_init(tl->w_r, init_val, s->common.rnd_state); + } + } + + tl->w_q = nc_new_tensor_2d(d, s->param_type, s->n_head * s->d_key, + s->d_model); + nc_new_param(&s->param_list, &tl->w_q, "w_q_%d", layer_idx); + var_init(tl->w_q, init_val, s->common.rnd_state); + + if (s->query_bias) { + tl->b_q = nc_new_tensor_1d(d, s->param_type, s->n_head * s->d_key); + nc_new_param(&s->param_list, &tl->b_q, "b_q_%d", layer_idx); + } + + tl->w_kv = nc_new_tensor_2d(d, s->param_type, s->n_head * s->d_key + + s->n_head * s->d_value, + s->d_model); + nc_new_param(&s->param_list, &tl->w_kv, "w_kv_%d", layer_idx); + var_init(tl->w_kv, init_val, s->common.rnd_state); + + if (s->d_value != s->d_model) { + tl->w_o = nc_new_tensor_2d(d, s->param_type, s->d_model, + s->n_head * s->d_value); + nc_new_param(&s->param_list, &tl->w_o, "w_o_%d", layer_idx); + var_init(tl->w_o, init_val, s->common.rnd_state); + } + + if (s->ff_act == FF_ACT_GEGLU || s->ff_act == FF_ACT_GATED_SILU) + n = s->d_inner * 2; + else + n = s->d_inner; + tl->ff1 = nc_new_tensor_2d(d, s->param_type, n, + s->d_model); + nc_new_param(&s->param_list, &tl->ff1, "ff1_%d", layer_idx); + var_init(tl->ff1, init_val, s->common.rnd_state); + + if (s->use_bias) { + tl->ff_bias1 = nc_new_tensor_1d(d, s->param_type, n); + nc_new_param(&s->param_list, &tl->ff_bias1, "ff_bias1_%d", layer_idx); + } + + tl->ff2 = nc_new_tensor_2d(d, s->param_type, s->d_model, + s->d_inner); + nc_new_param(&s->param_list, &tl->ff2, "ff2_%d", layer_idx); + var_init(tl->ff2, init_val * + sqrtf((float)s->d_model / (float)s->d_inner), + s->common.rnd_state); + + if (s->use_bias) { + tl->ff_bias2 = nc_new_tensor_1d(d, s->param_type, s->d_model); + nc_new_param(&s->param_list, &tl->ff_bias2, "ff_bias2_%d", layer_idx); + } + + if (p->ln_flags & (LN_POST | LN_PRE)) { + layer_norm_init(s, &tl->ln_g1, &tl->ln_b1, s->d_model, layer_idx * 2); + layer_norm_init(s, &tl->ln_g2, &tl->ln_b2, s->d_model, layer_idx * 2 + 1); + } + if (p->ln_flags & LN_COEF) { + tl->alpha = nc_new_scalar(d, NC_TYPE_F32); + nc_new_param(&s->param_list, &tl->alpha, "alpha_%d", layer_idx); + nc_tensor_set_f32(tl->alpha, 0); + } + if (np->seq_eval) { + tl->mem_key = + nc_new_tensor_4d(d, s->param_type, s->d_key, + s->mem_len + s->train_len, s->n_head, + s->n_streams); + tl->mem_value = + nc_new_tensor_4d(d, s->param_type, s->d_value, + s->mem_len + s->train_len, s->n_head, + s->n_streams); + tl->key_nodes = nc_mallocz(sizeof(tl->key_nodes[0]) * (s->train_len + 1)); + tl->kq_nodes = nc_mallocz(sizeof(tl->kq_nodes[0]) * s->train_len); + tl->value_nodes = nc_mallocz(sizeof(tl->value_nodes[0]) * (s->train_len + 1)); + tl->va_nodes = nc_mallocz(sizeof(tl->va_nodes[0]) * s->train_len); + } + } + + if (s->ln_flags & LN_FINAL) { + layer_norm_init(s, &s->ln_g, &s->ln_b, s->d_model, s->n_layer * 2); + } + + if (s->rotary_pos_embed) { + int n, i, j; + float th, *ptr; + assert((s->d_key % 2) == 0); + s->rot_pos_embed = nc_new_tensor_2d(s->common.cpu_device, NC_TYPE_F32, s->d_key, + s->train_len + s->mem_len); + n = s->d_key / 2; + ptr = nc_tensor_get_ptr(s->rot_pos_embed, NULL); + for(i = 0; i < s->d_key / 2; i++) { + if (i >= n) + th = 0; + else + th = 1.0f / pow(100000, (float)i / (float)n); + // printf("%d: th=%f\n", i, th); + for(j = 0; j < s->train_len + s->mem_len; j++) { + ptr[(2 * i) + j * s->d_key] = cos(th * j); + ptr[(2 * i + 1) + j * s->d_key] = sin(th * j); + } + } + s->rot_pos_embed = nc_convert(nc_tensor_to_device(s->rot_pos_embed, d), s->param_type); + } + + s->embed = nc_new_tensor_2d(d, NC_TYPE_F32, s->d_model, + s->n_symbols); + nc_new_param(&s->param_list, &s->embed, "embed"); + var_init(s->embed, init_val, s->common.rnd_state); + + n = s->d_model; + if (p->tied_embed) { + s->embed_out = NULL; + } else { + s->embed_out = nc_new_tensor_2d(d, s->param_type, s->n_symbols, n); + nc_new_param(&s->param_list, &s->embed_out, "embed_out"); + var_init(s->embed_out, init_val, s->common.rnd_state); + } + + if (s->use_bias) { + s->out_bias = nc_new_tensor_1d(d, s->param_type, s->n_symbols); + nc_new_param(&s->param_list, &s->out_bias, "out_bias"); + } + + s->mem_h = nc_mallocz(sizeof(s->mem_h[0]) * s->n_layer); + s->train_h = nc_mallocz(sizeof(s->train_h[0]) * s->n_layer); + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + s->mem_h[layer_idx] = + nc_new_tensor_3d(d, s->param_type, s->d_model, s->n_streams, + s->mem_len); + s->train_h[layer_idx] = + nc_new_tensor_3d(d, s->param_type, s->d_model, s->n_streams, + s->train_len); + } + + s->outputs = nc_mallocz(sizeof(s->outputs[0]) * s->train_len); + + s->sgd_opt = nc_sgd_opt_init(m, &p->sgd_opt); + + /* apply the SGD optimizer to all the parameters */ + nc_sgd_opt_set_all(&s->param_list, s->sgd_opt); + + s->dropout_prob = p->dropout_prob; + s->dropout_att_prob = p->dropout_att_prob; +} + +static void trf_end(NNCPModelState *s1) +{ + TransformerModel *s = (TransformerModel *)s1; + int layer_idx; + TransformerLayer *tl; + + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + tl = &s->layers[layer_idx]; + nc_free_tensor(s->mem_h[layer_idx]); + nc_free_tensor(s->train_h[layer_idx]); + nc_free_tensor(tl->mem_key); + nc_free_tensor(tl->mem_value); + nc_free_tensor(tl->attn_mask); + nc_free(tl->key_nodes); + nc_free(tl->kq_nodes); + nc_free(tl->value_nodes); + nc_free(tl->va_nodes); + } + nc_free_tensor(s->rot_pos_embed); + nc_free(s->mem_h); + nc_free(s->train_h); + nc_free_tensor(s->input); + nc_free(s->outputs); + + nc_sgd_opt_set_all(&s->param_list, NULL); + nc_sgd_opt_end(s->sgd_opt); + nc_param_list_end(&s->param_list); + nc_free(s->layers); +} + +/* [seg_len, batch_size, d_model] -> + [batch_size, n_head, seg_len, d_model/n_head] */ +static NCTensor *split_head(NCTensor *x, int n_head) +{ + size_t dims[NC_N_DIMS_MAX]; + int n_dims; + + n_dims = nc_tensor_get_dims(x, dims); + assert(n_dims == 3); + assert((dims[0] % n_head) == 0); + x = nc_reshape_4d(x, dims[0] / n_head, n_head, dims[1], dims[2]); + /* [seg_len, batch_size, n_head, d_model/n_head] */ + return nc_permute_4d(x, 0, 3, 1, 2); +} + +/* [batch_size, n_head, seg_len, d_value] + -> [seg_len * batch_size, d_value * n_head] */ +static NCTensor *concat_head(NCTensor *x) +{ + size_t dims[NC_N_DIMS_MAX]; + int n_dims; + + x = nc_permute_4d(x, 0, 2, 3, 1); + n_dims = nc_tensor_get_dims(x, dims); + assert(n_dims == 4); + /* [seg_len, batch_size, n_head, d_value] */ + return nc_reshape_2d(x, dims[0] * dims[1], dims[2] * dims[3]); +} + +static NCTensor *trf_eval(NNCPModelState *s1, int output_index, const NCTensor *input) +{ + TransformerModel *s = (TransformerModel *)s1; + NCDevice *d = s->common.device; + int layer_idx, seg_len; + NCTensor *layer_input, **tab_tmp, *t0, *t1, *output; + +#if defined(DUMP_HASH) && 0 + { + NCParam *p; + struct list_head *el; + static int step; + printf("step %d:\n", step); + list_for_each(el, &s->param_list.param_list) { + p = list_entry(el, NCParam, link); + nc_dump_tensor_hash(p->name, *p->pval); +#if 0 + if (p->low_part) + nc_dump_tensor_hash(" low_part", p->low_part); +#endif + } + step++; + } +#endif + + prof_start(PROF_EVAL); + + tab_tmp = nc_mallocz(sizeof(tab_tmp[0]) * + max_int(max_int(2, s->train_len), + max_int(s->n_head, s->n_layer))); + + if (output_index < 0) { + t0 = nc_dup_tensor(input); + s->seq_eval = FALSE; + seg_len = s->train_len; + } else { + t0 = nc_slice_alias(input, 1, output_index, output_index + 1); + s->seq_eval = TRUE; + seg_len = 1; + } + t0 = nc_tensor_to_device(t0, d); + + t0 = nc_reshape_1d(t0, s->n_streams * seg_len); + + layer_input = nc_get_col(nc_dup_tensor(s->embed), t0); + + layer_input = nc_convert(layer_input, s->param_type); + + layer_input = nc_mul(layer_input, nc_convert(nc_new_f32(d, s->embed_mult), + s->param_type)); + if (s->dropout_enabled) { + layer_input = dropout_mul(layer_input, s->dropout_prob, s->common.rnd_state); + } + + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + TransformerLayer *tl = &s->layers[layer_idx]; + NCTensor *query, *key, *value, *layer_input1; + NCTensor *ff_input, *rd; + + layer_input1 = nc_dup_tensor(layer_input); + if (s->ln_flags & LN_PRE) { + layer_input1 = layer_norm(layer_input1, tl->ln_g1, tl->ln_b1, + s->ln_flags); + } + + /* save the matrix input */ + if (output_index < 0) { + t0 = nc_dup_tensor(s->train_h[layer_idx]); + } else { + t0 = nc_slice_alias(s->train_h[layer_idx], 2, + output_index, output_index + 1); + } + t1 = nc_reshape_3d(nc_dup_tensor(layer_input1), s->d_model, + s->n_streams, seg_len); + nc_tensor_copy(t0, t1); + nc_free_tensor(t1); + nc_free_tensor(t0); + + query = nc_matmul(nc_dup_tensor(tl->w_q), nc_dup_tensor(layer_input1)); + if (s->query_bias) + query = nc_add(query, nc_dup_tensor(tl->b_q)); + t0 = nc_matmul(nc_dup_tensor(tl->w_kv), layer_input1); + key = nc_slice(nc_dup_tensor(t0), 0, 0, s->n_head * s->d_key); + value = nc_slice(t0, 0, s->n_head * s->d_key, s->n_head * s->d_key + s->n_head * s->d_value); + + query = nc_reshape_3d(query, s->d_key * s->n_head, s->n_streams, + seg_len); + key = nc_reshape_3d(key, s->d_key * s->n_head, s->n_streams, + seg_len); + value = nc_reshape_3d(value, s->d_value * s->n_head, s->n_streams, + seg_len); + + if (output_index < 0 || output_index == 0) { + NCTensor *key0, *value0; + /* also use the longer memory for key and value */ + t0 = nc_reshape_2d(nc_dup_tensor(s->mem_h[layer_idx]), + s->d_model, s->mem_len * s->n_streams); + t0 = nc_matmul(nc_dup_tensor(tl->w_kv), t0); + + key0 = nc_slice(nc_dup_tensor(t0), 0, 0, s->n_head * s->d_key); + value0 = nc_slice(t0, 0, s->n_head * s->d_key, s->n_head * s->d_key + s->n_head * s->d_value); + + key0 = nc_reshape_3d(key0, s->d_key * s->n_head, s->n_streams, + s->mem_len); + value0 = nc_reshape_3d(value0, s->d_value * s->n_head, s->n_streams, + s->mem_len); + + if (output_index < 0) { + tab_tmp[0] = key0; + tab_tmp[1] = key; + key = nc_concat(tab_tmp, 2, 2); + + tab_tmp[0] = value0; + tab_tmp[1] = value; + value = nc_concat(tab_tmp, 2, 2); + } else { + t0 = nc_slice_alias(tl->mem_key, 1, 0, s->mem_len); + key0 = split_head(key0, s->n_head); + tl->key_nodes[0] = nc_dup_node(nc_get_node(key0)); + nc_tensor_copy(t0, key0); + nc_free_tensor(key0); + nc_free_tensor(t0); + + t0 = nc_slice_alias(tl->mem_value, 1, 0, s->mem_len); + value0 = split_head(value0, s->n_head); + tl->value_nodes[0] = nc_dup_node(nc_get_node(value0)); + nc_tensor_copy(t0, value0); + nc_free_tensor(value0); + nc_free_tensor(t0); + } + } + + if (s->dropout_enabled) { + query = dropout_mul(query, s->dropout_prob, s->common.rnd_state); + /* no need to apply w_k on key */ + value = dropout_mul(value, s->dropout_prob, s->common.rnd_state); + } + /* split query, key and value for each head: + [seg_len, batch_size, d_model] -> + [batch_size, n_head, seg_len, d_key] */ + + key = split_head(key, s->n_head); + + query = split_head(query, s->n_head); + + value = split_head(value, s->n_head); + + if (output_index <= 0 && !s->rotary_pos_embed) { + /* relative distance term */ + if (s->use_w_r) { + if (layer_idx == 0 || !s->tied_w_r) { + NCTensor *w_r; + /* XXX: not efficient */ + w_r = nc_dup_tensor(tl->w_r); + if (s->n_streams > 1) { + w_r = nc_repeat_1d(w_r, s->n_streams); + } else { + w_r = nc_reshape_4d(w_r, s->d_key, s->d_pos, s->n_head, + s->n_streams); + } + tl->tmp_w_r = w_r; + } else { + tl->tmp_w_r = nc_dup_tensor(s->layers[0].tmp_w_r); + } + } + + /* relative distance bias */ + if (layer_idx == 0 || !s->tied_b_r) { + NCTensor *b_r; + + b_r = nc_mul(nc_dup_tensor(tl->b_r), + nc_convert(nc_new_f32(d, sqrtf(s->d_key * s->d_model)), s->param_type)); + b_r = nc_repeat_2d(b_r, s->train_len, s->n_streams); + /* [batch_size, train_len, n_head, mem_len+train_len ] -> + [batch_size, n_head, train_len, mem_len+train_len ] + */ + tl->tmp_b_r = nc_permute_4d(b_r, 0, 2, 1, 3); + } else { + tl->tmp_b_r = nc_dup_tensor(s->layers[0].tmp_b_r); + } + } + + if (output_index < 0) { + if (s->rotary_pos_embed) { + NCTensor *t1; + /* XXX: optimize */ + t1 = nc_slice_alias(s->rot_pos_embed, 1, s->mem_len, s->mem_len + s->train_len); + query = nc_cmul(query, nc_repeat_2d(t1, s->n_head, s->n_streams), FALSE, FALSE); + key = nc_cmul(key, nc_repeat_2d(nc_dup_tensor(s->rot_pos_embed), s->n_head, s->n_streams), FALSE, FALSE); + } + /* cross product term */ + t0 = nc_matmul_add(key, nc_dup_tensor(query), NULL, TRUE, FALSE, 1.0); + if (!s->rotary_pos_embed) { + if (s->use_w_r) { + rd = nc_matmul_add(nc_dup_tensor(tl->tmp_w_r), + query, NULL, TRUE, FALSE, 1.0); + rd = nc_pad(rd, s->mem_len + s->train_len - s->d_pos, + NC_PAD_DUP, 0, NC_PAD_ZERO); + rd = nc_add(rd, nc_dup_tensor(tl->tmp_b_r)); + } else { + nc_free_tensor(query); + rd = nc_dup_tensor(tl->tmp_b_r); + } + rd = nc_rel_shift(rd, -(s->train_len - 1), 1); + t0 = nc_add(rd, t0); + } else { + nc_free_tensor(query); + } + t0 = nc_mul(t0, nc_convert(nc_new_f32(d, 1.0f / sqrtf(s->d_key)), + s->param_type)); + + /* set the future cross products to -infinity so that they + don't change the softmax result */ + t0 = nc_masked_fill(t0, nc_dup_tensor(tl->attn_mask), -INFINITY, 0); + + t0 = nc_soft_max(t0); + if (s->dropout_enabled) { + t0 = dropout_mul(t0, s->dropout_att_prob, s->common.rnd_state); + } + t0 = nc_matmul(value, t0); + } else { + int start, end; + NCNode *node; + + /* decoder case: get all the previous keys and value_nodes */ + start = s->mem_len + output_index; + end = start + 1; + + tl->key_nodes[output_index + 1] = nc_dup_node(nc_get_node(key)); + t0 = nc_slice_alias(tl->mem_key, 1, start, end); + nc_tensor_copy(t0, key); + nc_free_tensor(key); + nc_free_tensor(t0); + key = nc_dup_tensor(tl->mem_key); + + tl->value_nodes[output_index + 1] = nc_dup_node(nc_get_node(value)); + t0 = nc_slice_alias(tl->mem_value, 1, start, end); + nc_tensor_copy(t0, value); + nc_free_tensor(value); + nc_free_tensor(t0); + value = nc_dup_tensor(tl->mem_value); + + /* cross product term */ + t0 = nc_matmul_add(key, nc_dup_tensor(query), NULL, TRUE, FALSE, 1.0); + node = nc_get_node(t0); + /* force the storage of the argument */ + nc_node_set_arg(node, 1, query); + tl->kq_nodes[output_index] = node; + + /* relative distance term */ + /* XXX: rotary embedding are not supported yet with seq_eval */ + if (s->use_w_r) { + rd = nc_matmul_add(nc_dup_tensor(tl->tmp_w_r), query, NULL, + TRUE, FALSE, 1.0); + rd = nc_pad(rd, s->mem_len + s->train_len - s->d_pos, + NC_PAD_DUP, 0, NC_PAD_ZERO); + t1 = nc_slice(nc_dup_tensor(tl->tmp_b_r), + 1, output_index, output_index + 1); + rd = nc_add(rd, t1); + } else { + nc_free_tensor(query); + rd = nc_slice(nc_dup_tensor(tl->tmp_b_r), + 1, output_index, output_index + 1); + } + rd = nc_rel_shift(rd, -(s->train_len - 1 - output_index), 1); + t0 = nc_add(rd, t0); + t0 = nc_mul(t0, nc_convert(nc_new_f32(d, 1.0f / sqrtf(s->d_key)), + s->param_type)); + + /* set the future cross products to -infinity so that they + don't change the softmax result */ + t1 = nc_slice_alias(tl->attn_mask, + 1, output_index, output_index + 1); + t0 = nc_masked_fill(t0, t1, -INFINITY, 0); + + t1 = nc_soft_max(t0); + t0 = nc_matmul(value, nc_dup_tensor(t1)); + node = nc_get_node(t0); + /* force the storage of the argument */ + nc_node_set_arg(node, 1, t1); + nc_free_tensor(t1); + tl->va_nodes[output_index] = node; + } + + if (tl->w_o) { + /* merge all the heads: + [batch_size, n_head, seg_len, d_value] + -> [seg_len * batch_size, d_value*n_head] */ + t0 = concat_head(t0); + + /* linear layer */ + t0 = nc_matmul(nc_dup_tensor(tl->w_o), t0); + if (s->dropout_enabled) + t0 = dropout_mul(t0, s->dropout_prob, s->common.rnd_state); + } else { + int axis[4]; + /* just sum the output of the attention heads */ + /* [batch_size, n_head, seg_len, d_value] */ + axis[0] = 0; + axis[1] = 3; + axis[2] = 1; + axis[3] = 2; + t0 = nc_permute(t0, 4, axis); + /* [n_head, seg_len, batch_size, d_value] */ + t0 = nc_reduce_sum(NULL, t0, 3); + t0 = nc_mul(t0, nc_new_f32(d, 1.0 / sqrtf(s->n_head))); + /* [seg_len, batch_size, d_value] */ + t0 = nc_reshape_2d(t0, s->d_value, s->train_len * s->n_streams); + /* [seg_len * batch_size, d_value] */ + } + + if (s->ln_flags & LN_COEF) { + t0 = nc_mul(t0, nc_dup_tensor(tl->alpha)); + } + + t0 = nc_add(t0, layer_input); +#if 0 + { + char name[10]; + int i; + NCTensor *t1; + if (output_index < 0) { + for(i = 0; i < s->train_len; i++) { + t1 = nc_slice_alias(t0, 1, i, i + 1); + snprintf(name, sizeof(name), "t%2d", i); + nc_dump_tensor_hash(name, t1); + nc_free_tensor(t1); + } + } else { + snprintf(name, sizeof(name), "t%2d", output_index); + nc_dump_tensor_hash(name, t0); + } + } +#endif +#ifdef DUMP_HASH + nc_dump_tensor_hash("attn_out_bl", t0); +#endif + if (s->ln_flags & LN_POST) { + t0 = layer_norm(t0, tl->ln_g1, tl->ln_b1, s->ln_flags); + } +#ifdef DUMP_HASH + nc_dump_tensor_hash("attn_out", t0); +#endif + + ff_input = nc_dup_tensor(t0); + if (s->ln_flags & LN_PRE) { + t0 = layer_norm(t0, tl->ln_g2, tl->ln_b2, s->ln_flags); + } + + t0 = nc_matmul(nc_dup_tensor(tl->ff1), t0); + if (tl->ff_bias1) + t0 = nc_add(t0, nc_dup_tensor(tl->ff_bias1)); + if (s->dropout_enabled) + t0 = dropout_mul(t0, s->dropout_prob, s->common.rnd_state); +#ifdef DUMP_HASH + nc_dump_tensor_hash("ff1_out", t0); +#endif + switch(s->ff_act) { + case FF_ACT_RELU: + t0 = nc_relu(t0); + break; + case FF_ACT_GELU: + t0 = nc_gelu(t0); + break; + case FF_ACT_GEGLU: + { + NCTensor *tab2[2]; + nc_split(tab2, t0, 2, NULL, 0); +#if 1 + /* must keep for backward pass opt */ + t0 = nc_mul(nc_gelu(tab2[0]), tab2[1]); +#else + t0 = nc_geglu(tab2[1], tab2[0]); +#endif + } + break; + case FF_ACT_GATED_SILU: + { + NCTensor *tab2[2]; + nc_split(tab2, t0, 2, NULL, 0); + t0 = nc_gated_swish(tab2[1], tab2[0], 1.0); + } + break; + default: + abort(); + } +#ifdef DUMP_HASH + nc_dump_tensor_hash("ff2_in", t0); +#endif + t0 = nc_matmul(nc_dup_tensor(tl->ff2), t0); + if (tl->ff_bias2) + t0 = nc_add(t0, nc_dup_tensor(tl->ff_bias2)); + if (s->dropout_enabled) + t0 = dropout_mul(t0, s->dropout_prob, s->common.rnd_state); + if (s->ln_flags & LN_COEF) { + t0 = nc_mul(t0, nc_dup_tensor(tl->alpha)); + } + + t0 = nc_add(t0, ff_input); + +#ifdef DUMP_HASH + nc_dump_tensor_hash("ff_out_bl", t0); +#endif + if (s->ln_flags & LN_POST) { + t0 = layer_norm(t0, tl->ln_g2, tl->ln_b2, s->ln_flags); + } + layer_input = t0; +#ifdef DUMP_HASH + nc_dump_tensor_hash("ff_out", t0); +#endif + } + + if (s->ln_flags & LN_FINAL) { + layer_input = layer_norm(layer_input, s->ln_g, s->ln_b, s->ln_flags); + } + + if (s->dropout_enabled) { + layer_input = dropout_mul(layer_input, s->dropout_prob, s->common.rnd_state); + } + + t0 = layer_input; + t0 = nc_matmul(nc_dup_tensor(s->embed_out), t0); + if (s->out_bias) + t0 = nc_add(t0, nc_dup_tensor(s->out_bias)); + t0 = nc_convert(t0, NC_TYPE_F32); + + t0 = nc_reshape_3d(t0, s->n_symbols, s->n_streams, seg_len); + output = nc_soft_max(t0); + s->outputs[max_int(output_index, 0)] = nc_dup_tensor(output); +#ifdef DUMP_HASH + nc_dump_tensor_hash("output", s->outputs[max_int(output_index, 0)]); +#endif + + /* XXX: could free in trf_eval_gradient() */ + if (output_index < 0 || output_index == (s->train_len - 1)) { + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + TransformerLayer *tl = &s->layers[layer_idx]; + nc_free_tensor(tl->tmp_w_r); + tl->tmp_w_r = NULL; + nc_free_tensor(tl->tmp_b_r); + tl->tmp_b_r = NULL; + } + } + + nc_free(tab_tmp); + + prof_end(PROF_EVAL); + return output; +} + +/* called to free resources of trf_eval() if no gradient is computed */ +static void trf_eval_end(NNCPModelState *s1) +{ + TransformerModel *s = (TransformerModel *)s1; + TransformerLayer *tl; + int layer_idx, i; + + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + tl = &s->layers[layer_idx]; + + nc_free_tensor(tl->tmp_w_r); + tl->tmp_w_r = NULL; + nc_free_tensor(tl->tmp_b_r); + tl->tmp_b_r = NULL; + if (s->seq_eval) { + for(i = 0; i < s->train_len + 1; i++) { + nc_free_node(tl->key_nodes[i]); + tl->key_nodes[i] = NULL; + } + for(i = 0; i < s->train_len + 1; i++) { + nc_free_node(tl->value_nodes[i]); + tl->value_nodes[i] = NULL; + } + } + } + for(i = 0; i < s->train_len; i++) { + nc_free_tensor(s->outputs[i]); + s->outputs[i] = NULL; + } +} + +static __unused void dump_param_hash(TransformerModel *s) +{ + struct list_head *el; + static int count; + printf("Step %d:\n", count++); + list_for_each(el, &s->param_list.param_list) { + NCParam *p = list_entry(el, NCParam, link); + printf(" %12s %08x\n", p->name, nc_tensor_get_hash(*p->pval)); + } +} + +#ifdef DUMP_GRAD_NORM +static double grad_sum; +static int grad_count; +#endif + +static void backward_cb(void *opaque, NCTensor *yg, NCTensor *get_col_index) +{ +#ifdef DUMP_GRAD_NORM + { + NCTensor *t0; + int n_dims, i, n; + const size_t *dims; + dims = nc_tensor_get_dims(yg, &n_dims); + n = 1; + for(i = 0; i < n_dims; i++) + n *= dims[i]; + grad_count += n; + t0 = nc_sum(nc_mul(nc_dup_tensor(yg), nc_dup_tensor(yg))); + grad_sum += nc_get_scalar_f32(t0); + nc_free_tensor(t0); + } +#endif + sgd_opt_update_var(opaque, yg, get_col_index); +} + +/* evaluate the gradient and return the loss (not averaged) */ +static float trf_eval_gradient(NNCPModelState *s1, const NCTensor *expected_output1) +{ + TransformerModel *s = (TransformerModel *)s1; + NCContext *m = s->common.model; + int i, layer_idx; + TransformerLayer *tl; + NCTensor *loss, *expected_output, *output; + float ret_loss; + + prof_start(PROF_GRAD); + + expected_output = nc_tensor_to_device(nc_dup_tensor(expected_output1), s->common.device); + if (s->seq_eval) { + NCNode *n, *n1, *tab_n[2], **tab_nodes; + size_t *tab_size, tab_size2[2]; + int node_count; + + tab_nodes = nc_malloc(sizeof(tab_nodes[0]) * (s->n_layer * 2 + 1)); + node_count = 0; + for(layer_idx = 0; layer_idx < s->n_layer; layer_idx++) { + tl = &s->layers[layer_idx]; + + tab_size = nc_malloc(sizeof(tab_size[0]) * s->train_len); + for(i = 0; i < s->train_len; i++) + tab_size[i] = 1; + tab_size2[0] = s->mem_len; + tab_size2[1] = s->train_len; + + /* factorize the 'key*t(query)' matrix multiplication */ + n = nc_concat_node(m, tl->key_nodes + 1, s->train_len, 1, tab_size); + tab_n[0] = tl->key_nodes[0]; + tab_n[1] = n; + n1 = nc_concat_node(m, tab_n, 2, 1, tab_size2); + for(i = 0; i < s->train_len + 1; i++) { + nc_free_node(tl->key_nodes[i]); + tl->key_nodes[i] = NULL; + } + for(i = 0; i < s->train_len; i++) + nc_node_set_parent(tl->kq_nodes[i], 0, n1); + nc_free_node(n); + nc_free_node(n1); + tab_nodes[node_count++] = n; + + /* factorize the 'value*att' matrix multiplication */ + n = nc_concat_node(m, tl->value_nodes + 1, s->train_len, 1, tab_size); + tab_n[0] = tl->value_nodes[0]; + tab_n[1] = n; + n1 = nc_concat_node(m, tab_n, 2, 1, tab_size2); + for(i = 0; i < s->train_len + 1; i++) { + nc_free_node(tl->value_nodes[i]); + tl->value_nodes[i] = NULL; + } + for(i = 0; i < s->train_len; i++) + nc_node_set_parent(tl->va_nodes[i], 0, n1); + nc_free_node(n); + nc_free_node(n1); + tab_nodes[node_count++] = n; + + nc_free(tab_size); + } + + output = nc_concat(s->outputs, s->train_len, 2); + for(i = 0; i < s->train_len; i++) + s->outputs[i] = NULL; /* fail safe */ + tab_nodes[node_count++] = nc_get_node(output); + nc_concat_optimization(m, tab_nodes, node_count); + nc_free(tab_nodes); + } else { + output = s->outputs[0]; + s->outputs[0] = NULL; /* fail safe */ + } + loss = nc_indexed_log(output, nc_dup_tensor(expected_output)); + nc_free_tensor(expected_output); + + loss = nc_sum(loss); + ret_loss = nc_get_scalar_f32(loss); + loss = nc_mul(loss, nc_new_f32(nc_get_tensor_device(loss), -1.0f / (s->train_len * s->n_streams))); + + // nc_dump_graph(loss); exit(1); + +#ifdef DUMP_GRAD_NORM + grad_sum = 0; + grad_count = 0; +#endif + nc_backward(loss, nc_new_f32(s->common.device, 1.0), backward_cb, + s->use_sparse_grad ? NC_BW_SPARSE_GRAD : 0); +#ifdef DUMP_GRAD_NORM + printf("grad: norm=%0.2e RMS=%0.2e\n", + sqrt(grad_sum), sqrt(grad_sum / grad_count)); +#endif + nc_free_tensor(loss); + + prof_end(PROF_GRAD); + return ret_loss; +} + +static void trf_reset(NNCPModelState *s1) +{ + TransformerModel *s = (TransformerModel *)s1; + int i; + + for(i = 0; i < s->n_layer; i++) { + nc_tensor_set_zero(s->mem_h[i]); + } +} + +static void mem_update(TransformerModel *s) +{ + NCTensor **mem = s->mem_h, **train = s->train_h; + size_t i; + + for(i = 0; i < s->n_layer; i++) { + if (s->mem_len > s->train_len) { + nc_tensor_copy_slice(mem[i], mem[i], 2, + 0, s->mem_len - s->train_len, s->train_len); + nc_tensor_copy_slice(mem[i], train[i], 2, + s->mem_len - s->train_len, s->mem_len, 0); + } else { + nc_tensor_copy_slice(mem[i], train[i], 2, + 0, s->mem_len, s->train_len - s->mem_len); + } + } +} + +/* update with coefficients */ +static void trf_update(NNCPModelState *s1) +{ + TransformerModel *s = (TransformerModel *)s1; + prof_start(PROF_UPDATE); + + nc_sgd_opt_update(s->sgd_opt); + + /* shift the memory */ + mem_update(s); + + prof_end(PROF_UPDATE); +} + +static void trf_set_retrain(NNCPModelState *s1, BOOL enabled) +{ + TransformerModel *s = (TransformerModel *)s1; + s->dropout_enabled = (enabled && s->dropout_prob != 0); +} + +static void trf_set_lr(NNCPModelState *s1, float lr) +{ + TransformerModel *s = (TransformerModel *)s1; + nc_sgd_opt_set_lr(s->sgd_opt, lr); +} + +static void trf_dump_params(FILE *f, NNCPModelState *s1, + const NNCPModelParams *np) +{ + const TransformerModelParams *p = &np->u.trf; + TransformerModel *s = (TransformerModel *)s1; + + char buf1[32], buf3[32]; + uint64_t n_params, n_params_nie; + int i; + + fprintf(f, "n_layer=%d d_model=%d n_head=%d d_key=%d d_value=%d mem_len=%d d_pos=%d d_inner=%d tied_embed=%d init_range=%g use_bias=%d use_w_r=%d tied_w_r=%d tied_b_r=%d query_bias=%d rot_pos=%d ln_flags=%d ff_act=%d", + p->n_layer, + p->d_model, + p->n_head, + p->d_key, + p->d_value, + p->mem_len, + p->d_pos, + p->d_inner, + p->tied_embed, + p->init_range, + p->use_bias, p->use_w_r, p->tied_w_r, p->tied_b_r, p->query_bias, + p->rotary_pos_embed, + p->ln_flags, p->ff_act); + + fprintf(f, " attn_len="); + for(i = 0; i < p->n_layer; i++) { + if (i != 0) + fprintf(f, ","); + fprintf(f, "%d", p->attn_len[i]); + } + + fprintf(f, " dropout=%g dropout_att=%g", + p->dropout_prob, p->dropout_att_prob); + + dump_sgd_opt_params(f, &p->sgd_opt); + + n_params = nc_get_param_count(&s->param_list); + /* without input embeddings */ + n_params_nie = n_params; + if (!p->tied_embed) + n_params_nie -= p->d_model * s->n_symbols; + + fprintf(f, " n_params=%s n_params_nie=%s\n", + get_si_prefix(buf1, sizeof(buf1), n_params), + get_si_prefix(buf3, sizeof(buf3), n_params_nie)); +} + +static void fput_interp_params(FILE *f, const InterpParams *p) +{ + int i; + fput_u8(f, p->n_steps); + for(i = 0; i <= p->n_steps; i++) + fput_f32(f, p->val[i]); + for(i = 0; i < p->n_steps; i++) + fput_be32(f, p->pos[i]); + fput_f32(f, p->decay_power); +} + +static int fget_interp_params(FILE *f, InterpParams *p) +{ + uint8_t v8; + uint32_t v32; + int i; + + if (fget_u8(f, &v8)) + return -1; + if (v8 > INTERP_MAX_STEPS) + return -1; + p->n_steps = v8; + for(i = 0; i <= p->n_steps; i++) { + if (fget_f32(f, &p->val[i])) + return -1; + } + for(i = 0; i < p->n_steps; i++) { + if (fget_be32(f, &v32)) + return -1; + p->pos[i] = v32; + } + if (fget_f32(f, &p->decay_power)) + return -1; + return 0; +} + +static void trf_write_params(FILE *f, const NNCPModelParams *np) +{ + const TransformerModelParams *p = &np->u.trf; + int i; + + fput_u8(f, p->n_layer); + fput_u8(f, p->n_head); + fput_be16(f, p->d_key); + fput_be16(f, p->d_value); + fput_be16(f, p->d_inner); + fput_be16(f, p->d_pos); + fput_be16(f, p->mem_len); + for(i = 0; i < p->n_layer; i++) { + fput_be16(f, p->attn_len[i]); + } + fput_u8(f, p->tied_embed); + fput_u8(f, p->use_bias); + fput_u8(f, p->use_w_r); + fput_u8(f, p->tied_w_r); + fput_u8(f, p->tied_b_r); + fput_u8(f, p->query_bias); + fput_u8(f, p->rotary_pos_embed); + fput_u8(f, p->ln_flags); + fput_f32(f, p->init_range); + fput_f32(f, p->embed_mult); + fput_u8(f, p->ff_act); + fput_sgd_opt(f, &p->sgd_opt); + if (np->retrain_period != 0) { + fput_f32(f, p->dropout_prob); + fput_f32(f, p->dropout_att_prob); + } + fput_u8(f, p->use_sparse_grad); +} + +static int trf_read_params(FILE *f, NNCPModelParams *np) +{ + TransformerModelParams *p = &np->u.trf; + uint16_t v16; + uint8_t v8; + int i; + + if (fget_u8(f, &v8)) + return -1; + p->n_layer = v8; + if (fget_u8(f, &v8)) + return -1; + p->n_head = v8; + if (fget_be16(f, &v16)) + return -1; + p->d_key = v16; + p->d_model = p->d_key * p->n_head; + if (fget_be16(f, &v16)) + return -1; + p->d_value = v16; + if (fget_be16(f, &v16)) + return -1; + p->d_inner = v16; + if (fget_be16(f, &v16)) + return -1; + p->d_pos = v16; + if (fget_be16(f, &v16)) + return -1; + p->mem_len = v16; + for(i = 0; i < p->n_layer; i++) { + if (fget_be16(f, &v16)) + return -1; + p->attn_len[i] = v16; + } + if (fget_u8(f, &v8)) + return -1; + p->tied_embed = v8; + if (fget_u8(f, &v8)) + return -1; + p->use_bias = v8; + if (fget_u8(f, &v8)) + return -1; + p->use_w_r = v8; + if (fget_u8(f, &v8)) + return -1; + p->tied_w_r = v8; + if (fget_u8(f, &v8)) + return -1; + p->tied_b_r = v8; + if (fget_u8(f, &v8)) + return -1; + p->query_bias = v8; + if (fget_u8(f, &v8)) + return -1; + p->rotary_pos_embed = v8; + if (fget_u8(f, &v8)) + return -1; + p->ln_flags = v8; + if (fget_f32(f, &p->init_range)) + return -1; + if (fget_f32(f, &p->embed_mult)) + return -1; + if (fget_u8(f, &v8)) + return -1; + p->ff_act = v8; + + if (fget_sgd_opt(f, &p->sgd_opt)) + return -1; + + if (np->retrain_period != 0) { + fget_f32(f, &p->dropout_prob); + fget_f32(f, &p->dropout_att_prob); + } + + if (fget_u8(f, &v8)) + return -1; + p->use_sparse_grad = v8; + return 0; +} + +static const CMDOptDesc trf_options[] = { + { "n_layer", CMD_HAS_ARG, "number of layers" }, + { "d_model", CMD_HAS_ARG, "model dimension" }, + { "n_head", CMD_HAS_ARG, "number of attention heads" }, + { "d_key", CMD_HAS_ARG, "set the attention key dimension" }, + { "d_value", CMD_HAS_ARG, "set the attention value dimension" }, + { "mem_len", CMD_HAS_ARG, "recurrent memory length" }, + { "d_pos", CMD_HAS_ARG, "number of relative positions" }, + { "d_inner", CMD_HAS_ARG, "dimension of the feed forward layer" }, + { "query_bias", CMD_HAS_ARG, "add a query bias" }, + { "rot_pos", CMD_HAS_ARG, "rotary position embedding" }, + + { "init_range", CMD_HAS_ARG, "initial range" }, + { "tied_embed", CMD_HAS_ARG, "use tied embedding" }, + { "use_bias", CMD_HAS_ARG, "use bias in matmul" }, + { "use_w_r", CMD_HAS_ARG, "use relative pos dot products" }, + { "tied_w_r", CMD_HAS_ARG, "use tied relative pos encodings" }, + { "tied_b_r", CMD_HAS_ARG, "use tied relative pos bias" }, + { "ln_flags", CMD_HAS_ARG, "layer normalisation flags" }, + { "gradient_clip", CMD_HAS_ARG, "per parameter gradient clip value" }, + { "attn_len", CMD_HAS_ARG, "per layer attention length" }, + { "embed_mult", CMD_HAS_ARG, "embedding multiplier" }, + { "retrain_dropout", CMD_HAS_ARG, "retrain dropout" }, + { "retrain_dropout_att", CMD_HAS_ARG, "retrain dropout for the attention" }, + + { "ff_act", CMD_HAS_ARG, "feed forward activation: 0=RELU, 1=GELU, 2=GEGLU" }, + { "sparse_grad", CMD_HAS_ARG, "use sparse gradient update" }, + { NULL }, +}; + +static void trf_parse_options(NNCPModelParams *np, CMDOption *co) +{ + TransformerModelParams *p = &np->u.trf; + const char *r; + int i; + + p->n_layer = cmdopt_get_int(co, "n_layer", p->n_layer); + + p->d_model = cmdopt_get_int(co, "d_model", p->d_model); + p->n_head = cmdopt_get_int(co, "n_head", p->n_head); + p->d_key = p->d_model / p->n_head; + p->d_value = p->d_key; + + p->d_key = cmdopt_get_int(co, "d_key", p->d_key); + p->d_value = cmdopt_get_int(co, "d_value", p->d_value); + + p->d_inner = cmdopt_get_int(co, "d_inner", p->d_inner); + + p->mem_len = cmdopt_get_int(co, "mem_len", p->mem_len); + p->d_pos = cmdopt_get_int(co, "d_pos", p->d_pos); + + for(i = 0; i < p->n_layer; i++) + p->attn_len[i] = p->mem_len + np->seg_len; + + p->init_range = cmdopt_get_float(co, "init_range", p->init_range); + + p->tied_embed = cmdopt_get_int(co, "tied_embed", p->tied_embed); + + p->use_bias = (cmdopt_get_int(co, "use_bias", p->use_bias) != 0); + p->use_w_r = (cmdopt_get_int(co, "use_w_r", p->use_w_r) != 0); + p->tied_w_r = (cmdopt_get_int(co, "tied_w_r", p->tied_w_r) != 0); + p->tied_b_r = (cmdopt_get_int(co, "tied_b_r", p->tied_b_r) != 0); + + p->ln_flags = cmdopt_get_int(co, "ln_flags", p->ln_flags); + + p->sgd_opt.u.adam.gradient_clip = + cmdopt_get_float(co, "gradient_clip", p->sgd_opt.u.adam.gradient_clip); + p->embed_mult = cmdopt_get_float(co, "embed_mult", p->embed_mult); + + r = cmdopt_get(co, "attn_len"); + if (r) { + p->attn_len[0] = strtoul(r, (char **)&r, 0); + if (*r == '\0') { + for(i = 1; i < p->n_layer; i++) + p->attn_len[i] = p->attn_len[0]; + } else { + for(i = 1; i < p->n_layer; i++) { + skip_c(&r, ','); + p->attn_len[i] = strtoul(r, (char **)&r, 0); + } + } + } + + p->dropout_prob = cmdopt_get_float(co, "retrain_dropout", + p->dropout_prob); + p->dropout_att_prob = cmdopt_get_float(co, "retrain_dropout_att", + p->dropout_att_prob); + + p->query_bias = (cmdopt_get_int(co, "query_bias", p->query_bias) != 0); + + p->rotary_pos_embed = (cmdopt_get_int(co, "rot_pos", p->rotary_pos_embed) != 0); + + p->ff_act = cmdopt_get_int(co, "ff_act", p->ff_act); + + p->use_sparse_grad = cmdopt_get_int(co, "sparse_grad", 0); +} + +static NNCPModelClass trf_model = { + "trf", + 0, + sizeof(TransformerModel), + trf_options, + trf_parse_options, + trf_write_params, + trf_read_params, + trf_dump_params, + trf_init, + trf_end, + trf_eval, + trf_eval_end, + trf_eval_gradient, + trf_reset, + trf_update, + trf_set_retrain, + trf_set_lr, +}; + +/*********************************************************/ +/* LSTM model */ + +typedef uint16_t DataSymbol; + +#define LSTM_MAT_COUNT_MAX 4 + +#define LSTM_FORGET_GATE 0 +#define LSTM_INPUT_NODE 1 +#define LSTM_OUTPUT_GATE 2 +#define LSTM_INPUT_GATE 3 + +#define GRU_UPDATE_GATE 0 +#define GRU_RESET_GATE 1 +#define GRU_OUTPUT_NODE 2 + +typedef struct { + BOOL use_layer_norm; + int mat_count; + NCTensor *u; + NCTensor *w; + NCTensor *ws; + NCTensor *b[LSTM_MAT_COUNT_MAX]; + NCTensor *g[LSTM_MAT_COUNT_MAX]; /* only for layer norm */ + NCTensor *p; /* only used for projection */ + NCTensor *c0; /* initial memory state */ + NCTensor *h0; /* initial output */ + NCTensor *c; /* current memory state */ + NCTensor *h; /* current output */ + NCNode **w_nodes; + NCNode **ws_nodes; +} LSTMCell; + +typedef struct { + NNCPModelState common; + + BOOL seq_eval; + int n_layers; + int n_inputs; + int n_outputs; + int n_cells; + int n_streams; + int n_states; + int seg_len; + BOOL full_connect; + int n_cells2; + int n_embed_out; + LSTMTypeEnum lstm_type; + LSTMCell *lstm_layers; + NCTensor *fc_b, *fc_w; + NCTensor **outputs; + NCSGDOptState *sgd_opt; + int retrain_start; /* in symbols, multiple of block_len */ + int retrain_factor; /* multiplied by 100 */ + NCParamList param_list; + float dropout_prob0; + float dropout_prob; + BOOL use_sparse_grad; + NCTypeEnum param_type; /* F32 or BF16 */ +} LSTM; + +static void lstm_reset(NNCPModelState *s); +static void lstm_set_batch_size(LSTM *s, int batch_size); + +static NCTensor *concat_add(NCTensor **tab, int n_in, int n_out) +{ + NCTensor **tab1, *out; + int q, r, i, n, j, k; + assert(n_out <= n_in); + tab1 = nc_mallocz(sizeof(tab1[0]) * n_out); + q = n_in / n_out; + r = n_in % n_out; + /* if r != 0, we add less high order inputs */ + k = 0; + for(i = 0; i < n_out; i++) { + n = q + (i < r); + tab1[i] = tab[k++]; + for(j = 1; j < n; j++) { + tab1[i] = nc_add(tab1[i], tab[k++]); + } + } + assert(k == n_in); + out = nc_vconcat(tab1, n_out); + nc_free(tab1); + return out; +} + +static void var_init_rnd(NCTensor *x, float range, NCRNDState *rnd_state) +{ + nc_tensor_set_rnd_unif(x, 0, range, rnd_state); +} + +static NCTensor *dropout2_init(LSTM *s, + float prob, int n_dims, const size_t *dims) +{ +#if 0 + NCTensor *mult; + NCTensorData xbuf, *x; + size_t i, j; + int v; + float m; + + mult = nc_new_tensor(s->device, NC_TYPE_F32, n_dims, dims); + x = nc_tensor_get_data(&xbuf, mult); + m = 1.0f / (1.0f - prob); + for(i = 0; i < x->n_strides; i++) { + for(j = 0; j < x->dims[0]; j++) { + v = (rnd_unif(s->rnd_state) >= prob); + ((float *)x->data)[i * x->stride + j] = (float)v * m; + } + } + return mult; +#else + return NULL; +#endif +} + +static NCTensor *dropout2_init_2d(LSTM *s, + float prob, size_t d0, size_t d1) +{ + size_t dims[2]; + dims[0] = d0; + dims[1] = d1; + return dropout2_init(s, prob, 2, dims); +} + +static NCTensor *dropout2_mul(LSTM *s, NCTensor *x, float prob) +{ + NCTensor *d; + size_t dims[NC_N_DIMS_MAX]; + int n_dims; + + n_dims = nc_tensor_get_dims(x, dims); + d = dropout2_init(s, prob, n_dims, dims); + return nc_mul(x, d); +} + +static void lstm_init(NNCPModelState *s1, const NNCPModelParams *np) +{ + LSTM *s = (LSTM *)s1; + const LSTMParams *p = &np->u.lstm; + int layer_idx; + NCContext *m = s1->model; + NCDevice *d = s1->device; + int j; + + assert(np->seg_len <= p->n_states); + + s->n_states = p->n_states; + s->seg_len = np->seg_len; + s->n_layers = p->n_layers; + s->n_inputs = np->n_symbols; + s->n_outputs = np->n_symbols; + s->n_cells = p->n_cells; + s->lstm_type = p->lstm_type; + s->full_connect = p->full_connect; + s->n_embed_out = p->n_embed_out; + s->n_cells2 = p->n_cells2; + + s->use_sparse_grad = p->use_sparse_grad; + + nc_param_list_init(m, &s->param_list); + + if (np->use_bf16) + s->param_type = NC_TYPE_BF16; + else + s->param_type = NC_TYPE_F32; + + s->lstm_layers = nc_mallocz(sizeof(s->lstm_layers[0]) * s->n_layers); + for(layer_idx = 0; layer_idx < s->n_layers; layer_idx++) { + LSTMCell *lc; + int n_inputs, n_sparse_inputs; + lc = &s->lstm_layers[layer_idx]; + if (p->full_connect) { + /* input from all previous layers */ + n_inputs = s->n_cells * layer_idx; + } else { + /* input from the previous layer */ + n_inputs = layer_idx != 0 ? s->n_cells : 0; + } + n_sparse_inputs = s->n_inputs; + + lc->use_layer_norm = p->use_layer_norm; + assert(p->n_cells2 >= s->n_cells); + if (p->lstm_type == LSTM_TYPE_TIED || p->lstm_type == LSTM_TYPE_GRU) { + lc->mat_count = 3; + } else { + lc->mat_count = 4; + } + lc->u = nc_new_tensor_2d(d, s->param_type, p->n_cells2 * lc->mat_count, + p->n_cells); + nc_new_param(&s->param_list, &lc->u, "u%d", layer_idx); + var_init_rnd(lc->u, 1.0f / sqrtf(p->n_cells), s->common.rnd_state); + if (n_inputs != 0) { + lc->w = nc_new_tensor_2d(d, s->param_type, p->n_cells2 * lc->mat_count, + n_inputs); + nc_new_param(&s->param_list, &lc->w, "w%d", layer_idx); + var_init_rnd(lc->w, 1.0f / sqrtf(n_inputs), s->common.rnd_state); + lc->w_nodes = nc_mallocz(sizeof(lc->w_nodes[0]) * s->seg_len); + } + if (n_sparse_inputs != 0) { + lc->ws = nc_new_tensor_2d(d, NC_TYPE_F32, p->n_cells2 * lc->mat_count, + n_sparse_inputs); + nc_new_param(&s->param_list, &lc->ws, "ws%d", layer_idx); + var_init_rnd(lc->ws, 0.75f, s->common.rnd_state); + lc->ws_nodes = nc_mallocz(sizeof(lc->w_nodes[0]) * s->seg_len); + } + for(j = 0; j < lc->mat_count; j++) { + lc->b[j] = nc_new_tensor_1d(d, s->param_type, p->n_cells2); + nc_new_param(&s->param_list, &lc->b[j], "b%d_%d", layer_idx, j); + if (lc->use_layer_norm) { + lc->g[j] = nc_new_scalar(d, s->param_type); + nc_new_param(&s->param_list, &lc->g[j], "g%d_%d", layer_idx, j); + nc_tensor_set_f32(lc->g[j], 1.0f); + } + } + nc_tensor_set_f32(lc->b[LSTM_FORGET_GATE], p->forget_bias); + + if (p->n_cells2 != p->n_cells) { + lc->p = nc_new_tensor_2d(d, s->param_type, p->n_cells, p->n_cells2); + nc_new_param(&s->param_list, &lc->p, "p%d", layer_idx); + var_init_rnd(lc->p, sqrtf(1.0f / p->n_cells2), s->common.rnd_state); + } + } + + s->fc_b = nc_new_tensor_1d(d, s->param_type, s->n_outputs); + nc_new_param(&s->param_list, &s->fc_b, "fc_b"); + s->fc_w = nc_new_tensor_2d(d, s->param_type, s->n_outputs, s->n_cells * p->n_embed_out); + nc_new_param(&s->param_list, &s->fc_w, "fc_w"); + var_init_rnd(s->fc_w, sqrtf(12.0f / (s->n_cells * s->n_layers)), + s->common.rnd_state); + + s->outputs = nc_mallocz(sizeof(s->outputs[0]) * s->n_states); + + lstm_set_batch_size(s, np->batch_size); + + /* apply the SGD optimizer to all the parameters */ + s->sgd_opt = nc_sgd_opt_init(m, &p->sgd_opt); + + nc_sgd_opt_set_all(&s->param_list, s->sgd_opt); + + lstm_reset(s1); + + /* retrain parameters */ + s->retrain_start = p->retrain_start; + s->retrain_factor = p->retrain_factor; + s->dropout_prob0 = p->dropout_prob; + s->dropout_prob = 0; +} + +/* change the batch size */ +static void lstm_set_batch_size(LSTM *s, int batch_size) +{ + NCDevice *d = s->common.device; + int i; + + s->n_streams = batch_size; + + /* XXX: keep the data */ + for(i = 0; i < s->n_layers; i++) { + LSTMCell *lc = &s->lstm_layers[i]; + nc_free_tensor(lc->h0); + nc_free_tensor(lc->c0); + lc->h0 = nc_new_tensor_2d(d, s->param_type, s->n_cells, s->n_streams); + if (s->lstm_type != LSTM_TYPE_GRU) { + lc->c0 = nc_new_tensor_2d(d, s->param_type, s->n_cells2, s->n_streams); + } + } +} + +static void lstm_end(NNCPModelState *s1) +{ + LSTM *s = (LSTM *)s1; + int i; + + nc_sgd_opt_set_all(&s->param_list, NULL); + nc_sgd_opt_end(s->sgd_opt); + + nc_param_list_end(&s->param_list); + + nc_free(s->outputs); + + for(i = 0; i < s->n_layers; i++) { + LSTMCell *lc = &s->lstm_layers[i]; + nc_free_tensor(lc->c0); + nc_free_tensor(lc->h0); + nc_free_tensor(lc->c); + nc_free_tensor(lc->h); + nc_free(lc->w_nodes); + nc_free(lc->ws_nodes); + } + + nc_free(s->lstm_layers); +} + +static void lstm_reset(NNCPModelState *s1) +{ + LSTM *s = (LSTM *)s1; + int i; + for(i = 0; i < s->n_layers; i++) { + LSTMCell *lc = &s->lstm_layers[i]; + nc_tensor_set_f32(lc->h0, 0); + if (lc->c) { + nc_tensor_set_f32(lc->c0, 0); + } + } +} + +static NCTensor *lstm_eval(NNCPModelState *s1, + int output_index, const NCTensor *input) +{ + LSTM *s = (LSTM *)s1; + NCDevice *d = s->common.device; + int state_start, overlap, state_end, layer_idx; + int state_start_out, state_idx, i, j, len; + NCTensor *t0, *c, *h, **layer_output, **tab_tmp, **tab_tmp1, *t1; + NCTensor *h_dropout, *output; + prof_start(PROF_EVAL); + + overlap = s->n_states - s->seg_len; + if (output_index < 0) { + s->seq_eval = FALSE; + state_start = 0; + state_start_out = overlap; + state_end = s->n_states; + } else { + s->seq_eval = TRUE; + if (output_index == 0) + state_start = 0; + else + state_start = overlap + output_index; + state_start_out = overlap + output_index; + state_end = state_start_out + 1; + assert(s->dropout_prob == 0); /* dropout is not supported in decoder */ + } + + layer_output = nc_mallocz(sizeof(layer_output[0]) * + s->n_states * s->n_layers); + tab_tmp = nc_mallocz(sizeof(tab_tmp[0]) * + max_int(LSTM_MAT_COUNT_MAX * s->n_states, + s->n_layers)); + tab_tmp1 = nc_mallocz(sizeof(tab_tmp1[0]) * s->n_states); + + for(layer_idx = 0; layer_idx < s->n_layers; layer_idx++) { + LSTMCell *lc = &s->lstm_layers[layer_idx]; + + /* handle the inputs first for cache locality */ + t0 = nc_slice_alias(input, 1, state_start, state_end); + t0 = nc_tensor_to_device(t0, d); + t0 = nc_reshape_1d(t0, (state_end - state_start) * s->n_streams); + t1 = nc_get_col(nc_dup_tensor(lc->ws), t0); + if (output_index >= 0) + lc->ws_nodes[output_index] = nc_get_node(t1); + t1 = nc_convert(t1, s->param_type); + if (s->dropout_prob != 0) { + t1 = dropout2_mul(s, t1, s->dropout_prob); + } + + if (layer_idx != 0) { + for(state_idx = state_start; state_idx < state_end; state_idx++) { + if (!s->full_connect || layer_idx == 1) { + t0 = nc_dup_tensor(layer_output[state_idx * s->n_layers + layer_idx - 1]); + } else { + for(i = 0; i < layer_idx; i++) + tab_tmp[i] = nc_dup_tensor(layer_output[state_idx * s->n_layers + i]); + t0 = nc_vconcat(tab_tmp, layer_idx); + } + tab_tmp1[state_idx] = t0; + } + t0 = nc_hconcat(tab_tmp1 + state_start, state_end - state_start); + if (s->dropout_prob != 0) { + t0 = dropout2_mul(s, t0, s->dropout_prob); + } + t0 = nc_matmul(nc_dup_tensor(lc->w), t0); + if (output_index >= 0) + lc->w_nodes[output_index] = nc_get_node(t0); + t1 = nc_add(t1, t0); + } + nc_split(tab_tmp + state_start, t1, state_end - state_start, NULL, 1); + + if (state_start == 0) { + nc_free_tensor(lc->h); + lc->h = nc_new_tensor_2d(d, s->param_type, s->n_cells, s->n_streams); + nc_tensor_copy(lc->h, lc->h0); + if (lc->c0) { + nc_free_tensor(lc->c); + lc->c = nc_new_tensor_2d(d, s->param_type, s->n_cells2, s->n_streams); + nc_tensor_copy(lc->c, lc->c0); + } + } + h = lc->h; + c = lc->c; + h_dropout = NULL; + for(state_idx = state_start; state_idx < state_end; state_idx++) { + NCTensor *tab[LSTM_MAT_COUNT_MAX]; + if (s->dropout_prob != 0) { + if (!h_dropout) { + h_dropout = dropout2_init_2d(s, s->dropout_prob, + s->n_cells, + s->n_streams); + } + h = nc_mul(h, nc_dup_tensor(h_dropout)); + } + /* XXX: GRU is no longer supported */ + t0 = nc_matmul(nc_dup_tensor(lc->u), h); + t0 = nc_add(t0, tab_tmp[state_idx]); + nc_split(tab, t0, lc->mat_count, NULL, 0); + + for(j = 0; j < lc->mat_count; j++) { + t0 = tab[j]; + if (lc->use_layer_norm) { + t0 = nc_mul(nc_rms_norm(t0, 1e-5), nc_dup_tensor(lc->g[j])); + } + t0 = nc_add(t0, nc_dup_tensor(lc->b[j])); + tab[j] = t0; + } + + if (s->lstm_type == LSTM_TYPE_GRU) { + h = nc_lerp(nc_tanh(tab[GRU_OUTPUT_NODE]), h, + nc_sigmoid(tab[GRU_UPDATE_GATE])); + } else { + NCTensor *fg, *ig, *og, *in; + fg = nc_sigmoid(tab[LSTM_FORGET_GATE]); + og = nc_sigmoid(tab[LSTM_OUTPUT_GATE]); + in = nc_tanh(tab[LSTM_INPUT_NODE]); + switch(s->lstm_type) { + case LSTM_TYPE_NORMAL: + ig = nc_sigmoid(tab[LSTM_INPUT_GATE]); + c = nc_add(nc_mul(c, fg), nc_mul(in, ig)); + h = nc_mul(og, nc_tanh(nc_dup_tensor(c))); + break; + case LSTM_TYPE_CLAMPED: + ig = nc_sigmoid(tab[LSTM_INPUT_GATE]); + c = nc_lstm_clamped(c, in, fg, ig); + h = nc_mul(og, nc_dup_tensor(c)); + break; + case LSTM_TYPE_TIED: + c = nc_lerp(in, c, fg); + h = nc_mul(og, nc_dup_tensor(c)); + break; + default: + abort(); + } + } + /* optional projection */ + if (lc->p) + h = nc_matmul(nc_dup_tensor(lc->p), h); + + nc_tensor_set_name(h, "h%d_%d", layer_idx, state_idx); + layer_output[state_idx * s->n_layers + layer_idx] = + nc_dup_tensor(h); + if (state_idx == (s->seg_len - 1)) { + nc_tensor_copy(lc->h0, h); + if (lc->c0) + nc_tensor_copy(lc->c0, c); + } + } + nc_free_tensor(h_dropout); + lc->h = h; + lc->c = c; + } + + /* free the unused layer output */ + for(state_idx = state_start; state_idx < state_start_out; state_idx++) { + for(layer_idx = 0; layer_idx < s->n_layers; layer_idx++) { + nc_free_tensor(layer_output[state_idx * s->n_layers + layer_idx]); + } + } + + /* for efficiency, do the matrix multiplication on all the states + at once */ + for(state_idx = state_start_out; state_idx < state_end; state_idx++) { + t0 = concat_add(layer_output + state_idx * s->n_layers, + s->n_layers, s->n_embed_out); + tab_tmp1[state_idx - state_start_out] = t0; + } + len = state_end - state_start_out; + t0 = nc_hconcat(tab_tmp1, len); + if (s->dropout_prob != 0) { + t0 = dropout2_mul(s, t0, s->dropout_prob); + } + t0 = nc_matmul(nc_dup_tensor(s->fc_w), t0); + t0 = nc_add(t0, nc_dup_tensor(s->fc_b)); + t0 = nc_convert(t0, NC_TYPE_F32); + t0 = nc_reshape_3d(t0, s->n_outputs, s->n_streams, len); + output = nc_soft_max(t0); + s->outputs[state_start_out - overlap] = nc_dup_tensor(output); + + nc_free(layer_output); + nc_free(tab_tmp); + nc_free(tab_tmp1); + + prof_end(PROF_EVAL); + return output; +} + +static void lstm_eval_end(NNCPModelState *s1) +{ + LSTM *s = (LSTM *)s1; + int i; + for(i = 0; i < s->seg_len; i++) { + nc_free_tensor(s->outputs[i]); + s->outputs[i] = NULL; + } +} + +static float lstm_eval_gradient(NNCPModelState *s1, const NCTensor *expected_output) +{ + LSTM *s = (LSTM *)s1; + NCContext *m = s->common.model; + NCDevice *d = s->common.device; + int layer_idx, i; + NCTensor *loss, *output; + float ret_loss; + + prof_start(PROF_GRAD); + + /* compute the loss */ + if (s->seq_eval) { + NCNode *output_node; + output = nc_concat(s->outputs, s->seg_len, 2); + for(i = 0; i < s->seg_len; i++) + s->outputs[i] = NULL; + output_node = nc_get_node(output); + nc_concat_optimization(m, &output_node, 1); + } else { + output = s->outputs[0]; + s->outputs[0] = NULL; + } + + loss = nc_indexed_log(output, nc_tensor_to_device(nc_dup_tensor(expected_output), d)); + loss = nc_sum(loss); + ret_loss = nc_get_scalar_f32(loss); + loss = nc_mul(loss, nc_new_f32(d, -1.0f / (s->seg_len * s->n_streams))); + + /* in the decoder, combine the matmul and additions so that the + result of the backward pass is the same as in the encoder. It + also reduces the computation cost */ + if (s->seq_eval) { + size_t *tab; + tab = nc_malloc(sizeof(tab[0]) * s->seg_len); + tab[0] = (s->n_states - s->seg_len + 1) * s->n_streams; + for(i = 1; i < s->seg_len; i++) + tab[i] = s->n_streams; + for(layer_idx = 0; layer_idx < s->n_layers; layer_idx++) { + LSTMCell *lc = &s->lstm_layers[layer_idx]; + if (lc->w_nodes) { + nc_combine_nodes(m, lc->w_nodes, s->seg_len, 1, 0, + tab); + } + nc_combine_nodes(m, lc->ws_nodes, s->seg_len, 1, 0, tab); + } + nc_free(tab); + } + // nc_dump_graph(loss); exit(1); + +#ifdef DUMP_GRAD_NORM + grad_sum = 0; + grad_count = 0; +#endif + nc_backward(loss, nc_new_f32(d, 1.0), backward_cb, + s->use_sparse_grad ? NC_BW_SPARSE_GRAD : 0); + nc_free_tensor(loss); +#ifdef DUMP_GRAD_NORM + printf("grad: norm=%0.2e RMS=%0.2e\n", + sqrt(grad_sum), sqrt(grad_sum / grad_count)); +#endif + prof_end(PROF_GRAD); + return ret_loss; +} + +/* update with coefficients */ +static void lstm_update(NNCPModelState *s1) +{ + LSTM *s = (LSTM *)s1; + prof_start(PROF_UPDATE); + nc_sgd_opt_update(s->sgd_opt); + prof_end(PROF_UPDATE); +} + +static void lstm_dump_params(FILE *f, NNCPModelState *s1, + const NNCPModelParams *np) +{ + LSTM *s = (LSTM *)s1; + const LSTMParams *p = &np->u.lstm; + char buf1[32], buf3[32]; + uint64_t n_params, n_params_nie; + int mat_count; + + fprintf(f, "cell="); + switch(p->lstm_type) { + case LSTM_TYPE_CLAMPED: + fprintf(f, "LSTM-C"); + break; + case LSTM_TYPE_TIED: + fprintf(f, "LSTM-T"); + break; + case LSTM_TYPE_NORMAL: + fprintf(f, "LSTM"); + break; + case LSTM_TYPE_GRU: + fprintf(f, "GRU"); + break; + default: + abort(); + } + fprintf(f, " n_layer=%d hidden_size=%d time_steps=%d ln=%d fc=%d forget_bias=%0.1f", + p->n_layers, + p->n_cells, p->n_states, + p->use_layer_norm, p->full_connect, p->forget_bias); + if (p->n_cells2 != p->n_cells) + fprintf(f, " proj=%d", p->n_cells2); + if (p->n_embed_out != p->n_layers) + fprintf(f, " n_embed_out=%d", p->n_embed_out); + if (p->retrain_start != 0) { + fprintf(f, " dropout=%0.3g", + p->dropout_prob); + } + dump_sgd_opt_params(f, &p->sgd_opt); + + n_params = nc_get_param_count(&s->param_list); + /* without input embeddings */ + n_params_nie = n_params; + if (p->lstm_type == LSTM_TYPE_TIED || p->lstm_type == LSTM_TYPE_GRU) + mat_count = 3; + else + mat_count = 4; + n_params_nie -= p->n_layers * mat_count * p->n_cells2 * np->n_symbols; + + fprintf(f, " n_params=%s n_params_nie=%s\n", + get_si_prefix(buf1, sizeof(buf1), n_params), + get_si_prefix(buf3, sizeof(buf3), n_params_nie)); +} + +static void lstm_write_params(FILE *f, const NNCPModelParams *np) +{ + const LSTMParams *p = &np->u.lstm; + fput_u8(f, p->lstm_type); + fput_u8(f, p->n_layers); + fput_u8(f, p->n_embed_out); + fput_be16(f, p->n_cells); + fput_be16(f, p->n_states); + fput_u8(f, p->use_layer_norm | (p->full_connect << 1)); + fput_sgd_opt(f, &p->sgd_opt); + fput_f32(f, p->dropout_prob); + fput_f32(f, p->forget_bias); + fput_u8(f, p->use_sparse_grad); +} + +static int lstm_read_params(FILE *f, NNCPModelParams *np) +{ + LSTMParams *p = &np->u.lstm; + uint16_t v16; + uint8_t v8; + + if (fget_u8(f, &v8)) + return -1; + p->lstm_type = v8; + if (fget_u8(f, &v8)) + return -1; + p->n_layers = v8; + if (fget_u8(f, &v8)) + return -1; + p->n_embed_out = v8; + if (fget_be16(f, &v16)) + return -1; + p->n_cells = v16; + p->n_cells2 = p->n_cells; + if (fget_be16(f, &v16)) + return -1; + p->n_states = v16; + if (fget_u8(f, &v8)) + return -1; + p->use_layer_norm = v8 & 1; + p->full_connect = (v8 >> 1) & 1; + if (fget_sgd_opt(f, &p->sgd_opt)) + return -1; + if (fget_f32(f, &p->dropout_prob)) + return -1; + if (fget_f32(f, &p->forget_bias)) + return -1; + if (fget_u8(f, &v8)) + return -1; + p->use_sparse_grad = v8; + return 0; +} + +static void lstm_set_lr(NNCPModelState *s1, float lr) +{ + LSTM *s = (LSTM *)s1; + nc_sgd_opt_set_lr(s->sgd_opt, lr); +} + +static const CMDOptDesc lstm_options[] = { + { "n_layer", CMD_HAS_ARG, "number of layers" }, + { "hidden_size", CMD_HAS_ARG, "number of LSTM hidden states", "n" }, + { "cell", CMD_HAS_ARG, "LSTM cell variant", "[lstm|lstmc|lstmt]" }, + { "full_connect", CMD_HAS_ARG, "fully connect all the layers", "[0|1]" }, + { "n_embed_out", CMD_HAS_ARG, "number of layers in output embedding", "n" }, + { "layer_norm", CMD_HAS_ARG, "enable layer normalization", "[0|1]" }, + { "adam_beta1", CMD_HAS_ARG, "ADAM beta1 parameter" }, + { "adam_beta2", CMD_HAS_ARG, "ADAM beta2 parameter" }, + { "adam_eps", CMD_HAS_ARG, "ADAM epsilon parameter" }, + { "sparse_grad", CMD_HAS_ARG, "use sparse gradient update" }, + { NULL }, +}; + +static void lstm_parse_options(NNCPModelParams *np, CMDOption *co) +{ + LSTMParams *p = &np->u.lstm; + const char *r; + + p->n_layers = cmdopt_get_int(co, "n_layer", p->n_layers); + + p->n_cells = cmdopt_get_int(co, "hidden_size", p->n_cells); + p->n_cells2 = p->n_cells; + + r = cmdopt_get(co, "cell"); + if (r) { + if (!strcmp(r, "lstm")) + p->lstm_type = LSTM_TYPE_NORMAL; + else if (!strcmp(r, "lstmc")) + p->lstm_type = LSTM_TYPE_CLAMPED; + else if (!strcmp(r, "lstmt")) + p->lstm_type = LSTM_TYPE_TIED; +#if 0 + /* GRU is no longer supported */ + else if (!strcmp(r, "gru")) + p->lstm_type = LSTM_TYPE_GRU; +#endif + else { + cmd_error("unknown cell type: %s", r); + } + } + + p->full_connect = + (cmdopt_get_int(co, "full_connect", p->full_connect) != 0); + p->use_layer_norm = + (cmdopt_get_int(co, "layer_norm", p->use_layer_norm) != 0); + p->sgd_opt.u.adam.beta1 = + cmdopt_get_float(co, "adam_beta1", p->sgd_opt.u.adam.beta1); + p->sgd_opt.u.adam.beta2 = + cmdopt_get_float(co, "adam_beta2", p->sgd_opt.u.adam.beta2); + p->sgd_opt.u.adam.eps = + cmdopt_get_float(co, "adam_eps", p->sgd_opt.u.adam.eps); + p->use_sparse_grad = cmdopt_get_int(co, "sparse_grad", 0); +} + +static NNCPModelClass lstm_model = { + "lstm", + 1, + sizeof(LSTM), + lstm_options, + lstm_parse_options, + lstm_write_params, + lstm_read_params, + lstm_dump_params, + lstm_init, + lstm_end, + lstm_eval, + lstm_eval_end, + lstm_eval_gradient, + lstm_reset, + lstm_update, + NULL, + lstm_set_lr, +}; + +/*********************************************************/ + +static int stats_dump_interval = 100000; + +typedef struct { + char debug_dir[1024]; + FILE *log_file; + FILE *plot_file; + int64_t n_input_bytes; + int64_t last_n_input_bytes; + int64_t last_n_output_bytes; + int64_t last_time; + int64_t start_time; + BOOL header_output; + BOOL debug_output; + float last_lr; +} LogState; + +typedef struct { + int64_t max_size; /* truncate (preprocessed) input to max_size symbols */ + BOOL preprocess_flag; + int n_words; + int min_word_freq; + const char *dict_filename; /* if != NULL, force a dictionary and + assume the input is already + preprocessed */ + NNCPModelParams model_params; +} EncodeParams; + +static const NNCPModelClass *nncp_models[] = { + &trf_model, + &lstm_model, +}; + +static void log_init(LogState *st, const char *debug_dir, const char *prog_name) +{ + char filename[1024]; + + memset(st, 0, sizeof(*st)); + if (debug_dir) { + st->debug_output = TRUE; + create_debug_dir(st->debug_dir, sizeof(st->debug_dir), + debug_dir, prog_name); + printf("[Outputing logs to '%s']\n", st->debug_dir); + snprintf(filename, sizeof(filename), "%s/log.txt", st->debug_dir); + st->log_file = fopen(filename, "wb"); + if (!st->log_file) { + fprintf(stderr, "could not create '%s'\n", filename); + exit(1); + } + } + st->start_time = st->last_time = get_time_ms(); +} + +static void __attribute__((format(printf, 2, 3))) log_printf(LogState *st, const char *fmt, ...) +{ + va_list ap; + char buf[4096]; + size_t len, i; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + len = strlen(buf); + fwrite(buf, 1, len, stdout); + fflush(stdout); + if (st->log_file) { + for(i = 0; i < len; i++) { + if (buf[i] == '\r') + buf[i] = '\n'; + } + fwrite(buf, 1, len, st->log_file); + fflush(st->log_file); + } +} + +static void log_end(LogState *st) +{ + if (st->log_file) + fclose(st->log_file); + if (st->plot_file) + fclose(st->plot_file); +} + +static void log_dump(LogState *st, int64_t n_input_bytes, + int64_t n_output_bytes, int64_t train_step, float lr, + BOOL is_end) +{ + int64_t ti; + double bps, speed; + int n_input_bytes1, n_output_bytes1; + + if (is_end) { + /* last line is averaged over the whole file */ + ti = get_time_ms() - st->start_time; + bps = (double)(n_output_bytes * 8) / n_input_bytes; + speed = (double)n_input_bytes / ti; + } else { + n_input_bytes1 = n_input_bytes - st->last_n_input_bytes; + n_output_bytes1 = n_output_bytes - st->last_n_output_bytes; + ti = get_time_ms() - st->last_time; + if (ti <= 0) + ti = 1; + + bps = (double)(n_output_bytes1 * 8) / n_input_bytes1; + speed = (double)n_input_bytes1 / ti; + } + + if (!st->header_output) { + st->header_output = TRUE; + log_printf(st, "%1s %8s %10s %10s %6s %6s %8s\n", + "M", "STEP", "SIZE", "CSIZE", "BPS", "kS/s", "LR"); + } + log_printf(st, " %8" PRIu64 " %10" PRIu64 " %10" PRIu64 " %6.3f %6.2f %8.2e%c", + train_step, + n_input_bytes, + n_output_bytes, + bps, + speed, + lr, + is_end ? '\n' : '\r'); + if (st->plot_file) { + fprintf(st->plot_file, " %10" PRIu64 " %10" PRIu64 "\n", + n_input_bytes, + n_output_bytes); + fflush(st->plot_file); + } + st->last_time = get_time_ms(); + st->last_n_output_bytes = n_output_bytes; + st->last_n_input_bytes = n_input_bytes; +} + +static void nncp_init_params(NNCPModelParams *np, const char *profile) +{ + int i; + + memset(np, 0, sizeof(*np)); + np->seed = 123; + + if (!strcmp(profile, "default")) { + TransformerModelParams *p; + + np->block_len.n_steps = 0; + np->block_len.val[0] = 500000; + + np->batch_size = 16; + np->seg_len = 32; + np->n_symbols = 256; + + np->lr.n_steps = 1; + np->lr.val[0] = 3e-4; + np->lr.val[1] = 1e-4; + np->lr.pos[0] = 5e6 / 32; + + np->model_class = &trf_model; + p = &np->u.trf; + + p->n_layer = 4; + p->d_model = 256; + p->n_head = 8; + p->d_key = p->d_model / p->n_head; + p->d_value = p->d_key; + p->d_inner = p->d_model * 2; + p->d_pos = 32; + p->mem_len = 32; + for(i = 0; i < p->n_layer; i++) + p->attn_len[i] = p->mem_len + np->seg_len; + p->tied_embed = 0; + p->init_range = 1.0; + p->use_bias = 1; + p->use_w_r = 1; + p->tied_w_r = 1; + p->tied_b_r = 1; + p->ln_flags = LN_POST; + p->embed_mult = 1.0; + p->ff_act = FF_ACT_GELU; + + p->sgd_opt.algo = SGD_OPT_ADAM; + p->sgd_opt.u.adam.beta1 = 0; + p->sgd_opt.u.adam.beta2 = 0.9999; + p->sgd_opt.u.adam.eps = 1e-8; + p->sgd_opt.u.adam.gradient_clip = 0.1; + + } else if (!strcmp(profile, "enwik9") || + !strcmp(profile, "enwik8")) { + TransformerModelParams *p; + BOOL is_enwik8 = !strcmp(profile, "enwik8"); + + np->batch_size = 32; + np->seg_len = 64; + np->n_symbols = 256; /* will be modified by the preprocessor */ + + if (is_enwik8) { + parse_interp_param(&np->block_len, "100000,500000,100000,500000,500000"); + } else { + parse_interp_param(&np->block_len, "500000"); + } + parse_interp_param(&np->lr, "1.6e-4,10000,1.0e-4,p0.5"); + + if (is_enwik8) { + np->retrain_len = 15000000; + } else { + np->retrain_len = 7500000; + } + np->retrain_period = 1; + + np->has_retrain_lr = TRUE; + parse_interp_param(&np->retrain_lr, "1.6e-4,10000,1.0e-4,p0.5"); + + np->use_bf16 = 1; + + np->model_class = &trf_model; + p = &np->u.trf; + + p->n_layer = 20; + p->d_model = 1024; + p->n_head = 8; + p->d_key = p->d_model / p->n_head; + p->d_value = p->d_key; + p->d_inner = 3072; + p->ff_act = FF_ACT_GEGLU; + p->d_pos = 320; + p->mem_len = 256; + for(i = 0; i < p->n_layer; i++) + p->attn_len[i] = p->mem_len + np->seg_len; + p->tied_embed = 0; + p->init_range = 0.79; + p->use_bias = 1; + p->use_w_r = 1; + p->tied_w_r = 0; + p->tied_b_r = 1; + p->ln_flags = LN_PRE | LN_FINAL | LN_RMSNORM; + p->embed_mult = 1.0; + p->dropout_prob = 0.19; + p->dropout_att_prob = 0.19; + + p->sgd_opt.algo = SGD_OPT_ADAM; + p->sgd_opt.u.adam.beta1 = 0; + p->sgd_opt.u.adam.beta2 = 0.9999; + p->sgd_opt.u.adam.eps = 1e-8; + p->sgd_opt.u.adam.gradient_clip = 0.05; + + } else if (!strcmp(profile, "lstm")) { + LSTMParams *p; + + np->block_len.n_steps = 0; + np->block_len.val[0] = 500000; + + np->batch_size = 32; + np->seg_len = 20; + np->n_symbols = 256; + + np->lr.n_steps = 0; + np->lr.val[0] = 4e-3; + + np->model_class = &lstm_model; + p = &np->u.lstm; + p->use_layer_norm = TRUE; + p->full_connect = TRUE; + p->lstm_type = LSTM_TYPE_CLAMPED; + p->n_cells = 352; + p->n_layers = 4; + p->n_embed_out = p->n_layers; + p->n_states = np->seg_len; + p->n_cells2 = p->n_cells; + p->forget_bias = 0; + + p->sgd_opt.algo = SGD_OPT_ADAM; + p->sgd_opt.u.adam.beta1 = 0; + p->sgd_opt.u.adam.beta2 = 0.9999; + p->sgd_opt.u.adam.eps = 1e-10; + p->sgd_opt.u.adam.gradient_clip = 0; + + } else if (!strcmp(profile, "lstm_fast")) { + LSTMParams *p; + + np->block_len.n_steps = 0; + np->block_len.val[0] = 100000000; + + np->batch_size = 256; + np->seg_len = 20; + np->n_symbols = 256; + + np->lr.n_steps = 0; + np->lr.val[0] = 1e-2; + + np->model_class = &lstm_model; + p = &np->u.lstm; + p->use_layer_norm = TRUE; + p->full_connect = TRUE; + p->lstm_type = LSTM_TYPE_CLAMPED; + p->n_cells = 512; + p->n_layers = 4; + p->n_embed_out = p->n_layers; + p->n_states = np->seg_len; + p->n_cells2 = p->n_cells; + p->forget_bias = 0; + + p->sgd_opt.algo = SGD_OPT_ADAM; + p->sgd_opt.u.adam.beta1 = 0; + p->sgd_opt.u.adam.beta2 = 0.9999; + p->sgd_opt.u.adam.eps = 1e-10; + p->sgd_opt.u.adam.gradient_clip = 0; + + } else { + cmd_error("unknown profile: %s\n", profile); + } +} + +static void nncp_dump_params(FILE *f, NNCPModelState *s, const NNCPModelParams *p) +{ + fprintf(f, "model=%s bf16=%d batch_size=%d seg_len=%d n_symb=%d", + p->model_class->name, p->use_bf16, + p->batch_size, p->seg_len, p->n_symbols); + fprintf(f, " block_len="); + dump_interp_param(f, &p->block_len); + fprintf(f, " lr="); + dump_interp_param(f, &p->lr); + if (p->retrain_period != 0) { + fprintf(f, " retrain_period=%d retrain_len=%d", + p->retrain_period, p->retrain_len); + if (p->has_retrain_lr) { + fprintf(f, " retrain_lr="); + dump_interp_param(f, &p->retrain_lr); + } + } + fprintf(f, " "); + p->model_class->model_dump_params(f, s, p); +} + +#define NNCP_FILE_MAGIC 0xb727ac58 +#define NNCP_FILE_VERSION 1 + +static void nncp_write_file_header(FILE *f, const NNCPModelParams *p) +{ + fput_be32(f, NNCP_FILE_MAGIC); + fput_be16(f, NNCP_FILE_VERSION); + fput_u8(f, p->use_cuda); + fput_u8(f, p->use_bf16); + + fput_be16(f, p->batch_size); + fput_be16(f, p->seg_len); + fput_be16(f, p->n_symbols); + fput_be32(f, p->seed); + + fput_interp_params(f, &p->lr); + fput_interp_params(f, &p->block_len); + fput_be32(f, p->retrain_period); + if (p->retrain_period != 0) { + fput_be32(f, p->retrain_len); + fput_u8(f, p->has_retrain_lr); + if (p->has_retrain_lr) { + fput_interp_params(f, &p->retrain_lr); + } + } + + fput_u8(f, p->model_class->model_id); + p->model_class->model_write_params(f, p); +} + +static int nncp_read_file_header(FILE *f, NNCPModelParams *p) +{ + uint32_t v32; + uint16_t v16; + uint8_t v8; + int i; + + if (fget_be32(f, &v32)) + return -1; + if (v32 != NNCP_FILE_MAGIC) + return -1; + if (fget_be16(f, &v16)) + return -1; + if (v16 != NNCP_FILE_VERSION) + return -1; + if (fget_u8(f, &v8)) + return -1; + p->use_cuda = v8; + + if (fget_u8(f, &v8)) + return -1; + p->use_bf16 = v8; + + if (fget_be16(f, &v16)) + return -1; + p->batch_size = v16; + + if (fget_be16(f, &v16)) + return -1; + p->seg_len = v16; + + if (fget_be16(f, &v16)) + return -1; + p->n_symbols = v16; + + if (fget_be32(f, &p->seed)) + return -1; + + if (fget_interp_params(f, &p->lr)) + return -1; + + if (fget_interp_params(f, &p->block_len)) + return -1; + + fget_be32(f, &p->retrain_period); + if (p->retrain_period != 0) { + fget_be32(f, &p->retrain_len); + if (fget_u8(f, &v8)) + return -1; + p->has_retrain_lr = v8; + if (p->has_retrain_lr) { + if (fget_interp_params(f, &p->retrain_lr)) + return -1; + } + } + + /* model_id */ + if (fget_u8(f, &v8)) + return -1; + for(i = 0; i < countof(nncp_models); i++) { + if (nncp_models[i]->model_id == v8) + break; + } + if (i == countof(nncp_models)) + return -1; + p->model_class = nncp_models[i]; + + return p->model_class->model_read_params(f, p); +} + +static NNCPModelState *nncp_init(NNCPModelParams *p) +{ + NNCPModelState *s; + NCContext *m; + NCDevice *d; + + s = nc_mallocz(p->model_class->instance_size); + + m = nc_context_init(nb_threads); + s->model = m; + s->cpu_device = nc_new_cpu_device(m); + if (p->use_cuda) + d = nc_new_cuda_device(m, 0); + else + d = s->cpu_device; + s->device = d; + + s->rnd_state = nc_rnd_init(s->device, p->seed); + + s->model_class = p->model_class; + s->batch_size = p->batch_size; + s->seg_len = p->seg_len; + s->seed = p->seed; + s->n_symbols = p->n_symbols; + + s->lr = p->lr; + s->retrain_period = p->retrain_period; + s->retrain_buf_size = p->retrain_len; + + s->has_retrain_lr = p->has_retrain_lr; + s->retrain_lr = p->retrain_lr; + s->retrain_buf = nc_mallocz(sizeof(s->retrain_buf[0]) * s->retrain_buf_size); + s->retrain_buf_pos = 0; + s->retrain_buf_len = 0; + s->retrain_pos = 0; + + s->model_class->model_init(s, p); + return s; +} + +static void nncp_end(NNCPModelState *s) +{ + s->model_class->model_end(s); + nc_rnd_end(s->rnd_state); + nc_context_end(s->model); + nc_free(s->retrain_buf); + nc_free(s); +} + +static int get_symb_fifo(const DataSymbol *block_buf, int rpos, int size, + int idx) +{ + if (idx < 0) { + return 0; + } else { + return block_buf[(rpos + idx) % size]; + } +} + +static void retrain_block(NNCPModelState *s, + const DataSymbol *block_buf, int block_len, + int64_t file_pos, LogState *st) +{ + int l, pos, cur_state, c, stream_idx; + int n_streams, n_states, seg_len, overlap, block_stride, block_idx; + int64_t train_bytes, last_train_bytes; + NCTensor *expected_output, *input, *output; + double n_output_bits, last_n_output_bits; + int64_t last_time; + float lr, inv_log2; + + if (s->retrain_period == 0) + return; /* no retrain */ + + /* add the block to the retrain buffer */ + pos = 0; + while (pos < block_len) { + l = min_int(s->retrain_buf_size - s->retrain_buf_pos, block_len - pos); + memcpy(s->retrain_buf + s->retrain_buf_pos, block_buf + pos, + sizeof(block_buf[0]) * l); + s->retrain_buf_pos += l; + if (s->retrain_buf_pos == s->retrain_buf_size) + s->retrain_buf_pos = 0; + pos += l; + } + s->retrain_buf_len = min_int(s->retrain_buf_len + block_len, + s->retrain_buf_size); + s->retrain_pos += block_len; + if (s->retrain_pos < s->retrain_period) + return; + s->retrain_pos = 0; + + n_streams = s->batch_size; + n_states = s->seg_len; + seg_len = s->seg_len; + overlap = 0; + block_stride = s->retrain_buf_len / n_streams; + if (block_stride == 0) + return; + + /* statistics */ + train_bytes = file_pos - s->retrain_buf_len; + last_train_bytes = train_bytes; + n_output_bits = 0; + last_n_output_bits = 0; + inv_log2 = 1.0 / log(2); + last_time = get_time_ms(); + + block_idx = 0; + + s->model_class->model_set_retrain(s, TRUE); + + input = nc_new_tensor_2d(s->cpu_device, NC_TYPE_I32, + n_streams, n_states); + expected_output = nc_new_tensor_2d(s->cpu_device, NC_TYPE_I32, + n_streams, n_states); + s->model_class->model_reset(s); + + while (s->retrain_buf_len >= ((seg_len + block_idx) * n_streams)) { + prof_start(PROF_TOTAL); + for(cur_state = 0; cur_state < n_states; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + c = get_symb_fifo(s->retrain_buf, s->retrain_buf_pos, + s->retrain_buf_len, + block_stride * stream_idx + + block_idx + cur_state - 1 - overlap); + nc_set1_i32_2d(input, stream_idx, cur_state, c); + if (cur_state >= overlap) { + c = get_symb_fifo(s->retrain_buf, s->retrain_buf_pos, + s->retrain_buf_len, + block_stride * stream_idx + + block_idx + cur_state - overlap); + nc_set1_i32_2d(expected_output, stream_idx, + cur_state - overlap, c); + } + } + } + output = s->model_class->model_eval(s, -1, input); + nc_free_tensor(output); + + if (s->has_retrain_lr) { + lr = get_interp_param(&s->retrain_lr, s->retrain_train_step); + } else { + lr = get_interp_param(&s->lr, s->train_step); + } + s->model_class->model_set_lr(s, lr); + + n_output_bits -= s->model_class->model_eval_gradient(s, expected_output) * inv_log2; + s->model_class->model_update(s); + if (s->has_retrain_lr) { + s->retrain_train_step++; + } else { + s->train_step++; + } + block_idx += seg_len; + prof_end(PROF_TOTAL); + train_bytes += seg_len * n_streams; + if ((train_bytes - last_train_bytes) >= stats_dump_interval) { + double bps; + int64_t cur_time; + bps = (n_output_bits - last_n_output_bits) / + (train_bytes - last_train_bytes); + cur_time = get_time_ms(); + log_printf(st, "R %8" PRIu64 " %10" PRIu64 " %10s %6.3f %6.2f %8.2e\r", + s->has_retrain_lr ? s->retrain_train_step : s->train_step, + train_bytes, + "-", + bps, (double)(train_bytes - last_train_bytes) / + (double)(cur_time - last_time), + lr); + + last_train_bytes = train_bytes; + last_time = cur_time; + last_n_output_bits = n_output_bits; + } + } + nc_free_tensor(expected_output); + nc_free_tensor(input); + s->model_class->model_set_retrain(s, FALSE); +} + +/* the first rem streams have (stride + 1) symbols, the next ones have + stride symbols */ +static int get_symb(const DataSymbol *buf, int stride, int rem, + int stream_idx, int pos) +{ + int e; + + e = (stream_idx < rem); + if (pos < 0 || pos >= (stride + e)) + return 0; + return buf[stride * stream_idx + min_int(rem, stream_idx) + pos]; +} + +static void put_symb(DataSymbol *buf, int stride, int rem, + int stream_idx, int pos, int c) +{ + int e; + + e = (stream_idx < rem); + if (pos < 0 || pos >= (stride + e)) + abort(); + buf[stride * stream_idx + min_int(rem, stream_idx) + pos] = c; +} + +/* compress block_len bytes divided in n_streams */ +static void process_block(NNCPModelState *s, FILE *fo, + PutBitState *pb, GetBitState *gb, + DataSymbol *block_buf, int block_len, LogState *st, + BOOL is_decode) +{ + int block_idx, c, stream_idx, cur_state, n_states; + int block_stride, n_streams, block_rem, seg_len1, seg_len2; + float *output, lr; + size_t stride; + NCTensor *output_host, *expected_output, *input; + + n_streams = s->batch_size; + n_states = s->seg_len; + block_stride = block_len / n_streams; + block_rem = block_len % n_streams; + + input = nc_new_tensor_2d(s->cpu_device, NC_TYPE_I32, + n_streams, n_states); + expected_output = nc_new_tensor_2d(s->cpu_device, NC_TYPE_I32, + n_streams, n_states); + s->model_class->model_reset(s); + + /* normal batches */ + lr = 0; + block_idx = 0; + while ((block_idx + n_states) <= block_stride) { + prof_start(PROF_TOTAL); + if (!use_encode_only) { + for(cur_state = 0; cur_state < n_states; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + nc_set1_i32_2d(input, stream_idx, cur_state, + get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state - 1)); + } + + output_host = s->model_class->model_eval(s, cur_state, input); + output_host = nc_tensor_to_cpu_device(output_host); + output = nc_tensor_get_ptr(output_host, &stride); + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + prof_start(PROF_WRITE_SYM); + if (!is_decode) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state); + write_sym(pb, output + stream_idx * stride, s->n_symbols, c); + } else { + c = read_sym(gb, output + stream_idx * stride, + s->n_symbols); + put_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state, c); + } + prof_end(PROF_WRITE_SYM); + nc_set1_i32_2d(expected_output, stream_idx, cur_state, c); + } + nc_free_tensor(output_host); + } + } else { + for(cur_state = 0; cur_state < n_states; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + nc_set1_i32_2d(input, stream_idx, cur_state, + get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state - 1)); + } + } + output_host = s->model_class->model_eval(s, -1, input); + + output_host = nc_tensor_to_cpu_device(output_host); + output = nc_tensor_get_ptr(output_host, &stride); + for(cur_state = 0; cur_state < n_states; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state); + prof_start(PROF_WRITE_SYM); + write_sym(pb, output + (cur_state * n_streams + stream_idx) * stride, s->n_symbols, c); + prof_end(PROF_WRITE_SYM); + nc_set1_i32_2d(expected_output, stream_idx, cur_state, c); + } + } + nc_free_tensor(output_host); + } + + lr = get_interp_param(&s->lr, s->train_step); + st->last_lr = lr; + s->model_class->model_set_lr(s, lr); + + s->model_class->model_eval_gradient(s, expected_output); + s->model_class->model_update(s); + s->train_step++; + block_idx += n_states; + prof_end(PROF_TOTAL); + + /* statistics */ + { + int64_t n_output_bytes; + + st->n_input_bytes += n_states * n_streams; + if ((st->n_input_bytes - st->last_n_input_bytes) >= + stats_dump_interval) { + if (!is_decode) { + n_output_bytes = put_bit_get_bit_count(pb) / 8; + } else { + n_output_bytes = get_bit_get_bit_count(gb) / 8; + } + log_dump(st, st->n_input_bytes, n_output_bytes, + s->train_step, st->last_lr, FALSE); + } + } + } + + seg_len2 = block_stride - block_idx; + seg_len1 = seg_len2 + (block_rem != 0); + if (seg_len1 > 0) { + st->n_input_bytes += seg_len2 * n_streams + block_rem; + /* no training for the last batch */ + for(cur_state = 0; cur_state < n_states; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + nc_set1_i32_2d(input, stream_idx, cur_state, 0); + } + } + if (!use_encode_only) { + for(cur_state = 0; cur_state < seg_len1; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state - 1); + nc_set1_i32_2d(input, stream_idx, cur_state, c); + } + + output_host = s->model_class->model_eval(s, cur_state, input); + + output_host = nc_tensor_to_cpu_device(output_host); + output = nc_tensor_get_ptr(output_host, &stride); + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + if (cur_state < seg_len2 || + (cur_state == seg_len2 && stream_idx < block_rem)) { + if (!is_decode) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state); + write_sym(pb, output + stream_idx * stride, s->n_symbols, c); + } else { + c = read_sym(gb, output + stream_idx * stride, + s->n_symbols); + put_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state, c); + } + } + } + nc_free_tensor(output_host); + } + } else { + for(cur_state = 0; cur_state < seg_len1; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state - 1); + nc_set1_i32_2d(input, stream_idx, cur_state, c); + } + } + + output_host = s->model_class->model_eval(s, -1, input); + + output_host = nc_tensor_to_cpu_device(output_host); + output = nc_tensor_get_ptr(output_host, &stride); + for(cur_state = 0; cur_state < seg_len1; cur_state++) { + for(stream_idx = 0; stream_idx < n_streams; stream_idx++) { + if (cur_state < seg_len2 || + (cur_state == seg_len2 && stream_idx < block_rem)) { + c = get_symb(block_buf, block_stride, block_rem, + stream_idx, block_idx + cur_state); + write_sym(pb, output + + (cur_state * n_streams + stream_idx) * + stride, s->n_symbols, c); + } + } + } + nc_free_tensor(output_host); + } + s->model_class->model_eval_end(s); + } + + nc_free_tensor(expected_output); + nc_free_tensor(input); +} + +static const char *load_coefs_filename; +static BOOL quiet_flag; +static const char *plot_filename; + +static void read_block(FILE *f, DataSymbol *block_buf, int len, int symb_shift, + int n_symbols) +{ + int i, c; + for(i = 0; i < len; i++) { + if (symb_shift == 0) { + c = fgetc(f); + if (c < 0) + break; + } else { + uint16_t v16; + if (fget_be16(f, &v16)) + break; + c = v16; + } + if (c >= n_symbols) + fatal_error("Invalid symbol: %d\n", c); + block_buf[i] = c; + } +} + +static void write_block(FILE *f, DataSymbol *block_buf, int len, int symb_shift) +{ + int i; + for(i = 0; i < len; i++) { + if (symb_shift == 0) + fputc(block_buf[i], f); + else + fput_be16(f, block_buf[i]); + } +} + +#define ARITH_BUF_LEN 65536 + +static ssize_t arith_read_buf(void *opaque, uint8_t *buf, size_t buf_size) +{ + FILE *f = opaque; + return fread(buf, 1, buf_size, f); +} + +static void arith_write_buf(void *opaque, const uint8_t *buf, size_t buf_size) +{ + FILE *f = opaque; + fwrite(buf, 1, buf_size, f); +} + +static int64_t get_file_size(FILE *f) +{ + int64_t last_pos, file_size; + last_pos = ftello(f); + fseek(f, 0, SEEK_END); + file_size = ftello(f); + fseek(f, last_pos, SEEK_SET); + return file_size; +} + +static int64_t get_file_size2(const char *filename) +{ + FILE *f; + int64_t file_size; + f = fopen(filename, "rb"); + if (!f) + return -1; + file_size = get_file_size(f); + fclose(f); + return file_size; +} + +/* write a small compressed file using zlib */ +static void write_compressed_file(FILE *fo, const char *filename) +{ + FILE *f; + int file_size, out_buf_size; + uint8_t *buf, *out_buf; + unsigned long csize; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + file_size = get_file_size(f); + if (file_size < 0) + goto read_error; + buf = malloc(file_size); + if (fread(buf, 1, file_size, f) != file_size) { + read_error: + fatal_error("%s: read error", filename); + } + fclose(f); + + out_buf_size = compressBound(file_size); + out_buf = malloc(out_buf_size); + csize = out_buf_size; + if (compress2(out_buf, &csize, buf, file_size, + Z_BEST_COMPRESSION) != Z_OK) { + fatal_error("zlib compress2"); + } + + if (!quiet_flag) { + printf("Compressed dictionary size=%d bytes\n", (int)csize); + } + + fput_be32(fo, file_size); + fput_be32(fo, csize); + + if (fwrite(out_buf, 1, csize, fo) != csize) { + fatal_error("write_compressed_file: write_error"); + } + + free(buf); + free(out_buf); +} + +/* read a small compressed file using zlib */ +static void read_compressed_file(FILE *f, const char *filename) +{ + uint32_t file_size, csize; + uint8_t *buf, *out_buf; + unsigned long dsize; + FILE *fo; + + if (fget_be32(f, &file_size)) + goto read_error; + if (fget_be32(f, &csize)) + goto read_error; + + buf = malloc(csize); + out_buf = malloc(file_size); + + if (fread(buf, 1, csize, f) != csize) { + read_error: + fatal_error("read_compressed_file: read_error"); + } + + dsize = file_size; + if (uncompress(out_buf, &dsize, buf, csize) != Z_OK) { + fatal_error("zlib uncompress"); + } + if (dsize != file_size) { + fatal_error("invalid zlib decoded size"); + } + + fo = fopen(filename, "wb"); + if (!fo) { + fatal_error("%s: write error", filename); + } + fwrite(out_buf, 1, file_size, fo); + fclose(fo); + + free(out_buf); + free(buf); +} + +void encode_file(const char *in_filename, const char *out_filename, + const char *debug_dir, EncodeParams *ep, int argc, const char **argv) +{ + FILE *f, *fo; + NNCPModelParams *p; + NNCPModelState *pred; + LogState st_s, *st = &st_s; + DataSymbol *block_buf; + int symb_shift, block_len, block_buf_size; + int64_t n_output_bytes, file_length, file_pos, block_len1; + int64_t org_file_length; + char out_filename_buf[1024], dict_filename[1024], tmp_filename[1024]; + PutBitState pb; + uint8_t *arith_buf; + + p = &ep->model_params; + + log_init(st, debug_dir, "nncp-log"); + + if (st->log_file) { + int i; + fprintf(st->log_file, "cmd_line='"); + for(i = 0; i < argc; i++) { + if (i != 0) + fprintf(st->log_file, " "); + fprintf(st->log_file, "%s", argv[i]); + } + fprintf(st->log_file, "'\n"); + } + + if (plot_filename || st->debug_output) { + char filename[1024]; + if (plot_filename) { + snprintf(filename, sizeof(filename), "%s", plot_filename); + } else { + snprintf(filename, sizeof(filename), "%s/plot.txt", st->debug_dir); + } + st->plot_file = fopen(filename, "wb"); + if (!st->plot_file) { + fatal_error("could not create '%s'", filename); + } + } + + if (!out_filename) { + snprintf(out_filename_buf, sizeof(out_filename_buf), "%s/%s", + st->debug_dir, "out.bin"); + out_filename = out_filename_buf; + } + + org_file_length = -1; + if (ep->preprocess_flag) { + int n_words; + int64_t pp_time; + + snprintf(tmp_filename, sizeof(tmp_filename), + "%s.pp", out_filename); + if (ep->dict_filename) { + /* force dictionary and use preprocessed input */ + snprintf(dict_filename, sizeof(dict_filename), "%s", + ep->dict_filename); + } else { + snprintf(dict_filename, sizeof(dict_filename), + "%s.voc", out_filename); + + org_file_length = get_file_size2(in_filename); + + pp_time = get_time_ms(); + n_words = word_encode(in_filename, tmp_filename, dict_filename, + ep->n_words, ep->min_word_freq, + NULL, FALSE, !quiet_flag); + if (!quiet_flag) { + log_printf(st, "Preprocessing time=%0.3f s\n", + (get_time_ms() - pp_time) / 1000.0); + } + /* multiple of 8 to accelerate computations */ + p->n_symbols = (n_words + 7) & ~7; + in_filename = tmp_filename; + } + symb_shift = 1; + } else { + if (p->n_symbols <= 256) + symb_shift = 0; + else + symb_shift = 1; + } + + f = fopen(in_filename, "rb"); + if (!f) { + perror(in_filename); + exit(1); + } + + fo = fopen(out_filename, "wb"); + if (!fo) { + perror(out_filename); + exit(1); + } + + nncp_write_file_header(fo, p); + + /* preprocessing info */ + if (ep->preprocess_flag) { + fput_u8(fo, 1); + write_compressed_file(fo, dict_filename); + } else { + fput_u8(fo, 0); + } + + file_length = get_file_size(f); + if (file_length < 0) + fatal_error("could not get input file size"); + + file_length >>= symb_shift; + if (ep->max_size >= 0 && file_length > ep->max_size) + file_length = ep->max_size; + + fput_be32(fo, file_length); + + arith_buf = nc_malloc(ARITH_BUF_LEN); + put_bit_init(&pb, arith_buf, ARITH_BUF_LEN, arith_write_buf, fo); + + p->seq_eval = !use_encode_only; + + pred = nncp_init(p); + if (!quiet_flag) { + nncp_dump_params(stdout, pred, p); + } + if (st->log_file) { + nncp_dump_params(st->log_file, pred, p); + fflush(st->log_file); + } + +#if 0 + if (load_coefs_filename) + nc_load_coefs(&pred->param_list, load_coefs_filename); +#endif + + + block_buf = NULL; + block_buf_size = 0; + file_pos = 0; + st->last_time = get_time_ms(); /* exclude the init time */ + for(;;) { + block_len1 = file_length - file_pos; + if (block_len1 == 0) + break; + block_len = lrintf(get_interp_param(&p->block_len, file_pos)); + block_len = max_int(block_len / (p->seg_len * p->batch_size), 1) * + (p->seg_len * p->batch_size); + if (block_len > block_len1) + block_len = block_len1; + + if (block_len > block_buf_size) { + nc_free(block_buf); + block_buf = nc_malloc(block_len * sizeof(block_buf[0])); + block_buf_size = block_len; + } + + read_block(f, block_buf, block_len, symb_shift, p->n_symbols); + + process_block(pred, fo, &pb, NULL, block_buf, block_len, + st, FALSE); + + file_pos += block_len; + if (file_pos >= file_length) + break; + + retrain_block(pred, block_buf, block_len, file_pos, st); + } + nc_free(block_buf); + + put_bit_flush(&pb); + nc_free(arith_buf); + n_output_bytes = ftell(fo); + fclose(fo); + fclose(f); + + if (ep->preprocess_flag && !ep->dict_filename) { + unlink(dict_filename); + unlink(tmp_filename); + } + + log_dump(st, st->n_input_bytes, n_output_bytes, + pred->train_step, st->last_lr, TRUE); + if (!quiet_flag) { + int64_t ti; + ti = get_time_ms() - st->start_time; + log_printf(st, "Total time=%0.3f s", ti / 1000.0); + if (org_file_length > 0) { + log_printf(st, " (%0.2f kB/s)", + (double)org_file_length / (double)ti); + } + log_printf(st, "\n"); + } + log_end(st); + + nncp_end(pred); + + nc_prof_dump(); +} + +void decode_file(const char *in_filename, const char *out_filename, + const char *debug_dir) +{ + FILE *f, *fo; + NNCPModelParams p_s, *p = &p_s; + NNCPModelState *pred; + LogState st_s, *st = &st_s; + DataSymbol *block_buf; + int symb_shift, block_len, block_buf_size; + int64_t n_output_bytes, file_length, file_pos, block_len1; + char out_filename_buf[1024], dict_filename[1024], tmp_filename[1024]; + GetBitState gb; + uint8_t *arith_buf; + BOOL preprocess_flag; + uint32_t v32; + uint8_t v8; + + log_init(st, debug_dir, "nncp-log"); + + if (!out_filename) { + snprintf(out_filename_buf, sizeof(out_filename_buf), "%s/%s", + st->debug_dir, "out.bin"); + out_filename = out_filename_buf; + } + + f = fopen(in_filename, "rb"); + if (!f) { + perror(in_filename); + exit(1); + } + + if (nncp_read_file_header(f, p) < 0) { + fatal_error("invalid file header"); + } + + if (p->use_cuda != use_cuda) { + if (p->use_cuda) { + fprintf(stderr, "Warning: enabling CUDA as the file was encoded with it\n"); + } else { + fprintf(stderr, "Warning: disabling CUDA as the file was encoded without it\n"); + } + } + p->use_cuda = use_cuda; + + if (fget_u8(f, &v8) < 0) { + fatal_error("read error"); + } + preprocess_flag = v8 & 1; + + if (preprocess_flag) { + snprintf(tmp_filename, sizeof(tmp_filename), + "%s.pp", out_filename); + snprintf(dict_filename, sizeof(dict_filename), + "%s.voc", out_filename); + + read_compressed_file(f, dict_filename); + + fo = fopen(tmp_filename, "wb"); + if (!fo) { + perror(tmp_filename); + exit(1); + } + symb_shift = 1; + } else { + fo = fopen(out_filename, "wb"); + if (!fo) { + perror(out_filename); + exit(1); + } + + if (p->n_symbols <= 256) + symb_shift = 0; + else + symb_shift = 1; + } + + if (fget_be32(f, &v32) < 0) { + fprintf(stderr, "Read error\n"); + exit(1); + } + file_length = v32; + + arith_buf = nc_malloc(ARITH_BUF_LEN); + get_bit_init(&gb, arith_buf, ARITH_BUF_LEN, arith_read_buf, f); + + p->seq_eval = TRUE; + + pred = nncp_init(p); + if (!quiet_flag) { + nncp_dump_params(stdout, pred, p); + } + if (st->log_file) { + nncp_dump_params(st->log_file, pred, p); + fflush(st->log_file); + } + +#if 0 + if (load_coefs_filename) + nc_load_coefs(&pred->param_list, load_coefs_filename); +#endif + + block_buf = NULL; + block_buf_size = 0; + file_pos = 0; + for(;;) { + block_len1 = file_length - file_pos; + if (block_len1 == 0) + break; + block_len = lrintf(get_interp_param(&p->block_len, file_pos)); + block_len = max_int(block_len / (p->seg_len * p->batch_size), 1) * + (p->seg_len * p->batch_size); + if (block_len > block_len1) + block_len = block_len1; + + if (block_len > block_buf_size) { + nc_free(block_buf); + block_buf = nc_malloc(block_len * sizeof(block_buf[0])); + block_buf_size = block_len; + } + + process_block(pred, fo, NULL, &gb, block_buf, block_len, + st, TRUE); + + write_block(fo, block_buf, block_len, symb_shift); + fflush(fo); + + file_pos += block_len; + if (file_pos >= file_length) + break; + + retrain_block(pred, block_buf, block_len, file_pos, st); + } + nc_free(block_buf); + + n_output_bytes = ftell(f); + + fclose(fo); + fclose(f); + nc_free(arith_buf); + + log_dump(st, st->n_input_bytes, n_output_bytes, + pred->train_step, st->last_lr, TRUE); + + nncp_end(pred); + + if (preprocess_flag) { + word_decode(tmp_filename, out_filename, dict_filename); + + unlink(dict_filename); + unlink(tmp_filename); + } + + if (!quiet_flag) { + int64_t ti, org_file_length; + + ti = get_time_ms() - st->start_time; + + log_printf(st, "Total time=%0.3f s", ti / 1000.0); + if (preprocess_flag) { + org_file_length = get_file_size2(out_filename); + log_printf(st, " (%0.2f kB/s)", + (double)org_file_length / (double)ti); + } + log_printf(st, "\n"); + } + + log_end(st); + + nc_prof_dump(); +} + + +static const CMDOptDesc nncp_options[] = { + { "h,help", 0, "show the help" }, + { "d", CMD_HAS_ARG, "set the debug directory", "dir" }, + { "q", 0, "enable quiet mode" }, + { "T", CMD_HAS_ARG, "number of CPU threads" }, + { "p,profile", CMD_HAS_ARG, "set the encoding profile: default, enwik8, enwik9, lstm, lstm_fast." }, + { "max_size", CMD_HAS_ARG, "truncate the input to N symbols", "N" }, + { "plot", CMD_HAS_ARG, "set the plot filename" }, + { "load_coefs", CMD_HAS_ARG, "load the model coefficients from file" }, + { "dump_interval", CMD_HAS_ARG, "dump interval of statistics" }, + { "cuda", 0, "enable CUDA support" }, + { "bf16", CMD_HAS_ARG, "enable bf16 processing", "[0|1]" }, + { "encode_only", 0, "faster encode only mode (output cannot be decompressed)" }, + + { "batch_size", CMD_HAS_ARG, "batch size" }, + { "seed", CMD_HAS_ARG, "random number seed" }, + { "block_len", CMD_HAS_ARG, "set the encoding block length" }, + { "train_len", CMD_HAS_ARG, "training segment length" }, + { "lr", CMD_HAS_ARG, "learning rate", "lr0[,step0,lr1]..." }, + { "retrain_period", CMD_HAS_ARG, "retrain period in symbols, 0 to disable retrain" }, + { "retrain_len", CMD_HAS_ARG, "retrain length" }, + { "retrain_lr", CMD_HAS_ARG, "retrain learning rate" }, + { "n_symb", CMD_HAS_ARG, "vocabulary size (2 to 65535)" }, + + { "preprocess", CMD_HAS_ARG, "enable text preprocessing", "n_words,min_word_freq" }, + { "dict", CMD_HAS_ARG, "set the dictionary filename (pc, pd, and c commands)", "filename" }, + { NULL }, +}; + +static void help(void) +{ + int i; + const NNCPModelClass *mc; + + printf("NNCP version " CONFIG_VERSION", Copyright (c) 2018-2021 Fabrice Bellard\n" + "Lossless data compression with Neural Networks\n" + "usage: nncp [options] cmd args...\n" + "\n" + "Commands:\n" + "c infile outfile compress 'infile' to 'outfile'\n" + "d infile outfile decompres 'infile' to 'outfile'\n" + "pc infile outfile preprocessor-only encoding\n" + "pd infile outfile preprocessor-only decoding\n" + "\n" + "General options:\n"); + + cmdopt_show_desc(nncp_options); + + for(i = 0; i < countof(nncp_models); i++) { + mc = nncp_models[i]; + printf("\nOptions for the %s model:\n", mc->name); + cmdopt_show_desc(mc->model_options); + } + + exit(1); +} + +int main(int argc, const char **argv) +{ + int optind, i; + const char *debug_dir, *cmd, *r; + CMDOption *co; + + debug_dir = NULL; + + co = cmdopt_init("nncp"); + cmdopt_add_desc(co, nncp_options); + for(i = 0; i < countof(nncp_models); i++) + cmdopt_add_desc(co, nncp_models[i]->model_options); + optind = cmdopt_parse(co, argc, argv); + + if (optind >= argc) + help(); + + cmd = argv[optind]; + + if (cmdopt_has(co, "help")) + help(); + + plot_filename = cmdopt_get(co, "plot"); + + load_coefs_filename = cmdopt_get(co, "load_coefs"); + + stats_dump_interval = cmdopt_get_int(co, "dump_interval", + stats_dump_interval); + + use_cuda = cmdopt_has(co, "cuda"); + + use_encode_only = cmdopt_has(co, "encode_only"); + + quiet_flag = cmdopt_has(co, "q"); + + nb_threads = cmdopt_get_int(co, "T", nb_threads); + + debug_dir = cmdopt_get(co, "d"); + + + if (!strcmp(cmd, "c")) { + const char *out_filename; + EncodeParams ep_s, *ep = &ep_s; + NNCPModelParams *p = &ep->model_params; + + memset(ep, 0, sizeof(*ep)); + + if (optind + 1 >= argc) + help(); + if ((optind + 2) < argc) { + out_filename = argv[optind + 2]; + } else { + out_filename = NULL; + if (!debug_dir) + help(); + } + + r = cmdopt_get(co, "profile"); + if (!r) + r = "default"; + + nncp_init_params(p, r); + + p->use_cuda = use_cuda; + + ep->max_size = cmdopt_get_int(co, "max_size", -1); + + r = cmdopt_get(co, "preprocess"); + if (r) { + ep->preprocess_flag = TRUE; + ep->n_words = strtoul(r, (char **)&r, 0); + if (*r != ',') + cmd_error("comma expected"); + r++; + ep->min_word_freq = strtoul(r, (char **)&r, 0); + if (*r != '\0') + cmd_error("unexpected chars"); + } + + r = cmdopt_get(co, "dict"); + if (r) { + ep->preprocess_flag = TRUE; + ep->dict_filename = r; + } + + + r = cmdopt_get(co, "lr"); + if (r) + parse_interp_param(&p->lr, r); + + p->retrain_period = cmdopt_get_int(co, "retrain_period", + p->retrain_period); + p->retrain_len = cmdopt_get_int(co, "retrain_len", + p->retrain_len); + + r = cmdopt_get(co, "retrain_lr"); + if (r) { + parse_interp_param(&p->retrain_lr, r); + p->has_retrain_lr = TRUE; + } + + p->batch_size = cmdopt_get_int(co, "batch_size", + p->batch_size); + p->seg_len = cmdopt_get_int(co, "train_len", p->seg_len); + p->seed = cmdopt_get_int(co, "seed", p->seed); + p->n_symbols= cmdopt_get_int(co, "n_symb", p->n_symbols); + if (p->n_symbols < 2 || p->n_symbols > 65536) + cmd_error("invalid number of symbols"); + + r = cmdopt_get(co, "block_len"); + if (r) { + parse_interp_param(&p->block_len, r); + } + + p->use_bf16 = cmdopt_get_int(co, "bf16", p->use_bf16); + + ep->model_params.model_class->model_parse_options(p, co); + + encode_file(argv[optind + 1], out_filename, debug_dir, ep, argc, argv); + } else if (!strcmp(cmd, "d")) { + if (optind + 2 >= argc) + help(); + decode_file(argv[optind + 1], argv[optind + 2], debug_dir); + } else if (!strcmp(cmd, "pc")) { + const char *in_filename; + const char *out_filename; + const char *dict_filename; + int n_words, min_word_freq; + + if (optind + 2 >= argc) + help(); + + r = cmdopt_get(co, "preprocess"); + if (!r) + cmd_error("--preprocess option missing"); + + n_words = strtoul(r, (char **)&r, 0); + if (*r != ',') + cmd_error("comma expected"); + r++; + min_word_freq = strtoul(r, (char **)&r, 0); + if (*r != '\0') + cmd_error("unexpected chars"); + + dict_filename = cmdopt_get(co, "dict"); + if (!dict_filename) + cmd_error("--dict option missing"); + + in_filename = argv[optind + 1]; + out_filename = argv[optind + 2]; + word_encode(in_filename, out_filename, dict_filename, n_words, + min_word_freq, NULL, FALSE, !quiet_flag); + } else if (!strcmp(cmd, "pd")) { + const char *in_filename; + const char *out_filename; + const char *dict_filename; + + if (optind + 2 >= argc) + help(); + dict_filename = cmdopt_get(co, "dict"); + if (!dict_filename) + cmd_error("--dict option missing"); + in_filename = argv[optind + 1]; + out_filename = argv[optind + 2]; + word_decode(in_filename, out_filename, dict_filename); + } else { + help(); + } + cmdopt_free(co); + return 0; +} diff --git a/deps/nncp/preprocess.c b/deps/nncp/preprocess.c new file mode 100644 index 0000000..3488bd4 --- /dev/null +++ b/deps/nncp/preprocess.c @@ -0,0 +1,1401 @@ +/* + * NNCP preprocessor + * + * Copyright (c) 2018-2021 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "cp_utils.h" + +/****************************************************************/ + +typedef uint16_t DataSymbol; + +typedef struct Word { + uint32_t next; /* -1 = end */ + uint32_t freq; + int64_t score; + uint32_t len; + DataSymbol buf[2]; +} Word; + +typedef struct { + Word *words; + size_t word_count; + size_t word_size; + uint32_t *hash_table; + int hash_size; + int hash_bits; +} WordList; + +static uint32_t hash_calc(const DataSymbol *buf, int len, int n_bits) +{ + uint32_t h; + int i; + + h = 1; + for(i = 0; i < len; i++) { + h = h * 314159 + buf[i]; + } + return h & ((1 << n_bits) - 1); +} + +static void hash_resize(WordList *s, int hash_bits) +{ + int i, h; + Word *p; + + s->hash_bits = hash_bits; + s->hash_size = 1 << hash_bits; + free(s->hash_table); + s->hash_table = malloc(sizeof(s->hash_table[0]) * s->hash_size); + for(i = 0; i < s->hash_size; i++) + s->hash_table[i] = -1; + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + h = hash_calc(p->buf, p->len, s->hash_bits); + p->next = s->hash_table[h]; + s->hash_table[h] = i; + } +} + +static WordList *word_list_init(void) +{ + WordList *s; + + s = mallocz(sizeof(WordList)); + s->word_count = 0; + s->word_size = 0; + hash_resize(s, 12); + return s; +} + +static void word_list_end(WordList *s) +{ + free(s->words); + free(s->hash_table); + free(s); +} + +int64_t hash_lookup_count; +int64_t hash_it_count; + +/* the hash size contains HASH_SIZE_FACTOR times more entries */ +#define HASH_SIZE_FACTOR 2 + +static Word *word_find_add(WordList *s, const DataSymbol *buf, int len, int add) +{ + uint32_t h, idx; + Word *p; + int i; + + assert(len >= 1); + h = hash_calc(buf, len, s->hash_bits); + idx = s->hash_table[h]; + hash_lookup_count++; + while (idx != -1) { + hash_it_count++; + p = &s->words[idx]; + if (p->len == len && !memcmp(p->buf, buf, len * sizeof(buf[0]))) + return p; + idx = p->next; + } + + if (!add) + return NULL; + + if (s->word_count >= s->word_size) { + size_t new_size = s->word_size + s->word_size / 2; + if (new_size < 32) + new_size = 32; + if (s->word_count + 1 > new_size) + new_size = s->word_count + 1; + s->words = realloc(s->words, new_size * sizeof(s->words[0])); + s->word_size = new_size; + + } + /* resize the hash table when needed */ + if ((s->word_count * HASH_SIZE_FACTOR) > s->hash_size) { + int hash_bits = s->hash_bits; + while ((s->word_count * HASH_SIZE_FACTOR) > (1 << hash_bits)) + hash_bits++; + hash_resize(s, hash_bits); + + /* recompute the hash with the new hash table size */ + h = hash_calc(buf, len, s->hash_bits); + } + + idx = s->word_count++; + p = &s->words[idx]; + p->freq = 0; + p->len = len; + for(i = 0; i < len; i++) + p->buf[i] = buf[i]; + p->next = s->hash_table[h]; + s->hash_table[h] = idx; + return p; +} + +/****************************************************************/ + +typedef struct { + uint32_t len; + char data[0]; +} StringEntry; + +typedef struct { + StringEntry **tab; + size_t size; + size_t count; +} StringTable; + +StringTable *string_table_init(void) +{ + StringTable *s; + s = mallocz(sizeof(*s)); + return s; +} + +void string_table_add(StringTable *s, const char *data, uint32_t data_len) +{ + size_t new_size; + StringEntry **new_tab, *se; + + if ((s->count + 1) > s->size) { + new_size = s->size * 3 / 2; + if (new_size < s->count + 1) + new_size = s->count + 1; + new_tab = realloc(s->tab, sizeof(s->tab[0]) * new_size); + s->tab = new_tab; + s->size = new_size; + } + se = malloc(sizeof(StringEntry) + data_len + 1); + se->len = data_len; + memcpy(se->data, data, data_len); + se->data[data_len] = '\0'; + s->tab[s->count++] = se; +} + +void string_table_end(StringTable *s) +{ + size_t i; + for(i = 0; i < s->count; i++) { + free(s->tab[i]); + } + free(s->tab); + free(s); +} + +/****************************************************************/ + +//#define USE_CUT /* disable multiple word combining */ + +#define FRAC_BITS 10 +#define FRAC_ONE (1 << FRAC_BITS) + +#define MAX_WORDS_PER_ITER 100 +#define SUBST_COST (int)(7.0 * FRAC_ONE + 0.5) /* in bits * FRAC_OnE */ +#define TOT_FREQ_RED_BITS ((int)(1.3 * FRAC_ONE + 0.5)) /* log2(old_tot_freq/new_tot_freq) */ + +#define CH_NO_SPACE 1 +#define CH_TO_UPPER 2 +#define CH_FIRST_UPPER 3 +#define CH_ESCAPE 4 + +/* separate words */ +#define CH_CUT 0xffff + +/* number of reserved symbols */ +#define NS 256 + +void dump_word(FILE *f, WordList *s, uint32_t code, BOOL text_output) +{ + Word *p; + + if (code < NS) { + if (text_output) { + switch(code) { + case '\n': + fprintf(f, "\\n"); + break; + case '\\': + fprintf(f, "\\%c", code); + break; + case CH_TO_UPPER: + fprintf(f, "\\u"); + break; + case CH_FIRST_UPPER: + fprintf(f, "\\c"); + break; + case CH_NO_SPACE: + fprintf(f, "\\S"); + break; + default: + fprintf(f, "%c", code); + break; + } + } else { + switch(code) { + case '\n': + fprintf(f, "\\n"); + break; + case '\\': + fprintf(f, "\\%c", code); + break; + default: + fprintf(f, "%c", code); + break; + } + } + } else { + code -= NS; + assert(code < s->word_count); + p = &s->words[code]; + dump_word(f, s, p->buf[0], text_output); + dump_word(f, s, p->buf[1], text_output); + } +} + +int get_word_bytes(uint8_t *buf, int buf_size, WordList *s, uint32_t code) +{ + Word *p; + int n; + + if (code < NS) { + if (buf_size >= 1) { + buf[0] = code; + n = 1; + } else { + n = 0; /* not enough space */ + } + } else { + code -= NS; + assert(code < s->word_count); + p = &s->words[code]; + n = get_word_bytes(buf, buf_size, s, p->buf[0]); + n += get_word_bytes(buf + n, buf_size - n, s, p->buf[1]); + } + return n; +} + + +typedef struct { + WordList *s; + uint32_t *char_freq; +} SortState; + +static int word_freq_cmp2(const void *a1, const void *a2, void *arg) +{ + SortState *ss = arg; + uint32_t c1 = *(DataSymbol *)a1; + uint32_t c2 = *(DataSymbol *)a2; + uint32_t freq1, freq2; + + if (c1 < NS) + freq1 = ss->char_freq[c1]; + else + freq1 = ss->s->words[c1 - NS].freq; + + if (c2 < NS) + freq2 = ss->char_freq[c2]; + else + freq2 = ss->s->words[c2 - NS].freq; + + if (freq1 < freq2) + return 1; + else if (freq1 == freq2) + return 0; + else + return -1; +} + +/* XXX: could remove */ +#define SORT_MAX_LEN 512 + +static int word_lex_cmp(const void *a1, const void *a2, void *arg) +{ + SortState *ss = arg; + uint32_t c1 = *(DataSymbol *)a1; + uint32_t c2 = *(DataSymbol *)a2; + uint8_t buf1[SORT_MAX_LEN]; + uint8_t buf2[SORT_MAX_LEN]; + int res, n1, n2; + + n1 = get_word_bytes(buf1, sizeof(buf1), ss->s, c1); + n2 = get_word_bytes(buf2, sizeof(buf2), ss->s, c2); + res = memcmp(buf1, buf2, min_int(n1, n2)); + if (res != 0) + return res; + if (n1 < n2) + return -1; + else if (n1 == n2) + return 0; + else + return 1; +} + + +#if defined(_WIN32) || defined(__ANDROID__) + +static void *rqsort_arg; +static int (*rqsort_cmp)(const void *, const void *, void *); + +static int rqsort_cmp2(const void *p1, const void *p2) +{ + return rqsort_cmp(p1, p2, rqsort_arg); +} + +/* not reentrant, but not needed with emscripten */ +void rqsort(void *base, size_t nmemb, size_t size, + int (*cmp)(const void *, const void *, void *), + void *arg) +{ + rqsort_arg = arg; + rqsort_cmp = cmp; + qsort(base, nmemb, size, rqsort_cmp2); +} + +#else + +void rqsort(void *base, size_t n, size_t elem_size, + int (*cmp)(const void *, const void *, void *), + void *arg) +{ + qsort_r(base, n, elem_size, cmp, arg); +} + +#endif /* !_WIN32 */ + +int sort_words(WordList *s, uint32_t **ptab, uint32_t *char_freq, + BOOL sort_by_freq) +{ + uint32_t *tab, n_words; + int i, j; + SortState ss_s, *ss = &ss_s; + + /* sort the words */ + n_words = NS + s->word_count; + tab = malloc(sizeof(tab[0]) * n_words); + j = 0; + for(i = 0; i < n_words; i++) { + if (i >= NS && s->words[i - NS].freq == 0) + continue; + tab[j++] = i; + } + ss->s = s; + ss->char_freq = char_freq; + if (sort_by_freq) { + rqsort(tab, j, sizeof(tab[0]), word_freq_cmp2, ss); + } else { + /* lexicographic sort for the words indexes >= NS */ + rqsort(tab + NS, j - NS, sizeof(tab[0]), word_lex_cmp, ss); + } + *ptab = tab; + return j; +} + +void save_words_debug(WordList *s, const char *filename, + const uint32_t *char_freq, uint32_t tot_freq, + const uint32_t *tab, int word_count) +{ + FILE *f; + int i; + uint32_t c, sum, freq; + Word *p; + + f = fopen(filename, "wb"); + if (!f) { + perror(filename); + exit(1); + } + + fprintf(f, "%7s %5s %s\n", + "FREQ", "CUM%", "WORD"); + sum = 0; + for(i = 0; i < word_count; i++) { + c = tab[i]; + if (c < NS) { + freq = char_freq[c]; + } else { + p = &s->words[c - NS]; + freq = p->freq; + } + sum += freq; + fprintf(f, "%7u %5.1f '", freq, (double)sum / tot_freq * 100); + dump_word(f, s, c, TRUE); + fprintf(f, "'\n"); + } + + fclose(f); +} + +void save_words(WordList *s, const char *filename, + const uint32_t *tab, int word_count) +{ + FILE *f; + int i; + + f = fopen(filename, "wb"); + if (!f) { + perror(filename); + exit(1); + } + + for(i = 0; i < word_count; i++) { + dump_word(f, s, tab[i], FALSE); + fprintf(f, "\n"); + } + + fclose(f); +} + +void dump_word_bin(FILE *f, WordList *s, uint32_t *convert_table, + uint32_t c) +{ + Word *p; + + if (c < NS) { + fput_be16(f, convert_table[c]); + } else { + c -= NS; + assert(c < s->word_count); + p = &s->words[c]; + if (p->freq == 0) { + dump_word_bin(f, s, convert_table, p->buf[0]); + dump_word_bin(f, s, convert_table, p->buf[1]); + } else { + fput_be16(f, convert_table[c + NS]); + } + } +} + +void save_output(const DataSymbol *buf, size_t buf_len, WordList *s, + const char *out_filename, const uint32_t *tab, int word_count) +{ + FILE *fo; + uint32_t *convert_table; + size_t i; + + fo = fopen(out_filename, "wb"); + if (!fo) { + perror(out_filename); + exit(1); + } + + /* build the convertion table */ + convert_table = malloc(sizeof(convert_table[0]) * (s->word_count + NS)); + for(i = 0; i < s->word_count + NS; i++) + convert_table[i] = -1; + for(i = 0; i < word_count; i++) { + convert_table[tab[i]] = i; + } + + for(i = 0; i < buf_len; i++) { + if (buf[i] != CH_CUT) { + dump_word_bin(fo, s, convert_table, buf[i]); + } + } + free(convert_table); + + fclose(fo); +} + +static int word_score_cmp(const void *a1, const void *a2) +{ + const Word *p1 = a1; + const Word *p2 = a2; + + if (p1->score > p2->score) + return -1; + else if (p1->score == p2->score) + return 0; + else + return 1; +} + +static const uint16_t log2_table[FRAC_ONE] = { + 0x000, 0x001, 0x003, 0x004, 0x006, 0x007, 0x009, 0x00a, + 0x00b, 0x00d, 0x00e, 0x010, 0x011, 0x013, 0x014, 0x015, + 0x017, 0x018, 0x01a, 0x01b, 0x01d, 0x01e, 0x01f, 0x021, + 0x022, 0x024, 0x025, 0x026, 0x028, 0x029, 0x02b, 0x02c, + 0x02d, 0x02f, 0x030, 0x032, 0x033, 0x034, 0x036, 0x037, + 0x039, 0x03a, 0x03b, 0x03d, 0x03e, 0x040, 0x041, 0x042, + 0x044, 0x045, 0x046, 0x048, 0x049, 0x04b, 0x04c, 0x04d, + 0x04f, 0x050, 0x051, 0x053, 0x054, 0x055, 0x057, 0x058, + 0x05a, 0x05b, 0x05c, 0x05e, 0x05f, 0x060, 0x062, 0x063, + 0x064, 0x066, 0x067, 0x068, 0x06a, 0x06b, 0x06c, 0x06e, + 0x06f, 0x070, 0x072, 0x073, 0x074, 0x076, 0x077, 0x078, + 0x07a, 0x07b, 0x07c, 0x07e, 0x07f, 0x080, 0x082, 0x083, + 0x084, 0x086, 0x087, 0x088, 0x08a, 0x08b, 0x08c, 0x08e, + 0x08f, 0x090, 0x092, 0x093, 0x094, 0x095, 0x097, 0x098, + 0x099, 0x09b, 0x09c, 0x09d, 0x09f, 0x0a0, 0x0a1, 0x0a2, + 0x0a4, 0x0a5, 0x0a6, 0x0a8, 0x0a9, 0x0aa, 0x0ab, 0x0ad, + 0x0ae, 0x0af, 0x0b1, 0x0b2, 0x0b3, 0x0b4, 0x0b6, 0x0b7, + 0x0b8, 0x0b9, 0x0bb, 0x0bc, 0x0bd, 0x0bf, 0x0c0, 0x0c1, + 0x0c2, 0x0c4, 0x0c5, 0x0c6, 0x0c7, 0x0c9, 0x0ca, 0x0cb, + 0x0cc, 0x0ce, 0x0cf, 0x0d0, 0x0d1, 0x0d3, 0x0d4, 0x0d5, + 0x0d6, 0x0d8, 0x0d9, 0x0da, 0x0db, 0x0dd, 0x0de, 0x0df, + 0x0e0, 0x0e2, 0x0e3, 0x0e4, 0x0e5, 0x0e7, 0x0e8, 0x0e9, + 0x0ea, 0x0ec, 0x0ed, 0x0ee, 0x0ef, 0x0f0, 0x0f2, 0x0f3, + 0x0f4, 0x0f5, 0x0f7, 0x0f8, 0x0f9, 0x0fa, 0x0fb, 0x0fd, + 0x0fe, 0x0ff, 0x100, 0x102, 0x103, 0x104, 0x105, 0x106, + 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10e, 0x10f, 0x110, + 0x111, 0x112, 0x114, 0x115, 0x116, 0x117, 0x118, 0x11a, + 0x11b, 0x11c, 0x11d, 0x11e, 0x120, 0x121, 0x122, 0x123, + 0x124, 0x125, 0x127, 0x128, 0x129, 0x12a, 0x12b, 0x12d, + 0x12e, 0x12f, 0x130, 0x131, 0x132, 0x134, 0x135, 0x136, + 0x137, 0x138, 0x139, 0x13b, 0x13c, 0x13d, 0x13e, 0x13f, + 0x140, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, + 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x151, 0x152, + 0x153, 0x154, 0x155, 0x156, 0x157, 0x159, 0x15a, 0x15b, + 0x15c, 0x15d, 0x15e, 0x15f, 0x161, 0x162, 0x163, 0x164, + 0x165, 0x166, 0x167, 0x168, 0x16a, 0x16b, 0x16c, 0x16d, + 0x16e, 0x16f, 0x170, 0x172, 0x173, 0x174, 0x175, 0x176, + 0x177, 0x178, 0x179, 0x17a, 0x17c, 0x17d, 0x17e, 0x17f, + 0x180, 0x181, 0x182, 0x183, 0x184, 0x186, 0x187, 0x188, + 0x189, 0x18a, 0x18b, 0x18c, 0x18d, 0x18e, 0x190, 0x191, + 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, + 0x19b, 0x19c, 0x19d, 0x19e, 0x19f, 0x1a0, 0x1a1, 0x1a2, + 0x1a3, 0x1a4, 0x1a5, 0x1a6, 0x1a8, 0x1a9, 0x1aa, 0x1ab, + 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b1, 0x1b2, 0x1b3, + 0x1b4, 0x1b6, 0x1b7, 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, + 0x1bd, 0x1be, 0x1bf, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c5, + 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, + 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, 0x1d3, 0x1d4, 0x1d5, + 0x1d6, 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, + 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e6, + 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ee, + 0x1ef, 0x1f0, 0x1f1, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f7, + 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, + 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, + 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f, + 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, + 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, + 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, + 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, + 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, + 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, + 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, + 0x248, 0x249, 0x249, 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, + 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, + 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, + 0x25f, 0x260, 0x261, 0x262, 0x262, 0x263, 0x264, 0x265, + 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26b, 0x26c, 0x26d, + 0x26e, 0x26f, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, + 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27c, + 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x283, 0x284, + 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28a, 0x28b, + 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x291, 0x291, 0x292, + 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29a, + 0x29b, 0x29c, 0x29d, 0x29d, 0x29e, 0x29f, 0x2a0, 0x2a1, + 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a7, 0x2a8, + 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, 0x2b0, + 0x2b1, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, + 0x2b8, 0x2b9, 0x2ba, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, + 0x2bf, 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c3, 0x2c4, 0x2c5, + 0x2c6, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cb, 0x2cc, + 0x2cd, 0x2ce, 0x2cf, 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d3, + 0x2d4, 0x2d5, 0x2d6, 0x2d7, 0x2d8, 0x2d9, 0x2da, 0x2db, + 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, 0x2e0, 0x2e1, 0x2e2, + 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, 0x2e8, 0x2e9, + 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, 0x2ef, + 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f6, + 0x2f7, 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fc, 0x2fd, + 0x2fe, 0x2ff, 0x300, 0x301, 0x302, 0x302, 0x303, 0x304, + 0x305, 0x306, 0x307, 0x308, 0x308, 0x309, 0x30a, 0x30b, + 0x30c, 0x30d, 0x30e, 0x30e, 0x30f, 0x310, 0x311, 0x312, + 0x313, 0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x319, + 0x319, 0x31a, 0x31b, 0x31c, 0x31d, 0x31e, 0x31e, 0x31f, + 0x320, 0x321, 0x322, 0x323, 0x323, 0x324, 0x325, 0x326, + 0x327, 0x328, 0x328, 0x329, 0x32a, 0x32b, 0x32c, 0x32d, + 0x32d, 0x32e, 0x32f, 0x330, 0x331, 0x332, 0x332, 0x333, + 0x334, 0x335, 0x336, 0x337, 0x337, 0x338, 0x339, 0x33a, + 0x33b, 0x33c, 0x33c, 0x33d, 0x33e, 0x33f, 0x340, 0x340, + 0x341, 0x342, 0x343, 0x344, 0x345, 0x345, 0x346, 0x347, + 0x348, 0x349, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, + 0x34e, 0x34f, 0x350, 0x351, 0x352, 0x352, 0x353, 0x354, + 0x355, 0x356, 0x356, 0x357, 0x358, 0x359, 0x35a, 0x35b, + 0x35b, 0x35c, 0x35d, 0x35e, 0x35f, 0x35f, 0x360, 0x361, + 0x362, 0x363, 0x363, 0x364, 0x365, 0x366, 0x367, 0x367, + 0x368, 0x369, 0x36a, 0x36b, 0x36b, 0x36c, 0x36d, 0x36e, + 0x36f, 0x36f, 0x370, 0x371, 0x372, 0x373, 0x373, 0x374, + 0x375, 0x376, 0x377, 0x377, 0x378, 0x379, 0x37a, 0x37a, + 0x37b, 0x37c, 0x37d, 0x37e, 0x37e, 0x37f, 0x380, 0x381, + 0x382, 0x382, 0x383, 0x384, 0x385, 0x385, 0x386, 0x387, + 0x388, 0x389, 0x389, 0x38a, 0x38b, 0x38c, 0x38d, 0x38d, + 0x38e, 0x38f, 0x390, 0x390, 0x391, 0x392, 0x393, 0x394, + 0x394, 0x395, 0x396, 0x397, 0x397, 0x398, 0x399, 0x39a, + 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39e, 0x39f, 0x3a0, + 0x3a1, 0x3a1, 0x3a2, 0x3a3, 0x3a4, 0x3a4, 0x3a5, 0x3a6, + 0x3a7, 0x3a8, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x3ab, 0x3ac, + 0x3ad, 0x3ae, 0x3ae, 0x3af, 0x3b0, 0x3b1, 0x3b1, 0x3b2, + 0x3b3, 0x3b4, 0x3b5, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b8, + 0x3b9, 0x3ba, 0x3bb, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3be, + 0x3bf, 0x3c0, 0x3c1, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c4, + 0x3c5, 0x3c6, 0x3c7, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3ca, + 0x3cb, 0x3cc, 0x3cd, 0x3cd, 0x3ce, 0x3cf, 0x3d0, 0x3d0, + 0x3d1, 0x3d2, 0x3d3, 0x3d3, 0x3d4, 0x3d5, 0x3d6, 0x3d6, + 0x3d7, 0x3d8, 0x3d9, 0x3d9, 0x3da, 0x3db, 0x3db, 0x3dc, + 0x3dd, 0x3de, 0x3de, 0x3df, 0x3e0, 0x3e1, 0x3e1, 0x3e2, + 0x3e3, 0x3e4, 0x3e4, 0x3e5, 0x3e6, 0x3e7, 0x3e7, 0x3e8, + 0x3e9, 0x3e9, 0x3ea, 0x3eb, 0x3ec, 0x3ec, 0x3ed, 0x3ee, + 0x3ef, 0x3ef, 0x3f0, 0x3f1, 0x3f2, 0x3f2, 0x3f3, 0x3f4, + 0x3f4, 0x3f5, 0x3f6, 0x3f7, 0x3f7, 0x3f8, 0x3f9, 0x3f9, + 0x3fa, 0x3fb, 0x3fc, 0x3fc, 0x3fd, 0x3fe, 0x3ff, 0x3ff, +}; + +static int int_log2(uint32_t n) +{ + int l, r; + if (n == 0) + return 0; /* indefinite */ + l = clz32(n); + n = (n << l) >> (31 - FRAC_BITS); + r = log2_table[n - FRAC_ONE] + ((31 - l) << FRAC_BITS); + return r; +} + +#if 0 +/* left for reference */ +void build_log2_table(void) +{ + int i; + for(i = 0; i < FRAC_ONE; i++) { + printf(" 0x%03x,", (int)lrint(log2(1.0 + (double)i / FRAC_ONE) * FRAC_ONE)); + if ((i % 8) == 7) + printf("\n"); + } +} + +void log2_test(void) +{ + double r, ref, err, err_max; + int i; + err_max = 0; + for(i = 1; i < 100000; i++) { + ref = log2((double)i); + r = (double)int_log2(i) / FRAC_ONE; + err = fabs(r - ref); + if (ref != 0) + err /= ref; + if (err > err_max) + err_max = err; + } + printf("err_max=%0.2e\n", err_max); +} +#endif + +/* return log2(n/d) * FRAC_ONE */ +static int64_t int_log2_frac(uint32_t n, uint32_t d) +{ + return int_log2(n) - int_log2(d); +} + +static int64_t get_n_bits(int c, WordList *s, + const uint32_t *char_freq, uint32_t tot_freq) +{ + Word *p; + if (c < NS) { + return -int_log2_frac(char_freq[c], tot_freq); + } else { + p = &s->words[c - NS]; + if (p->freq == 0) { + /* deleted word */ + return get_n_bits(p->buf[0], s, char_freq, tot_freq) + + get_n_bits(p->buf[1], s, char_freq, tot_freq); + } else { + return -int_log2_frac(p->freq, tot_freq); + } + } +} + +static int64_t compute_score(const Word *p, WordList *cw, + const uint32_t *char_freq, uint32_t tot_freq) +{ + int64_t old_bits, new_bits; + + if (p->freq <= 1) + return -1; /* not interesting if not repeating */ + if (1) { + old_bits = (get_n_bits(p->buf[0], cw, char_freq, tot_freq) + + get_n_bits(p->buf[1], cw, char_freq, tot_freq)) * p->freq; + + new_bits = (-int_log2_frac(p->freq, tot_freq) + TOT_FREQ_RED_BITS) * + p->freq + SUBST_COST; + /* return the gain in bits per substitution */ + return old_bits - new_bits; + } else { + return p->freq; + } +} + +/* select at most 'n' non overlaping words in ws and add them in + cw */ +int select_best_words(WordList *s, int n, WordList *cw, + const uint32_t *char_freq, uint32_t tot_freq, + int min_word_freq) +{ + int i, j; + Word *p; + uint8_t *cw_bitmap_start, *cw_bitmap_end; + const DataSymbol *buf; + + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + p->score = compute_score(p, cw, char_freq, tot_freq); + } + + qsort(s->words, s->word_count, sizeof(s->words[0]), word_score_cmp); + +#if 0 + { + printf("%3s %7s %7s %s\n", + "N", "FREQ", "SCORE", "WORD"); + for(i = 0; i < min_int(s->word_count, 50); i++) { + p = &s->words[i]; + printf("%3u %7u %7.0f '", i, p->freq, (double)p->score / FRAC_ONE); + dump_word(stdout, cw, p->buf[0], TRUE); + dump_word(stdout, cw, p->buf[1], TRUE); + printf("'\n"); + } + } +#endif + + cw_bitmap_start = mallocz(NS + cw->word_count); + cw_bitmap_end = mallocz(NS + cw->word_count); + + j = 0; + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + if (p->score <= 0 || p->freq < min_word_freq) + break; + /* test if there is a potential overlap with an existing word */ + buf = p->buf; + if (cw_bitmap_end[buf[0]] || + cw_bitmap_start[buf[1]]) + continue; + cw_bitmap_start[buf[0]] = 1; + cw_bitmap_end[buf[1]] = 1; + + /* add the word */ + word_find_add(cw, buf, 2, TRUE); +#if 0 + printf("%3u %7u '", j, p->freq); + dump_word(stdout, cw, NS + cw->word_count - 1, TRUE); + printf("'\n"); +#endif + if (++j >= n) + break; + } + + free(cw_bitmap_start); + free(cw_bitmap_end); + return j; +} + +static void buf_realloc(DataSymbol **pbuf, size_t *pbuf_size, size_t new_size) +{ + if (new_size <= *pbuf_size) + return; + new_size = max_size_t(new_size, *pbuf_size + (*pbuf_size) / 8); + *pbuf = realloc(*pbuf, new_size * sizeof(**pbuf)); + *pbuf_size = new_size; +} + +static void out_word(DataSymbol **pbuf, size_t *pbuf_size, + size_t *pbuf_pos, WordList *s, uint32_t c) +{ + size_t pos; + Word *p; + + if (c < NS) { + goto out_char; + } else { + p = &s->words[c - NS]; + if (p->freq == 0) { + out_word(pbuf, pbuf_size, pbuf_pos, s, p->buf[0]); + out_word(pbuf, pbuf_size, pbuf_pos, s, p->buf[1]); + } else { + out_char: + pos = *pbuf_pos; + if (pos >= *pbuf_size) + buf_realloc(pbuf, pbuf_size, pos + 1); + (*pbuf)[pos++] = c; + *pbuf_pos = pos; + } + } +} + +static void compute_word_freq(WordList *s, uint32_t *char_freq, + const DataSymbol *buf, size_t buf_size) +{ + int i; + uint32_t c; + Word *p; + + /* compute the frequency of all the words */ + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + p->freq = 0; + } + for(i = 0; i < NS; i++) { + char_freq[i] = 0; + } + for(i = 0; i < buf_size; i++) { + c = buf[i]; + if (c != CH_CUT) { + if (c >= NS) { + p = &s->words[c - NS]; + p->freq++; + } else { + char_freq[c]++; + } + } + } +} + +/* compute the frequency of the words and remove the ones with a too + low frequency. Return the word count */ +static int update_word_freq(WordList *s, uint32_t *char_freq, + DataSymbol **pbuf, size_t *pbuf_size, + int min_word_freq) +{ + int i, word_count; + Word *p; + DataSymbol *obuf, *buf; + size_t buf_size, obuf_size, buf_pos; + + buf_size = *pbuf_size; + buf = *pbuf; + + compute_word_freq(s, char_freq, buf, buf_size); + + word_count = 0; + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + if (p->freq >= min_word_freq) { + word_count++; + } else { + p->freq = 0; + } + } + if (word_count == s->word_count) + return word_count; + /* remove the words with a too low score from the buffer */ + obuf = malloc(sizeof(obuf[0]) * buf_size); + obuf_size = buf_size; + buf_pos = 0; + for(i = 0; i < buf_size; i++) { + out_word(&obuf, &obuf_size, &buf_pos, s, buf[i]); + } + free(buf); + + /* update the frequencies */ + compute_word_freq(s, char_freq, obuf, buf_pos); + + *pbuf = obuf; + *pbuf_size = buf_pos; + return word_count; +} + +static double compute_entropy(WordList *s, uint32_t *char_freq, + size_t buf_size) +{ + int64_t n_bits; + size_t i; + Word *p; + + n_bits = 0; + for(i = 0; i < NS; i++) { + if (char_freq[i] != 0) + n_bits += -int_log2_frac(char_freq[i], buf_size) * char_freq[i]; + } + for(i = 0; i < s->word_count; i++) { + p = &s->words[i]; + if (p->freq > 0) { + n_bits += -int_log2_frac(p->freq, buf_size) * p->freq; + } + } + return (double)n_bits / FRAC_ONE; +} + + +/* CH_WORD_START: add a space except if the last char is '[' or '(' */ + +static int is_word_char(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= 128); +} + +static int is_upper(int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +static int is_lower(int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 128); +} + +/* + syntax: + CH_NO_SPACE?[CH_TO_UPPER|CH_FIRST_UPPER]?SPACE word or not-word + + CH_ESCAPE is used in case one CH_x code is present in the input stream. +*/ + +DataSymbol *case_space_encoding(size_t *pobuf_len, DataSymbol *buf, size_t buf_len) +{ + size_t i, j, len, k, l, obuf_size; + DataSymbol *obuf; + int ch_type, c; + BOOL has_space; + + obuf = malloc(sizeof(buf[0]) * buf_len); + obuf_size = buf_len; + k = 0; + for(i = 0; i < buf_len;) { + if (is_word_char(buf[i])) { + j = i + 1; + if (is_lower(buf[i])) { + while (j < buf_len && is_lower(buf[j])) + j++; + ch_type = 0; + } else if (j < buf_len && is_upper(buf[j])) { + while (j < buf_len && is_upper(buf[j])) + j++; + ch_type = CH_TO_UPPER; + } else { + while (j < buf_len && is_lower(buf[j])) + j++; + ch_type = CH_FIRST_UPPER; + } + len = j - i; + + if (k > 0 && obuf[k - 1] == ' ') { + has_space = TRUE; + k--; + } else { + has_space = FALSE; + } + buf_realloc(&obuf, &obuf_size, k + len + 3); +#ifdef USE_CUT + obuf[k++] = CH_CUT; +#endif + if (!has_space) { + obuf[k++] = CH_NO_SPACE; + } + if (ch_type != 0) + obuf[k++] = ch_type; + obuf[k++] = ' '; + for(l = 0; l < len; l++) { + c = buf[i + l]; + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + obuf[k++] = c; + } + i += len; + } else if (buf[i] == CH_NO_SPACE || + buf[i] == CH_TO_UPPER || + buf[i] == CH_FIRST_UPPER || + buf[i] == CH_ESCAPE) { + /* escape the reserved codes */ + buf_realloc(&obuf, &obuf_size, k + 2); + obuf[k++] = CH_ESCAPE; + obuf[k++] = buf[i++]; + } else { + buf_realloc(&obuf, &obuf_size, k + 1); + obuf[k++] = buf[i++]; + } + } + obuf = realloc(obuf, sizeof(obuf[0]) * k); + *pobuf_len = k; + return obuf; +} + +typedef struct { + BOOL has_space; + int ch_type; + int ch_type1; + BOOL has_escape; +} CaseSpaceDecodeState; + +static void case_space_decode_init(CaseSpaceDecodeState *s) +{ + s->ch_type = 0; + s->has_space = TRUE; + s->ch_type1 = 0; + s->has_escape = FALSE; +} + +/* return the character to output or -1 if none */ +static int case_space_decode(CaseSpaceDecodeState *s, int c) +{ + if (s->has_escape) { + s->has_escape = FALSE; + } else if (c == CH_TO_UPPER || c == CH_FIRST_UPPER) { + s->ch_type = c; + c = -1; + } else if (c == CH_NO_SPACE) { + s->has_space = FALSE; + c = -1; + } else if (c == CH_ESCAPE) { + s->has_escape = TRUE; + c = -1; + } else if (c == ' ') { + s->ch_type1 = s->ch_type; + s->ch_type = 0; + if (!s->has_space) { + c = -1; + } + s->has_space = TRUE; + } else { + if (s->ch_type1 == CH_TO_UPPER || s->ch_type1 == CH_FIRST_UPPER) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + if (s->ch_type1 == CH_FIRST_UPPER) + s->ch_type1 = 0; + } + s->has_space = TRUE; + } + return c; +} + +/* return the total number of words */ +int word_encode(const char *in_filename, const char *out_filename, + const char *word_filename, int n_words, int min_word_freq, + const char *debug_dict_filename, BOOL sort_by_freq, + BOOL verbose) +{ + FILE *f; + size_t buf_size, i, j, buf_size1; + DataSymbol *buf, *buf1; + uint32_t *char_freq, *tab_sort; + WordList *ws, *s; + Word *p; + int n, word_count, word_count_prev; + double n_bits; + + f = fopen(in_filename, "rb"); + if (!f) { + perror(in_filename); + exit(1); + } + + fseek(f, 0, SEEK_END); + buf_size = ftell(f); + fseek(f, 0, SEEK_SET); + buf = malloc(buf_size * sizeof(buf[0])); + for(i = 0; i < buf_size; i++) { + buf[i] = fgetc(f); + } + fclose(f); + + buf1 = case_space_encoding(&buf_size1, buf, buf_size); + free(buf); + buf = buf1; + buf_size = buf_size1; + + if (verbose) { + printf("Preprocessing: after case/space preprocessing: %d symbols\n", + (int)buf_size); + } + + s = word_list_init(); + + char_freq = mallocz(sizeof(char_freq[0]) * NS); + + compute_word_freq(s, char_freq, buf, buf_size); + + n_words -= NS; + + if (verbose) { + printf("%6s %9s %9s\n", + "#WORDS", "SIZE", "ENTROPY"); + } + + for(word_count = 0; word_count < n_words;) { + if (buf_size < 2) + break; + ws = word_list_init(); + hash_lookup_count = 0; + hash_it_count = 0; + for(i = 0; i < buf_size - 1; i++) { + /* favorise words with space before */ + if (buf[i] != CH_CUT && buf[i + 1] != CH_CUT) { + p = word_find_add(ws, buf + i, 2, TRUE); + p->freq++; + } + } +#if 0 + printf("hash stats: %d %" PRId64 "d avg=%0.1f\n", + (int)ws->word_count, + hash_lookup_count, + (double)hash_it_count / hash_lookup_count); +#endif + n = select_best_words(ws, min_int(MAX_WORDS_PER_ITER, + n_words - word_count), + s, char_freq, buf_size, min_word_freq); + word_list_end(ws); + if (n == 0) + break; + + /* replace with the new words */ + j = 0; + for(i = 0; i < buf_size;) { + if ((i + 1) >= buf_size) + goto no_subst; + p = word_find_add(s, buf + i, 2, FALSE); + if (p) { + buf[j++] = NS + (p - s->words); + i += 2; + } else { + no_subst: + buf[j++] = buf[i++]; + } + } + buf_size = j; + + /* compute the frequency of all the words and remove the words + with a too low frequency */ + word_count_prev = word_count; + word_count = update_word_freq(s, char_freq, &buf, &buf_size, + min_word_freq); + + /* mesure the entropy */ + n_bits = compute_entropy(s, char_freq, buf_size); + + if (verbose) { + printf("%6u %9u %9.0f\r", word_count + NS, (int)buf_size, n_bits / 8); + fflush(stdout); + } + + if (word_count >= n_words || + word_count == word_count_prev) + break; + } + + if (verbose) { + printf("%6u %9u\n", word_count + NS, (int)buf_size); + } + + word_count = sort_words(s, &tab_sort, char_freq, sort_by_freq); + + save_words(s, word_filename, tab_sort, word_count); + if (debug_dict_filename) { + save_words_debug(s, debug_dict_filename, char_freq, buf_size, + tab_sort, word_count); + } + + save_output(buf, buf_size, s, out_filename, tab_sort, word_count); + free(tab_sort); + free(buf); + free(char_freq); + + word_list_end(s); + return word_count; +} + +void word_load(StringTable *s, const char *filename) +{ + FILE *f; + uint8_t buf[4096]; + int len, c; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + len = 0; + for(;;) { + c = fgetc(f); + if (c < 0) + break; + if (c == '\n') { + if (len > 0) { + string_table_add(s, (const char *)buf, len); + } + len = 0; + } else { + if (c == '\\') { + c = fgetc(f); + if (c < 0) + break; + if (c == 'n') { + c = '\n'; + } else if (c != '\\') { + fprintf(stderr, "Invalid escape\n"); + exit(1); + } + } + if (len >= sizeof(buf)) { + fprintf(stderr, "Word too long\n"); + exit(1); + } + buf[len++] = c; + } + } + fclose(f); +} + +void word_decode(const char *in_filename, const char *out_filename, + const char *word_filename) +{ + StringTable *s; + FILE *f, *fo; + uint16_t c; + int i, len, b; + StringEntry *p; + const uint8_t *buf; + CaseSpaceDecodeState cs; + + s = string_table_init(); + word_load(s, word_filename); + + // printf("%d words\n", (int)s->count); + + f = fopen(in_filename, "rb"); + if (!f) { + perror(in_filename); + exit(1); + } + + fo = fopen(out_filename, "wb"); + if (!fo) { + perror(out_filename); + exit(1); + } + + case_space_decode_init(&cs); + for(;;) { + if (fget_be16(f, &c)) + break; + if (c >= s->count) { + fprintf(stderr, "Invalid symbol %d\n", c); + exit(1); + } + p = s->tab[c]; + buf = (uint8_t *)p->data; + len = p->len; + for(i = 0; i < len; i++) { + b = case_space_decode(&cs, buf[i]); + if (b >= 0) + fputc(b, fo); + } + } + + fclose(fo); + + fclose(f); + + string_table_end(s); +} + +#ifdef CONFIG_STANDALONE + +void help(void) +{ + printf("Preprocess version " CONFIG_VERSION", Copyright (c) 2018-2021 Fabrice Bellard\n" + "Dictionary based preprocessor\n" + "usage: preprocess [options] c dictfile infile outfile n_words min_freq\n" + " preprocess [options] d dictfile infile outfile\n" + "\n" + "'c' command: build the dictionary 'dictfile' from 'infile' and output the preprocessed data to 'outfile'. 'n_words' is the approximative maximum number of words of the dictionary. 'min_freq' is the minimum frequency of the selected words.\n" + "'d' command: rebuild the original file from the dictionary and the preprocessed data.\n" + "\n" + "Options:\n" + "-h this help\n" + "-D filename output debug information associated with the dictionary\n" + "-s sort the words by decreasing frequency\n" + +); + exit(1); +} + +int main(int argc, char **argv) +{ + const char *in_filename, *out_filename, *mode, *dict_filename; + const char *debug_dict_filename; + BOOL sort_by_freq; + int c; + + debug_dict_filename = NULL; + sort_by_freq = FALSE; + for(;;) { + c = getopt(argc, argv, "hD:s"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + break; + case 'D': + debug_dict_filename = optarg; + break; + case 's': + sort_by_freq = TRUE; + break; + default: + exit(1); + } + } + + if ((argc - optind) < 1) + help(); + + mode = argv[optind++]; + + if (mode[0] == 'c') { + int n_words, min_word_freq; + if ((argc - optind) != 5) + help(); + dict_filename = argv[optind++]; + in_filename = argv[optind++]; + out_filename = argv[optind++]; + n_words = atoi(argv[optind++]); + min_word_freq = atoi(argv[optind++]); + word_encode(in_filename, out_filename, dict_filename, n_words, + min_word_freq, debug_dict_filename, sort_by_freq, TRUE); + } else if (mode[0] == 'd') { + if ((argc - optind) != 3) + help(); + dict_filename = argv[optind++]; + in_filename = argv[optind++]; + out_filename = argv[optind++]; + word_decode(in_filename, out_filename, dict_filename); + } else { + help(); + } + return 0; +} + +#endif diff --git a/deps/nncp/preprocess.h b/deps/nncp/preprocess.h new file mode 100644 index 0000000..1966f0b --- /dev/null +++ b/deps/nncp/preprocess.h @@ -0,0 +1,29 @@ +/* + * NNCP preprocessor + * + * Copyright (c) 2018-2021 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +int word_encode(const char *in_filename, const char *out_filename, + const char *word_filename, int n_words, int min_word_freq, + const char *debug_dict_filename, BOOL sort_by_freq, + int verbose); +void word_decode(const char *in_filename, const char *out_filename, + const char *word_filename); diff --git a/deps/nncp/readme.txt b/deps/nncp/readme.txt new file mode 100644 index 0000000..5c0c902 --- /dev/null +++ b/deps/nncp/readme.txt @@ -0,0 +1,57 @@ +Lossless Data Compression with Neural Networks +============================================== + +1) Overview +----------- + +NNCP is an experimental lossless data compressor using Neural +Networks. Two models are available: Transformer (slower but best +ratio) and LSTM (faster). A text preprocessor and tokenizer can +optionally be enabled. More information is available at +https://bellard.org/nncp . + +Thanks to LibNC, it supports both the GPU (NVIDIA CUDA version 11.x or +12.x required with a Ampere, ADA or Hopper GPU) and CPU. For an +acceptable speed with large models, a GPU is required. + +2) Compilation +-------------- + +A Linux system is assumed. Just type 'make' to compile the program. A +binary DLL of the LibNC library is included in the archive. When using +CUDA, cuBLAS must be installed too. + +Windows cross-compilation from Linux is supported provided the +libnc*.dll files are copied from the Windows version. + +5) Current best models for enwik8/enwik9 +---------------------------------------- + +enwik8: + + ./nncp --cuda --profile enwik8 --preprocess 4096,512 c enwik8 out.bin + + Result: 14915298 bytes (13.2 hours) + +enwik9: + + ./nncp --cuda --profile enwik9 --preprocess 16384,512 c enwik9 out.bin + + Result: 106632363 bytes (2.8 days) + +Decompression: + + ./nncp --cuda d out.bin out.txt + + Decompression has a similar speed than compression. + +Test system: AMD Ryzen 9 3900 + RTX 4090 NVIDIA GPU + +Memory usage: CPU: 1 GB, GPU: 6.6 GB + +6) Licence +---------- + +The source code is released under the MIT licence. + +The LibNC library is provided in binary form and can be freely redistributed. diff --git a/deps/quickjs/Changelog b/deps/quickjs/Changelog new file mode 100644 index 0000000..944d96a --- /dev/null +++ b/deps/quickjs/Changelog @@ -0,0 +1,175 @@ +2024-01-13: + +- top-level-await support in modules +- allow 'await' in the REPL +- added Array.prototype.{with,toReversed,toSpliced,toSorted} and +TypedArray.prototype.{with,toReversed,toSorted} +- added String.prototype.isWellFormed and String.prototype.toWellFormed +- added Object.groupBy and Map.groupBy +- added Promise.withResolvers +- class static block +- 'in' operator support for private fields +- optional chaining fixes +- added RegExp 'd' flag +- fixed RegExp zero length match logic +- fixed RegExp case insensitive flag +- added os.getpid() and os.now() +- added cosmopolitan build +- misc bug fixes + +2023-12-09: + +- added Object.hasOwn, {String|Array|TypedArray}.prototype.at, + {Array|TypedArray}.prototype.findLast{Index} +- BigInt support is enabled even if CONFIG_BIGNUM disabled +- updated to Unicode 15.0.0 +- misc bug fixes + +2021-03-27: + +- faster Array.prototype.push and Array.prototype.unshift +- added JS_UpdateStackTop() +- fixed Windows console +- misc bug fixes + +2020-11-08: + +- improved function parameter initializers +- added std.setenv(), std.unsetenv() and std.getenviron() +- added JS_EvalThis() +- misc bug fixes + +2020-09-06: + +- added logical assignment operators +- added IsHTMLDDA support +- faster for-of loops +- os.Worker now takes a module filename as parameter +- qjsc: added -D option to compile dynamically loaded modules or workers +- misc bug fixes + +2020-07-05: + +- modified JS_GetPrototype() to return a live value +- REPL: support unicode characters larger than 16 bits +- added os.Worker +- improved object serialization +- added std.parseExtJSON +- misc bug fixes + +2020-04-12: + +- added cross realm support +- added AggregateError and Promise.any +- added env, uid and gid options in os.exec() +- misc bug fixes + +2020-03-16: + +- reworked error handling in std and os libraries: suppressed I/O + exceptions in std FILE functions and return a positive errno value + when it is explicit +- output exception messages to stderr +- added std.loadFile(), std.strerror(), std.FILE.prototype.tello() +- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32() +- updated to Unicode 13.0.0 +- misc bug fixes + +2020-01-19: + +- keep CONFIG_BIGNUM in the makefile +- added os.chdir() +- qjs: added -I option +- more memory checks in the bignum operations +- modified operator overloading semantics to be closer to the TC39 + proposal +- suppressed "use bigint" mode. Simplified "use math" mode +- BigDecimal: changed suffix from 'd' to 'm' +- misc bug fixes + +2020-01-05: + +- always compile the bignum code. Added '--bignum' option to qjs. +- added BigDecimal +- added String.prototype.replaceAll +- misc bug fixes + +2019-12-21: + +- added nullish coalescing operator (ES2020) +- added optional chaining (ES2020) +- removed recursions in garbage collector +- test stack overflow in the parser +- improved backtrace logic +- added JS_SetHostPromiseRejectionTracker() +- allow exotic constructors +- improved c++ compatibility +- misc bug fixes + +2019-10-27: + +- added example of C class in a module (examples/test_point.js) +- added JS_GetTypedArrayBuffer() +- misc bug fixes + +2019-09-18: + +- added os.exec and other system calls +- exported JS_ValueToAtom() +- qjsc: added 'qjsc_' prefix to the generated C identifiers +- added cross-compilation support +- misc bug fixes + +2019-09-01: + +- added globalThis +- documented JS_EVAL_FLAG_COMPILE_ONLY +- added import.meta.url and import.meta.main +- added 'debugger' statement +- misc bug fixes + +2019-08-18: + +- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat, + os.readlink, os.readdir, os.utimes, std.popen +- module autodetection +- added import.meta +- misc bug fixes + +2019-08-10: + +- added public class fields and private class fields, methods and + accessors (TC39 proposal) +- changed JS_ToCStringLen() prototype +- qjsc: handle '-' in module names and modules with the same filename +- added std.urlGet +- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty() +- exported some bigint C functions +- added support for eshost in run-test262 +- misc bug fixes + +2019-07-28: + +- added dynamic import +- added Promise.allSettled +- added String.prototype.matchAll +- added Object.fromEntries +- reduced number of ticks in await +- added BigInt support in Atomics +- exported JS_NewPromiseCapability() +- misc async function and async generator fixes +- enabled hashbang support by default + +2019-07-21: + +- updated test262 tests +- updated to Unicode version 12.1.0 +- fixed missing Date object in qjsc +- fixed multi-context creation +- misc ES2020 related fixes +- simplified power and division operators in bignum extension +- fixed several crash conditions + +2019-07-09: + +- first public release diff --git a/deps/quickjs/LICENSE b/deps/quickjs/LICENSE new file mode 100644 index 0000000..2c8fdeb --- /dev/null +++ b/deps/quickjs/LICENSE @@ -0,0 +1,22 @@ +QuickJS Javascript Engine + +Copyright (c) 2017-2021 Fabrice Bellard +Copyright (c) 2017-2021 Charlie Gordon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/deps/quickjs/Makefile b/deps/quickjs/Makefile new file mode 100644 index 0000000..57cdd7e --- /dev/null +++ b/deps/quickjs/Makefile @@ -0,0 +1,487 @@ +# +# QuickJS Javascript Engine +# +# Copyright (c) 2017-2021 Fabrice Bellard +# Copyright (c) 2017-2021 Charlie Gordon +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +ifeq ($(shell uname -s),Darwin) +CONFIG_DARWIN=y +endif +# Windows cross compilation from Linux +#CONFIG_WIN32=y +# use link time optimization (smaller and faster executables but slower build) +CONFIG_LTO=y +# consider warnings as errors (for development) +#CONFIG_WERROR=y +# force 32 bit build for some utilities +#CONFIG_M32=y +# cosmopolitan build (see https://github.com/jart/cosmopolitan) +#CONFIG_COSMO=y + +# installation directory +PREFIX?=/usr/local + +# use the gprof profiler +#CONFIG_PROFILE=y +# use address sanitizer +#CONFIG_ASAN=y +# include the code for BigFloat/BigDecimal, math mode and faster large integers +CONFIG_BIGNUM=y + +OBJDIR=.obj + +ifdef CONFIG_DARWIN +# use clang instead of gcc +CONFIG_CLANG=y +CONFIG_DEFAULT_AR=y +endif + +ifdef CONFIG_WIN32 + ifdef CONFIG_M32 + CROSS_PREFIX?=i686-w64-mingw32- + else + CROSS_PREFIX?=x86_64-w64-mingw32- + endif + EXE=.exe +else + CROSS_PREFIX?= + EXE= +endif + +ifdef CONFIG_CLANG + HOST_CC=clang + CC=$(CROSS_PREFIX)clang + CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d + CFLAGS += -Wextra + CFLAGS += -Wno-sign-compare + CFLAGS += -Wno-missing-field-initializers + CFLAGS += -Wundef -Wuninitialized + CFLAGS += -Wunused -Wno-unused-parameter + CFLAGS += -Wwrite-strings + CFLAGS += -Wchar-subscripts -funsigned-char + CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d + ifdef CONFIG_DEFAULT_AR + AR=$(CROSS_PREFIX)ar + else + ifdef CONFIG_LTO + AR=$(CROSS_PREFIX)llvm-ar + else + AR=$(CROSS_PREFIX)ar + endif + endif +else ifdef CONFIG_COSMO + CONFIG_LTO= + HOST_CC=gcc + CC=cosmocc + # cosmocc does not correct support -MF + CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d + CFLAGS += -Wno-array-bounds -Wno-format-truncation + AR=cosmoar +else + HOST_CC=gcc + CC=$(CROSS_PREFIX)gcc + CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d + CFLAGS += -Wno-array-bounds -Wno-format-truncation + ifdef CONFIG_LTO + AR=$(CROSS_PREFIX)gcc-ar + else + AR=$(CROSS_PREFIX)ar + endif +endif +STRIP=$(CROSS_PREFIX)strip +CFLAGS+=-fwrapv # ensure that signed overflows behave as expected +ifdef CONFIG_WERROR +CFLAGS+=-Werror +endif +DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" +ifdef CONFIG_BIGNUM +DEFINES+=-DCONFIG_BIGNUM +endif +ifdef CONFIG_WIN32 +DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior +endif + +CFLAGS+=$(DEFINES) +CFLAGS_DEBUG=$(CFLAGS) -O0 +CFLAGS_SMALL=$(CFLAGS) -Os +CFLAGS_OPT=$(CFLAGS) -O2 +CFLAGS_NOLTO:=$(CFLAGS_OPT) +ifdef CONFIG_COSMO +LDFLAGS+=-s # better to strip by default +else +LDFLAGS+=-g +endif +ifdef CONFIG_LTO +CFLAGS_SMALL+=-flto +CFLAGS_OPT+=-flto +LDFLAGS+=-flto +endif +ifdef CONFIG_PROFILE +CFLAGS+=-p +LDFLAGS+=-p +endif +ifdef CONFIG_ASAN +CFLAGS+=-fsanitize=address -fno-omit-frame-pointer +LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer +endif +ifdef CONFIG_WIN32 +LDEXPORT= +else +LDEXPORT=-rdynamic +endif + +ifndef CONFIG_COSMO +ifndef CONFIG_DARWIN +CONFIG_SHARED_LIBS=y # building shared libraries is supported +endif +endif + +PROGS=qjs$(EXE) qjsc$(EXE) run-test262 +ifneq ($(CROSS_PREFIX),) +QJSC_CC=gcc +QJSC=./host-qjsc +PROGS+=$(QJSC) +else +QJSC_CC=$(CC) +QJSC=./qjsc$(EXE) +endif +ifndef CONFIG_WIN32 +PROGS+=qjscalc +endif +ifdef CONFIG_M32 +PROGS+=qjs32 qjs32_s +endif +PROGS+=libquickjs.a +ifdef CONFIG_LTO +PROGS+=libquickjs.lto.a +endif + +# examples +ifeq ($(CROSS_PREFIX),) +PROGS+=examples/hello +ifndef CONFIG_ASAN +PROGS+=examples/hello_module +endif +ifdef CONFIG_SHARED_LIBS +PROGS+=examples/test_fib examples/fib.so examples/point.so +endif +endif + +all: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS) + +QJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o $(OBJDIR)/libbf.o + +QJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS) +ifdef CONFIG_BIGNUM +QJS_OBJS+=$(OBJDIR)/qjscalc.o +endif + +HOST_LIBS=-lm -ldl -lpthread +LIBS=-lm +ifndef CONFIG_WIN32 +LIBS+=-ldl -lpthread +endif +LIBS+=$(EXTRA_LIBS) + +$(OBJDIR): + mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests + +qjs$(EXE): $(QJS_OBJS) + $(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS) + +qjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS)) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +qjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +ifneq ($(CROSS_PREFIX),) + +$(QJSC): $(OBJDIR)/qjsc.host.o \ + $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS)) + $(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS) + +endif #CROSS_PREFIX + +QJSC_DEFINES:=-DCONFIG_CC=\"$(QJSC_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" +ifdef CONFIG_LTO +QJSC_DEFINES+=-DCONFIG_LTO +endif +QJSC_HOST_DEFINES:=-DCONFIG_CC=\"$(HOST_CC)\" -DCONFIG_PREFIX=\"$(PREFIX)\" + +$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES) +$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES) + +qjs32: $(patsubst %.o, %.m32.o, $(QJS_OBJS)) + $(CC) -m32 $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS) + +qjs32_s: $(patsubst %.o, %.m32s.o, $(QJS_OBJS)) + $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) + @size $@ + +qjscalc: qjs + ln -sf $< $@ + +ifdef CONFIG_LTO +LTOEXT=.lto +else +LTOEXT= +endif + +libquickjs$(LTOEXT).a: $(QJS_LIB_OBJS) + $(AR) rcs $@ $^ + +ifdef CONFIG_LTO +libquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS)) + $(AR) rcs $@ $^ +endif # CONFIG_LTO + +repl.c: $(QJSC) repl.js + $(QJSC) -c -o $@ -m repl.js + +qjscalc.c: $(QJSC) qjscalc.js + $(QJSC) -fbignum -c -o $@ qjscalc.js + +ifneq ($(wildcard unicode/UnicodeData.txt),) +$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.m32.o $(OBJDIR)/libunicode.m32s.o \ + $(OBJDIR)/libunicode.nolto.o: libunicode-table.h + +libunicode-table.h: unicode_gen + ./unicode_gen unicode $@ +endif + +run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)) + $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) + +# object suffix order: nolto, [m32|m32s] + +$(OBJDIR)/%.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS_OPT) -c -o $@ $< + +$(OBJDIR)/%.host.o: %.c | $(OBJDIR) + $(HOST_CC) $(CFLAGS_OPT) -c -o $@ $< + +$(OBJDIR)/%.pic.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $< + +$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS_NOLTO) -c -o $@ $< + +$(OBJDIR)/%.m32.o: %.c | $(OBJDIR) + $(CC) -m32 $(CFLAGS_OPT) -c -o $@ $< + +$(OBJDIR)/%.m32s.o: %.c | $(OBJDIR) + $(CC) -m32 $(CFLAGS_SMALL) -c -o $@ $< + +$(OBJDIR)/%.debug.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS_DEBUG) -c -o $@ $< + +$(OBJDIR)/%.check.o: %.c | $(OBJDIR) + $(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $< + +regexp_test: libregexp.c libunicode.c cutils.c + $(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS) + +unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h + $(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o + +clean: + rm -f repl.c qjscalc.c out.c + rm -f *.a *.o *.d *~ unicode_gen regexp_test $(PROGS) + rm -f hello.c test_fib.c + rm -f examples/*.so tests/*.so + rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug + rm -rf run-test262-debug run-test262-32 + +install: all + mkdir -p "$(DESTDIR)$(PREFIX)/bin" + $(STRIP) qjs qjsc + install -m755 qjs qjsc "$(DESTDIR)$(PREFIX)/bin" + ln -sf qjs "$(DESTDIR)$(PREFIX)/bin/qjscalc" + mkdir -p "$(DESTDIR)$(PREFIX)/lib/quickjs" + install -m644 libquickjs.a "$(DESTDIR)$(PREFIX)/lib/quickjs" +ifdef CONFIG_LTO + install -m644 libquickjs.lto.a "$(DESTDIR)$(PREFIX)/lib/quickjs" +endif + mkdir -p "$(DESTDIR)$(PREFIX)/include/quickjs" + install -m644 quickjs.h quickjs-libc.h "$(DESTDIR)$(PREFIX)/include/quickjs" + +############################################################################### +# examples + +# example of static JS compilation +HELLO_SRCS=examples/hello.js +HELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ + -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \ + -fno-date -fno-module-loader -fno-bigint + +hello.c: $(QJSC) $(HELLO_SRCS) + $(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS) + +ifdef CONFIG_M32 +examples/hello: $(OBJDIR)/hello.m32s.o $(patsubst %.o, %.m32s.o, $(QJS_LIB_OBJS)) + $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) +else +examples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) +endif + +# example of static JS compilation with modules +HELLO_MODULE_SRCS=examples/hello_module.js +HELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \ + -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \ + -fno-date -m +examples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS) + $(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS) + +# use of an external C module (static compilation) + +test_fib.c: $(QJSC) examples/test_fib.js + $(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js + +examples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +examples/fib.so: $(OBJDIR)/examples/fib.pic.o + $(CC) $(LDFLAGS) -shared -o $@ $^ + +examples/point.so: $(OBJDIR)/examples/point.pic.o + $(CC) $(LDFLAGS) -shared -o $@ $^ + +############################################################################### +# documentation + +DOCS=doc/quickjs.pdf doc/quickjs.html doc/jsbignum.pdf doc/jsbignum.html + +build_doc: $(DOCS) + +clean_doc: + rm -f $(DOCS) + +doc/%.pdf: doc/%.texi + texi2pdf --clean -o $@ -q $< + +doc/%.html.pre: doc/%.texi + makeinfo --html --no-headers --no-split --number-sections -o $@ $< + +doc/%.html: doc/%.html.pre + sed -e 's||\n|' < $< > $@ + +############################################################################### +# tests + +ifdef CONFIG_SHARED_LIBS +test: tests/bjson.so examples/point.so +endif +ifdef CONFIG_M32 +test: qjs32 +endif + +test: qjs + ./qjs tests/test_closure.js + ./qjs tests/test_language.js + ./qjs tests/test_builtin.js + ./qjs tests/test_loop.js + ./qjs tests/test_std.js + ./qjs tests/test_worker.js +ifdef CONFIG_SHARED_LIBS +ifdef CONFIG_BIGNUM + ./qjs --bignum tests/test_bjson.js +else + ./qjs tests/test_bjson.js +endif + ./qjs examples/test_point.js +endif +ifdef CONFIG_BIGNUM + ./qjs --bignum tests/test_op_overloading.js + ./qjs --bignum tests/test_bignum.js + ./qjs --qjscalc tests/test_qjscalc.js +endif +ifdef CONFIG_M32 + ./qjs32 tests/test_closure.js + ./qjs32 tests/test_language.js + ./qjs32 tests/test_builtin.js + ./qjs32 tests/test_loop.js + ./qjs32 tests/test_std.js + ./qjs32 tests/test_worker.js +ifdef CONFIG_BIGNUM + ./qjs32 --bignum tests/test_op_overloading.js + ./qjs32 --bignum tests/test_bignum.js + ./qjs32 --qjscalc tests/test_qjscalc.js +endif +endif + +stats: qjs qjs32 + ./qjs -qd + ./qjs32 -qd + +microbench: qjs + ./qjs tests/microbench.js + +microbench-32: qjs32 + ./qjs32 tests/microbench.js + +# ES5 tests (obsolete) +test2o: run-test262 + time ./run-test262 -m -c test262o.conf + +test2o-32: run-test262-32 + time ./run-test262-32 -m -c test262o.conf + +test2o-update: run-test262 + ./run-test262 -u -c test262o.conf + +# Test262 tests +test2-default: run-test262 + time ./run-test262 -m -c test262.conf + +test2: run-test262 + time ./run-test262 -m -c test262.conf -a + +test2-32: run-test262-32 + time ./run-test262-32 -m -c test262.conf -a + +test2-update: run-test262 + ./run-test262 -u -c test262.conf -a + +test2-check: run-test262 + time ./run-test262 -m -c test262.conf -E -a + +testall: all test microbench test2o test2 + +testall-32: all test-32 microbench-32 test2o-32 test2-32 + +testall-complete: testall testall-32 + +bench-v8: qjs + make -C tests/bench-v8 + ./qjs -d tests/bench-v8/combined.js + +tests/bjson.so: $(OBJDIR)/tests/bjson.pic.o + $(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS) + +-include $(wildcard $(OBJDIR)/*.d) diff --git a/deps/quickjs/TODO b/deps/quickjs/TODO new file mode 100644 index 0000000..bbd1a45 --- /dev/null +++ b/deps/quickjs/TODO @@ -0,0 +1,67 @@ +Misc ideas: +- use custom printf to avoid compatibility issues with floating point numbers +- consistent naming for preprocessor defines +- unify coding style and naming conventions +- use names from the ECMA spec in library implementation +- use byte code emitters with typed arguments (for clarity) +- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing + and use the same wrappers in all phases +- use more generic method for line numbers in resolve_variables and resolve_labels +- use custom timezone support to avoid C library compatibility issues + +Memory: +- use memory pools for objects, etc? +- test border cases for max number of atoms, object properties, string length +- add emergency malloc mode for out of memory exceptions. +- test all DynBuf memory errors +- test all js_realloc memory errors +- improve JS_ComputeMemoryUsage() with more info + +Built-in standard library: +- BSD sockets +- modules: use realpath in module name normalizer and put it in quickjs-libc +- modules: if no ".", use a well known module loading path ? +- get rid of __loadScript, use more common name + +REPL: +- debugger +- readline: support MS Windows terminal +- readline: handle dynamic terminal resizing +- readline: handle double width unicode characters +- multiline editing +- runtime object and function inspectors +- interactive object browser +- use more generic approach to display evaluation results +- improve directive handling: dispatch, colorize, completion... +- save history +- close all predefined methods in repl.js and jscalc.js + +Optimization ideas: +- 64-bit atoms in 64-bit mode ? +- 64-bit small bigint in 64-bit mode ? +- reuse stack slots for disjoint scopes, if strip +- add heuristic to avoid some cycles in closures +- small String (0-2 charcodes) with immediate storage +- perform static string concatenation at compile time +- optimize string concatenation with ropes or miniropes? +- add implicit numeric strings for Uint32 numbers? +- optimize `s += a + b`, `s += a.b` and similar simple expressions +- ensure string canonical representation and optimise comparisons and hashes? +- remove JSObject.first_weak_ref, use bit+context based hashed array for weak references +- property access optimization on the global object, functions, + prototypes and special non extensible objects. +- create object literals with the correct length by backpatching length argument +- remove redundant set_loc_uninitialized/check_uninitialized opcodes +- peephole optim: push_atom_value, to_propkey -> push_atom_value +- peephole optim: put_loc x, get_loc_check x -> set_loc x +- convert slow array to fast array when all properties != length are numeric +- optimize destructuring assignments for global and local variables +- implement some form of tail-call-optimization +- optimize OP_apply +- optimize f(...b) + +Test262o: 0/11262 errors, 463 excluded +Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) + +Result: 10/76947 errors, 1497 excluded, 8117 skipped +Test262 commit: 6cbb6da9473c56d95358d8e679c5a6d2b4574efb diff --git a/deps/quickjs/VERSION b/deps/quickjs/VERSION new file mode 100644 index 0000000..e89de35 --- /dev/null +++ b/deps/quickjs/VERSION @@ -0,0 +1 @@ +2024-01-13 diff --git a/quickjs/cutils.c b/deps/quickjs/cutils.c similarity index 99% rename from quickjs/cutils.c rename to deps/quickjs/cutils.c index 95ddd2a..a02fb76 100644 --- a/quickjs/cutils.c +++ b/deps/quickjs/cutils.c @@ -23,12 +23,9 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" #include #include -#include "my_string.h" #include "cutils.h" diff --git a/quickjs/cutils.h b/deps/quickjs/cutils.h similarity index 92% rename from quickjs/cutils.h rename to deps/quickjs/cutils.h index 5eecd95..8399d61 100644 --- a/quickjs/cutils.h +++ b/deps/quickjs/cutils.h @@ -26,7 +26,7 @@ #define CUTILS_H #include -// #include +#include /* set if CPU is big endian */ #undef WORDS_BIGENDIAN @@ -49,6 +49,9 @@ #define countof(x) (sizeof(x) / sizeof((x)[0])) #endif +/* return the pointer of type 'type *' containing 'ptr' as field 'member' */ +#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member))) + typedef int BOOL; #ifndef FALSE @@ -294,23 +297,4 @@ void rqsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *, void *), void *arg); -#define CHECK2(cond, code) \ - do { \ - if (!(cond)) { \ - err = code; \ - printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ - goto exit; \ - } \ - } while (0) - -#define CHECK(_code) \ - do { \ - int code = (_code); \ - if (code != 0) { \ - err = code; \ - printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ - goto exit; \ - } \ - } while (0) - #endif /* CUTILS_H */ diff --git a/deps/quickjs/doc/jsbignum.html b/deps/quickjs/doc/jsbignum.html new file mode 100644 index 0000000..ab31612 --- /dev/null +++ b/deps/quickjs/doc/jsbignum.html @@ -0,0 +1,734 @@ + + + + +Javascript Bignum Extensions + + + + + + + + + + + + + + + +

Javascript Bignum Extensions

+ + +

Table of Contents

+ + + + + +

1 Introduction

+ +

The Bignum extensions add the following features to the Javascript +language while being 100% backward compatible: +

+
    +
  • Operator overloading with a dispatch logic inspired from the proposal available at https://github.com/tc39/proposal-operator-overloading/. + +
  • Arbitrarily large floating point numbers (BigFloat) in base 2 using the IEEE 754 semantics. + +
  • Arbitrarily large floating point numbers (BigDecimal) in base 10 based on the proposal available at +https://github.com/littledan/proposal-bigdecimal. + +
  • math mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (%) is defined as the Euclidian +remainder. ^ is an alias to the power operator +(**). ^^ is used as the exclusive or operator. + +
+ +

The extensions are independent from each other except the math +mode which relies on BigFloat and operator overloading. +

+ +

2 Operator overloading

+ +

Operator overloading is inspired from the proposal available at +https://github.com/tc39/proposal-operator-overloading/. It +implements the same dispatch logic but finds the operator sets by +looking at the Symbol.operatorSet property in the objects. The +changes were done in order to simplify the implementation. +

+

More precisely, the following modifications were made: +

+
    +
  • with operators from is not supported. Operator overloading is always enabled. + +
  • The dispatch is not based on a static [[OperatorSet]] field in all instances. Instead, a dynamic lookup of the Symbol.operatorSet property is done. This property is typically added in the prototype of each object. + +
  • Operators.create(...dictionaries) is used to create a new OperatorSet object. The Operators function is supported as an helper to be closer to the TC39 proposal. + +
  • [] cannot be overloaded. + +
  • In math mode, the BigInt division and power operators can be overloaded with Operators.updateBigIntOperators(dictionary). + +
+ + +

3 BigInt extensions

+ +

A few properties are added to the BigInt object: +

+
+
tdiv(a, b)
+

Return trunc(a/b). b = 0 raises a RangeError +exception. +

+
+
fdiv(a, b)
+

Return \lfloor a/b \rfloor. b = 0 raises a RangeError +exception. +

+
+
cdiv(a, b)
+

Return \lceil a/b \rceil. b = 0 raises a RangeError +exception. +

+
+
ediv(a, b)
+

Return sgn(b) \lfloor a/{|b|} \rfloor (Euclidian +division). b = 0 raises a RangeError exception. +

+
+
tdivrem(a, b)
+
fdivrem(a, b)
+
cdivrem(a, b)
+
edivrem(a, b)
+

Return an array of two elements. The first element is the quotient, +the second is the remainder. The same rounding is done as the +corresponding division operation. +

+
+
sqrt(a)
+

Return \lfloor \sqrt(a) \rfloor. A RangeError exception is +raised if a < 0. +

+
+
sqrtrem(a)
+

Return an array of two elements. The first element is \lfloor +\sqrt{a} \rfloor. The second element is a-\lfloor \sqrt{a} +\rfloor^2. A RangeError exception is raised if a < 0. +

+
+
floorLog2(a)
+

Return -1 if a \leq 0 otherwise return \lfloor \log2(a) \rfloor. +

+
+
ctz(a)
+

Return the number of trailing zeros in the two’s complement binary representation of a. Return -1 if a=0. +

+
+
+ + +

4 BigFloat

+ + +

4.1 Introduction

+ +

This extension adds the BigFloat primitive type. The +BigFloat type represents floating point numbers in base 2 +with the IEEE 754 semantics. A floating +point number is represented as a sign, mantissa and exponent. The +special values NaN, +/-Infinity, +0 and -0 +are supported. The mantissa and exponent can have any bit length with +an implementation specific minimum and maximum. +

+ +

4.2 Floating point rounding

+ +

Each floating point operation operates with infinite precision and +then rounds the result according to the specified floating point +environment (BigFloatEnv object). The status flags of the +environment are also set according to the result of the operation. +

+

If no floating point environment is provided, the global floating +point environment is used. +

+

The rounding mode of the global floating point environment is always +RNDN (“round to nearest with ties to even”)1. The status flags of the global environment cannot be +read2. The precision of the global environment is +BigFloatEnv.prec. The number of exponent bits of the global +environment is BigFloatEnv.expBits. The global environment +subnormal flag is set to true. +

+

For example, prec = 53 and expBits = 11 exactly give +the same precision as the IEEE 754 64 bit floating point format. The +default precision is prec = 113 and expBits = 15 (IEEE +754 128 bit floating point format). +

+

The global floating point environment can only be modified temporarily +when calling a function (see BigFloatEnv.setPrec). Hence a +function can change the global floating point environment for its +callees but not for its caller. +

+ +

4.3 Operators

+ +

The builtin operators are extended so that a BigFloat is returned if +at least one operand is a BigFloat. The computations are always done +with infinite precision and rounded according to the global floating +point environment. +

+

typeof applied on a BigFloat returns bigfloat. +

+

BigFloat can be compared with all the other numeric types and the +result follows the expected mathematical relations. +

+

However, since BigFloat and Number are different types they are never +equal when using the strict comparison operators (e.g. 0.0 === +0.0l is false). +

+ +

4.4 BigFloat literals

+ +

BigFloat literals are floating point numbers with a trailing l +suffix. BigFloat literals have an infinite precision. They are rounded +according to the global floating point environment when they are +evaluated.3 +

+ +

4.5 Builtin Object changes

+ + +

4.5.1 BigFloat function

+ +

The BigFloat function cannot be invoked as a constructor. When +invoked as a function: the parameter is converted to a primitive +type. If the result is a numeric type, it is converted to BigFloat +without rounding. If the result is a string, it is converted to +BigFloat using the precision of the global floating point environment. +

+

BigFloat properties: +

+
+
LN2
+
PI
+

Getter. Return the value of the corresponding mathematical constant +rounded to nearest, ties to even with the current global +precision. The constant values are cached for small precisions. +

+
+
MIN_VALUE
+
MAX_VALUE
+
EPSILON
+

Getter. Return the minimum, maximum and epsilon BigFloat values +(same definition as the corresponding Number constants). +

+
+
fpRound(a[, e])
+

Round the floating point number a according to the floating +point environment e or the global environment if e is +undefined. +

+
+
parseFloat(a[, radix[, e]])
+

Parse the string a as a floating point number in radix +radix. The radix is 0 (default) or from 2 to 36. The radix 0 +means radix 10 unless there is a hexadecimal or binary prefix. The +result is rounded according to the floating point environment e +or the global environment if e is undefined. +

+
+
isFinite(a)
+

Return true if a is a finite bigfloat. +

+
+
isNaN(a)
+

Return true if a is a NaN bigfloat. +

+
+
add(a, b[, e])
+
sub(a, b[, e])
+
mul(a, b[, e])
+
div(a, b[, e])
+

Perform the specified floating point operation and round the floating +point number a according to the floating point environment +e or the global environment if e is undefined. If +e is specified, the floating point status flags are updated. +

+
+
floor(x)
+
ceil(x)
+
round(x)
+
trunc(x)
+

Round to an integer. No additional rounding is performed. +

+
+
abs(x)
+

Return the absolute value of x. No additional rounding is performed. +

+
+
fmod(x, y[, e])
+
remainder(x, y[, e])
+

Floating point remainder. The quotient is truncated to zero (fmod) or +to the nearest integer with ties to even (remainder). e is an +optional floating point environment. +

+
+
sqrt(x[, e])
+

Square root. Return a rounded floating point number. e is an +optional floating point environment. +

+
+
sin(x[, e])
+
cos(x[, e])
+
tan(x[, e])
+
asin(x[, e])
+
acos(x[, e])
+
atan(x[, e])
+
atan2(x, y[, e])
+
exp(x[, e])
+
log(x[, e])
+
pow(x, y[, e])
+

Transcendental operations. Return a rounded floating point +number. e is an optional floating point environment. +

+
+
+ + +

4.5.2 BigFloat.prototype

+ +

The following properties are modified: +

+
+
valueOf()
+

Return the bigfloat primitive value corresponding to this. +

+
+
toString(radix)
+
+

For floating point numbers: +

+
    +
  • If the radix is a power of two, the conversion is done with infinite +precision. +
  • Otherwise, the number is rounded to nearest with ties to even using +the global precision. It is then converted to string using the minimum +number of digits so that its conversion back to a floating point using +the global precision and round to nearest gives the same number. + +
+ +

The exponent letter is e for base 10, p for bases 2, 8, +16 with a binary exponent and @ for the other bases. +

+
+
toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+
toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+
toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10)
+

Same semantics as the corresponding Number functions with +BigFloats. There is no limit on the accepted precision p. The +rounding mode and radix can be optionally specified. The radix must be +between 2 and 36. +

+
+
+ + +

4.5.3 BigFloatEnv constructor

+ +

The BigFloatEnv([p, [,rndMode]] constructor cannot be invoked as a +function. The floating point environment contains: +

+
    +
  • the mantissa precision in bits + +
  • the exponent size in bits assuming an IEEE 754 representation; + +
  • the subnormal flag (if true, subnormal floating point numbers can +be generated by the floating point operations). + +
  • the rounding mode + +
  • the floating point status. The status flags can only be set by the floating point operations. They can be reset with BigFloatEnv.prototype.clearStatus() or with the various status flag setters. + +
+ +

new BigFloatEnv([p, [,rndMode]] creates a new floating point +environment. The status flags are reset. If no parameter is given the +precision, exponent bits and subnormal flags are copied from the +global floating point environment. Otherwise, the precision is set to +p, the number of exponent bits is set to expBitsMax and the +subnormal flags is set to false. If rndMode is +undefined, the rounding mode is set to RNDN. +

+

BigFloatEnv properties: +

+
+
prec
+

Getter. Return the precision in bits of the global floating point +environment. The initial value is 113. +

+
+
expBits
+

Getter. Return the exponent size in bits of the global floating point +environment assuming an IEEE 754 representation. The initial value is +15. +

+
+
setPrec(f, p[, e])
+

Set the precision of the global floating point environment to p +and the exponent size to e then call the function +f. Then the Float precision and exponent size are reset to +their precious value and the return value of f is returned (or +an exception is raised if f raised an exception). If e +is undefined it is set to BigFloatEnv.expBitsMax. +

+
+
precMin
+

Read-only integer. Return the minimum allowed precision. Must be at least 2. +

+
+
precMax
+

Read-only integer. Return the maximum allowed precision. Must be at least 113. +

+
+
expBitsMin
+

Read-only integer. Return the minimum allowed exponent size in +bits. Must be at least 3. +

+
+
expBitsMax
+

Read-only integer. Return the maximum allowed exponent size in +bits. Must be at least 15. +

+
+
RNDN
+

Read-only integer. Round to nearest, with ties to even rounding mode. +

+
+
RNDZ
+

Read-only integer. Round to zero rounding mode. +

+
+
RNDD
+

Read-only integer. Round to -Infinity rounding mode. +

+
+
RNDU
+

Read-only integer. Round to +Infinity rounding mode. +

+
+
RNDNA
+

Read-only integer. Round to nearest, with ties away from zero rounding mode. +

+
+
RNDA
+

Read-only integer. Round away from zero rounding mode. +

+
+
RNDF4
+

Read-only integer. Faithful rounding mode. The result is +non-deterministically rounded to -Infinity or +Infinity. This rounding +mode usually gives a faster and deterministic running time for the +floating point operations. +

+
+
+ +

BigFloatEnv.prototype properties: +

+
+
prec
+

Getter and setter (Integer). Return or set the precision in bits. +

+
+
expBits
+

Getter and setter (Integer). Return or set the exponent size in bits +assuming an IEEE 754 representation. +

+
+
rndMode
+

Getter and setter (Integer). Return or set the rounding mode. +

+
+
subnormal
+

Getter and setter (Boolean). subnormal flag. It is false when +expBits = expBitsMax. +

+
+
clearStatus()
+

Clear the status flags. +

+
+
invalidOperation
+
divideByZero
+
overflow
+
underflow
+
inexact
+

Getter and setter (Boolean). Status flags. +

+
+
+ + +

5 BigDecimal

+ +

This extension adds the BigDecimal primitive type. The +BigDecimal type represents floating point numbers in base +10. It is inspired from the proposal available at +https://github.com/littledan/proposal-bigdecimal. +

+

The BigDecimal floating point numbers are always normalized and +finite. There is no concept of -0, Infinity or +NaN. By default, all the computations are done with infinite +precision. +

+ +

5.1 Operators

+ +

The following builtin operators support BigDecimal: +

+
+
+
+
-
+
*
+

Both operands must be BigDecimal. The result is computed with infinite +precision. +

+
%
+

Both operands must be BigDecimal. The result is computed with infinite +precision. A range error is throws in case of division by zero. +

+
+
/
+

Both operands must be BigDecimal. A range error is throws in case of +division by zero or if the result cannot be represented with infinite +precision (use BigDecimal.div to specify the rounding). +

+
+
**
+

Both operands must be BigDecimal. The exponent must be a positive +integer. The result is computed with infinite precision. +

+
+
===
+

When one of the operand is a BigDecimal, return true if both operands +are a BigDecimal and if they are equal. +

+
+
==
+
!=
+
<=
+
>=
+
<
+
>
+
+

Numerical comparison. When one of the operand is not a BigDecimal, it is +converted to BigDecimal by using ToString(). Hence comparisons between +Number and BigDecimal do not use the exact mathematical value of the +Number value. +

+
+
+ + +

5.2 BigDecimal literals

+ +

BigDecimal literals are decimal floating point numbers with a trailing +m suffix. +

+ +

5.3 Builtin Object changes

+ + +

5.3.1 The BigDecimal function.

+ +

It returns 0m if no parameter is provided. Otherwise the first +parameter is converted to a bigdecimal by using ToString(). Hence +Number values are not converted to their exact numerical value as +BigDecimal. +

+ +

5.3.2 Properties of the BigDecimal object

+ +
+
add(a, b[, e])
+
sub(a, b[, e])
+
mul(a, b[, e])
+
div(a, b[, e])
+
mod(a, b[, e])
+
sqrt(a, e)
+
round(a, e)
+

Perform the specified floating point operation and round the floating +point result according to the rounding object e. If the +rounding object is not present, the operation is executed with +infinite precision. +

+

For div, a RangeError exception is thrown in case of +division by zero or if the result cannot be represented with infinite +precision if no rounding object is present. +

+

For sqrt, a range error is thrown if a is less than +zero. +

+

The rounding object must contain the following properties: +roundingMode is a string specifying the rounding mode +("floor", "ceiling", "down", "up", +"half-even", "half-up"). Either +maximumSignificantDigits or maximumFractionDigits must +be present to specify respectively the number of significant digits +(must be >= 1) or the number of digits after the decimal point (must +be >= 0). +

+
+
+ + +

5.3.3 Properties of the BigDecimal.prototype object

+ +
+
valueOf()
+

Return the bigdecimal primitive value corresponding to this. +

+
+
toString()
+

Convert this to a string with infinite precision in base 10. +

+
+
toPrecision(p, rnd_mode = "half-up")
+
toFixed(p, rnd_mode = "half-up")
+
toExponential(p, rnd_mode = "half-up")
+

Convert the BigDecimal this to string with the specified +precision p. There is no limit on the accepted precision +p. The rounding mode can be optionally +specified. toPrecision outputs either in decimal fixed notation +or in decimal exponential notation with a p digits of +precision. toExponential outputs in decimal exponential +notation with p digits after the decimal point. toFixed +outputs in decimal notation with p digits after the decimal +point. +

+
+
+ + +

6 Math mode

+ +

A new math mode is enabled with the "use math" +directive. It propagates the same way as the strict mode. It is +designed so that arbitrarily large integers and floating point numbers +are available by default. In order to minimize the number of changes +in the Javascript semantics, integers are represented either as Number +or BigInt depending on their magnitude. Floating point numbers are +always represented as BigFloat. +

+

The following changes are made to the Javascript semantics: +

+
    +
  • Floating point literals (i.e. number with a decimal point or an exponent) are BigFloat by default (i.e. a l suffix is implied). Hence typeof 1.0 === "bigfloat". + +
  • Integer literals (i.e. numbers without a decimal point or an exponent) with or without the n suffix are BigInt if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to 2**53-1. Hence typeof 1 === "number ", typeof 1n === "number" but typeof 9007199254740992 === "bigint" . + +
  • All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt. + +
  • The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result. + +
  • The ^ operator is an alias to the power operator (**). + +
  • The power operator (both ^ and **) grammar is modified so that -2^2 is allowed and yields -4. + +
  • The logical xor operator is still available with the ^^ operator. + +
  • The modulo operator (%) returns the Euclidian remainder (always positive) instead of the truncated remainder. + +
  • The integer division operator can be overloaded with Operators.updateBigIntOperators(dictionary). + +
  • The integer power operator with a non zero negative exponent can be overloaded with Operators.updateBigIntOperators(dictionary). + +
+ +
+
+

Footnotes

+ +

(1)

+

The +rationale is that the rounding mode changes must always be +explicit.

+

(2)

+

The rationale is to avoid side effects for the built-in +operators.

+

(3)

+

Base 10 floating point literals cannot usually be +exactly represented as base 2 floating point number. In order to +ensure that the literal is represented accurately with the current +precision, it must be evaluated at runtime.

+

(4)

+

Could be removed in case a deterministic behavior for floating point operations is required.

+
+
+ + + + + diff --git a/deps/quickjs/doc/jsbignum.pdf b/deps/quickjs/doc/jsbignum.pdf new file mode 100644 index 0000000..442a8c0 Binary files /dev/null and b/deps/quickjs/doc/jsbignum.pdf differ diff --git a/deps/quickjs/doc/jsbignum.texi b/deps/quickjs/doc/jsbignum.texi new file mode 100644 index 0000000..079d920 --- /dev/null +++ b/deps/quickjs/doc/jsbignum.texi @@ -0,0 +1,589 @@ +\input texinfo + +@iftex +@afourpaper +@headings double +@end iftex + +@titlepage +@afourpaper +@sp 7 +@center @titlefont{Javascript Bignum Extensions} +@sp 3 +@center Version 2020-01-11 +@sp 3 +@center Author: Fabrice Bellard +@end titlepage + +@setfilename jsbignum.info +@settitle Javascript Bignum Extensions + +@contents + +@chapter Introduction + +The Bignum extensions add the following features to the Javascript +language while being 100% backward compatible: + +@itemize + +@item Operator overloading with a dispatch logic inspired from the proposal available at @url{https://github.com/tc39/proposal-operator-overloading/}. + +@item Arbitrarily large floating point numbers (@code{BigFloat}) in base 2 using the IEEE 754 semantics. + +@item Arbitrarily large floating point numbers (@code{BigDecimal}) in base 10 based on the proposal available at +@url{https://github.com/littledan/proposal-bigdecimal}. + +@item @code{math} mode: arbitrarily large integers and floating point numbers are available by default. The integer division and power can be overloaded for example to return a fraction. The modulo operator (@code{%}) is defined as the Euclidian +remainder. @code{^} is an alias to the power operator +(@code{**}). @code{^^} is used as the exclusive or operator. + +@end itemize + +The extensions are independent from each other except the @code{math} +mode which relies on BigFloat and operator overloading. + +@chapter Operator overloading + +Operator overloading is inspired from the proposal available at +@url{https://github.com/tc39/proposal-operator-overloading/}. It +implements the same dispatch logic but finds the operator sets by +looking at the @code{Symbol.operatorSet} property in the objects. The +changes were done in order to simplify the implementation. + +More precisely, the following modifications were made: + +@itemize + +@item @code{with operators from} is not supported. Operator overloading is always enabled. + +@item The dispatch is not based on a static @code{[[OperatorSet]]} field in all instances. Instead, a dynamic lookup of the @code{Symbol.operatorSet} property is done. This property is typically added in the prototype of each object. + +@item @code{Operators.create(...dictionaries)} is used to create a new OperatorSet object. The @code{Operators} function is supported as an helper to be closer to the TC39 proposal. + +@item @code{[]} cannot be overloaded. + +@item In math mode, the BigInt division and power operators can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. + +@end itemize + +@chapter BigInt extensions + +A few properties are added to the BigInt object: + +@table @code + +@item tdiv(a, b) +Return @math{trunc(a/b)}. @code{b = 0} raises a RangeError +exception. + +@item fdiv(a, b) +Return @math{\lfloor a/b \rfloor}. @code{b = 0} raises a RangeError +exception. + +@item cdiv(a, b) +Return @math{\lceil a/b \rceil}. @code{b = 0} raises a RangeError +exception. + +@item ediv(a, b) +Return @math{sgn(b) \lfloor a/{|b|} \rfloor} (Euclidian +division). @code{b = 0} raises a RangeError exception. + +@item tdivrem(a, b) +@item fdivrem(a, b) +@item cdivrem(a, b) +@item edivrem(a, b) +Return an array of two elements. The first element is the quotient, +the second is the remainder. The same rounding is done as the +corresponding division operation. + +@item sqrt(a) +Return @math{\lfloor \sqrt(a) \rfloor}. A RangeError exception is +raised if @math{a < 0}. + +@item sqrtrem(a) +Return an array of two elements. The first element is @math{\lfloor +\sqrt{a} \rfloor}. The second element is @math{a-\lfloor \sqrt{a} +\rfloor^2}. A RangeError exception is raised if @math{a < 0}. + +@item floorLog2(a) +Return -1 if @math{a \leq 0} otherwise return @math{\lfloor \log2(a) \rfloor}. + +@item ctz(a) +Return the number of trailing zeros in the two's complement binary representation of a. Return -1 if @math{a=0}. + +@end table + +@chapter BigFloat + +@section Introduction + +This extension adds the @code{BigFloat} primitive type. The +@code{BigFloat} type represents floating point numbers in base 2 +with the IEEE 754 semantics. A floating +point number is represented as a sign, mantissa and exponent. The +special values @code{NaN}, @code{+/-Infinity}, @code{+0} and @code{-0} +are supported. The mantissa and exponent can have any bit length with +an implementation specific minimum and maximum. + +@section Floating point rounding + +Each floating point operation operates with infinite precision and +then rounds the result according to the specified floating point +environment (@code{BigFloatEnv} object). The status flags of the +environment are also set according to the result of the operation. + +If no floating point environment is provided, the global floating +point environment is used. + +The rounding mode of the global floating point environment is always +@code{RNDN} (``round to nearest with ties to even'')@footnote{The +rationale is that the rounding mode changes must always be +explicit.}. The status flags of the global environment cannot be +read@footnote{The rationale is to avoid side effects for the built-in +operators.}. The precision of the global environment is +@code{BigFloatEnv.prec}. The number of exponent bits of the global +environment is @code{BigFloatEnv.expBits}. The global environment +subnormal flag is set to @code{true}. + +For example, @code{prec = 53} and @code{ expBits = 11} exactly give +the same precision as the IEEE 754 64 bit floating point format. The +default precision is @code{prec = 113} and @code{ expBits = 15} (IEEE +754 128 bit floating point format). + +The global floating point environment can only be modified temporarily +when calling a function (see @code{BigFloatEnv.setPrec}). Hence a +function can change the global floating point environment for its +callees but not for its caller. + +@section Operators + +The builtin operators are extended so that a BigFloat is returned if +at least one operand is a BigFloat. The computations are always done +with infinite precision and rounded according to the global floating +point environment. + +@code{typeof} applied on a @code{BigFloat} returns @code{bigfloat}. + +BigFloat can be compared with all the other numeric types and the +result follows the expected mathematical relations. + +However, since BigFloat and Number are different types they are never +equal when using the strict comparison operators (e.g. @code{0.0 === +0.0l} is false). + +@section BigFloat literals + +BigFloat literals are floating point numbers with a trailing @code{l} +suffix. BigFloat literals have an infinite precision. They are rounded +according to the global floating point environment when they are +evaluated.@footnote{Base 10 floating point literals cannot usually be +exactly represented as base 2 floating point number. In order to +ensure that the literal is represented accurately with the current +precision, it must be evaluated at runtime.} + +@section Builtin Object changes + +@subsection @code{BigFloat} function + +The @code{BigFloat} function cannot be invoked as a constructor. When +invoked as a function: the parameter is converted to a primitive +type. If the result is a numeric type, it is converted to BigFloat +without rounding. If the result is a string, it is converted to +BigFloat using the precision of the global floating point environment. + +@code{BigFloat} properties: + +@table @code + +@item LN2 +@item PI +Getter. Return the value of the corresponding mathematical constant +rounded to nearest, ties to even with the current global +precision. The constant values are cached for small precisions. + +@item MIN_VALUE +@item MAX_VALUE +@item EPSILON +Getter. Return the minimum, maximum and epsilon @code{BigFloat} values +(same definition as the corresponding @code{Number} constants). + +@item fpRound(a[, e]) +Round the floating point number @code{a} according to the floating +point environment @code{e} or the global environment if @code{e} is +undefined. + +@item parseFloat(a[, radix[, e]]) +Parse the string @code{a} as a floating point number in radix +@code{radix}. The radix is 0 (default) or from 2 to 36. The radix 0 +means radix 10 unless there is a hexadecimal or binary prefix. The +result is rounded according to the floating point environment @code{e} +or the global environment if @code{e} is undefined. + +@item isFinite(a) +Return true if @code{a} is a finite bigfloat. + +@item isNaN(a) +Return true if @code{a} is a NaN bigfloat. + +@item add(a, b[, e]) +@item sub(a, b[, e]) +@item mul(a, b[, e]) +@item div(a, b[, e]) +Perform the specified floating point operation and round the floating +point number @code{a} according to the floating point environment +@code{e} or the global environment if @code{e} is undefined. If +@code{e} is specified, the floating point status flags are updated. + +@item floor(x) +@item ceil(x) +@item round(x) +@item trunc(x) +Round to an integer. No additional rounding is performed. + +@item abs(x) +Return the absolute value of x. No additional rounding is performed. + +@item fmod(x, y[, e]) +@item remainder(x, y[, e]) +Floating point remainder. The quotient is truncated to zero (fmod) or +to the nearest integer with ties to even (remainder). @code{e} is an +optional floating point environment. + +@item sqrt(x[, e]) +Square root. Return a rounded floating point number. @code{e} is an +optional floating point environment. + +@item sin(x[, e]) +@item cos(x[, e]) +@item tan(x[, e]) +@item asin(x[, e]) +@item acos(x[, e]) +@item atan(x[, e]) +@item atan2(x, y[, e]) +@item exp(x[, e]) +@item log(x[, e]) +@item pow(x, y[, e]) +Transcendental operations. Return a rounded floating point +number. @code{e} is an optional floating point environment. + +@end table + +@subsection @code{BigFloat.prototype} + +The following properties are modified: + +@table @code +@item valueOf() +Return the bigfloat primitive value corresponding to @code{this}. + +@item toString(radix) + +For floating point numbers: + +@itemize +@item +If the radix is a power of two, the conversion is done with infinite +precision. +@item +Otherwise, the number is rounded to nearest with ties to even using +the global precision. It is then converted to string using the minimum +number of digits so that its conversion back to a floating point using +the global precision and round to nearest gives the same number. + +@end itemize + +The exponent letter is @code{e} for base 10, @code{p} for bases 2, 8, +16 with a binary exponent and @code{@@} for the other bases. + +@item toPrecision(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) +@item toFixed(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) +@item toExponential(p, rnd_mode = BigFloatEnv.RNDNA, radix = 10) +Same semantics as the corresponding @code{Number} functions with +BigFloats. There is no limit on the accepted precision @code{p}. The +rounding mode and radix can be optionally specified. The radix must be +between 2 and 36. + +@end table + +@subsection @code{BigFloatEnv} constructor + +The @code{BigFloatEnv([p, [,rndMode]]} constructor cannot be invoked as a +function. The floating point environment contains: + +@itemize +@item the mantissa precision in bits + +@item the exponent size in bits assuming an IEEE 754 representation; + +@item the subnormal flag (if true, subnormal floating point numbers can +be generated by the floating point operations). + +@item the rounding mode + +@item the floating point status. The status flags can only be set by the floating point operations. They can be reset with @code{BigFloatEnv.prototype.clearStatus()} or with the various status flag setters. + +@end itemize + +@code{new BigFloatEnv([p, [,rndMode]]} creates a new floating point +environment. The status flags are reset. If no parameter is given the +precision, exponent bits and subnormal flags are copied from the +global floating point environment. Otherwise, the precision is set to +@code{p}, the number of exponent bits is set to @code{expBitsMax} and the +subnormal flags is set to @code{false}. If @code{rndMode} is +@code{undefined}, the rounding mode is set to @code{RNDN}. + +@code{BigFloatEnv} properties: + +@table @code + +@item prec +Getter. Return the precision in bits of the global floating point +environment. The initial value is @code{113}. + +@item expBits +Getter. Return the exponent size in bits of the global floating point +environment assuming an IEEE 754 representation. The initial value is +@code{15}. + +@item setPrec(f, p[, e]) +Set the precision of the global floating point environment to @code{p} +and the exponent size to @code{e} then call the function +@code{f}. Then the Float precision and exponent size are reset to +their precious value and the return value of @code{f} is returned (or +an exception is raised if @code{f} raised an exception). If @code{e} +is @code{undefined} it is set to @code{BigFloatEnv.expBitsMax}. + +@item precMin +Read-only integer. Return the minimum allowed precision. Must be at least 2. + +@item precMax +Read-only integer. Return the maximum allowed precision. Must be at least 113. + +@item expBitsMin +Read-only integer. Return the minimum allowed exponent size in +bits. Must be at least 3. + +@item expBitsMax +Read-only integer. Return the maximum allowed exponent size in +bits. Must be at least 15. + +@item RNDN +Read-only integer. Round to nearest, with ties to even rounding mode. + +@item RNDZ +Read-only integer. Round to zero rounding mode. + +@item RNDD +Read-only integer. Round to -Infinity rounding mode. + +@item RNDU +Read-only integer. Round to +Infinity rounding mode. + +@item RNDNA +Read-only integer. Round to nearest, with ties away from zero rounding mode. + +@item RNDA +Read-only integer. Round away from zero rounding mode. + +@item RNDF@footnote{Could be removed in case a deterministic behavior for floating point operations is required.} +Read-only integer. Faithful rounding mode. The result is +non-deterministically rounded to -Infinity or +Infinity. This rounding +mode usually gives a faster and deterministic running time for the +floating point operations. + +@end table + +@code{BigFloatEnv.prototype} properties: + +@table @code + +@item prec +Getter and setter (Integer). Return or set the precision in bits. + +@item expBits +Getter and setter (Integer). Return or set the exponent size in bits +assuming an IEEE 754 representation. + +@item rndMode +Getter and setter (Integer). Return or set the rounding mode. + +@item subnormal +Getter and setter (Boolean). subnormal flag. It is false when +@code{expBits = expBitsMax}. + +@item clearStatus() +Clear the status flags. + +@item invalidOperation +@item divideByZero +@item overflow +@item underflow +@item inexact +Getter and setter (Boolean). Status flags. + +@end table + +@chapter BigDecimal + +This extension adds the @code{BigDecimal} primitive type. The +@code{BigDecimal} type represents floating point numbers in base +10. It is inspired from the proposal available at +@url{https://github.com/littledan/proposal-bigdecimal}. + +The @code{BigDecimal} floating point numbers are always normalized and +finite. There is no concept of @code{-0}, @code{Infinity} or +@code{NaN}. By default, all the computations are done with infinite +precision. + +@section Operators + +The following builtin operators support BigDecimal: + +@table @code + +@item + +@item - +@item * +Both operands must be BigDecimal. The result is computed with infinite +precision. +@item % +Both operands must be BigDecimal. The result is computed with infinite +precision. A range error is throws in case of division by zero. + +@item / +Both operands must be BigDecimal. A range error is throws in case of +division by zero or if the result cannot be represented with infinite +precision (use @code{BigDecimal.div} to specify the rounding). + +@item ** +Both operands must be BigDecimal. The exponent must be a positive +integer. The result is computed with infinite precision. + +@item === +When one of the operand is a BigDecimal, return true if both operands +are a BigDecimal and if they are equal. + +@item == +@item != +@item <= +@item >= +@item < +@item > + +Numerical comparison. When one of the operand is not a BigDecimal, it is +converted to BigDecimal by using ToString(). Hence comparisons between +Number and BigDecimal do not use the exact mathematical value of the +Number value. + +@end table + +@section BigDecimal literals + +BigDecimal literals are decimal floating point numbers with a trailing +@code{m} suffix. + +@section Builtin Object changes + +@subsection The @code{BigDecimal} function. + +It returns @code{0m} if no parameter is provided. Otherwise the first +parameter is converted to a bigdecimal by using ToString(). Hence +Number values are not converted to their exact numerical value as +BigDecimal. + +@subsection Properties of the @code{BigDecimal} object + +@table @code + +@item add(a, b[, e]) +@item sub(a, b[, e]) +@item mul(a, b[, e]) +@item div(a, b[, e]) +@item mod(a, b[, e]) +@item sqrt(a, e) +@item round(a, e) +Perform the specified floating point operation and round the floating +point result according to the rounding object @code{e}. If the +rounding object is not present, the operation is executed with +infinite precision. + +For @code{div}, a @code{RangeError} exception is thrown in case of +division by zero or if the result cannot be represented with infinite +precision if no rounding object is present. + +For @code{sqrt}, a range error is thrown if @code{a} is less than +zero. + +The rounding object must contain the following properties: +@code{roundingMode} is a string specifying the rounding mode +(@code{"floor"}, @code{"ceiling"}, @code{"down"}, @code{"up"}, +@code{"half-even"}, @code{"half-up"}). Either +@code{maximumSignificantDigits} or @code{maximumFractionDigits} must +be present to specify respectively the number of significant digits +(must be >= 1) or the number of digits after the decimal point (must +be >= 0). + +@end table + +@subsection Properties of the @code{BigDecimal.prototype} object + +@table @code +@item valueOf() +Return the bigdecimal primitive value corresponding to @code{this}. + +@item toString() +Convert @code{this} to a string with infinite precision in base 10. + +@item toPrecision(p, rnd_mode = "half-up") +@item toFixed(p, rnd_mode = "half-up") +@item toExponential(p, rnd_mode = "half-up") +Convert the BigDecimal @code{this} to string with the specified +precision @code{p}. There is no limit on the accepted precision +@code{p}. The rounding mode can be optionally +specified. @code{toPrecision} outputs either in decimal fixed notation +or in decimal exponential notation with a @code{p} digits of +precision. @code{toExponential} outputs in decimal exponential +notation with @code{p} digits after the decimal point. @code{toFixed} +outputs in decimal notation with @code{p} digits after the decimal +point. + +@end table + +@chapter Math mode + +A new @emph{math mode} is enabled with the @code{"use math"} +directive. It propagates the same way as the @emph{strict mode}. It is +designed so that arbitrarily large integers and floating point numbers +are available by default. In order to minimize the number of changes +in the Javascript semantics, integers are represented either as Number +or BigInt depending on their magnitude. Floating point numbers are +always represented as BigFloat. + +The following changes are made to the Javascript semantics: + +@itemize + +@item Floating point literals (i.e. number with a decimal point or an exponent) are @code{BigFloat} by default (i.e. a @code{l} suffix is implied). Hence @code{typeof 1.0 === "bigfloat"}. + +@item Integer literals (i.e. numbers without a decimal point or an exponent) with or without the @code{n} suffix are @code{BigInt} if their value cannot be represented as a safe integer. A safe integer is defined as a integer whose absolute value is smaller or equal to @code{2**53-1}. Hence @code{typeof 1 === "number "}, @code{typeof 1n === "number"} but @code{typeof 9007199254740992 === "bigint" }. + +@item All the bigint builtin operators and functions are modified so that their result is returned as a Number if it is a safe integer. Otherwise the result stays a BigInt. + +@item The builtin operators are modified so that they return an exact result (which can be a BigInt) if their operands are safe integers. Operands between Number and BigInt are accepted provided the Number operand is a safe integer. The integer power with a negative exponent returns a BigFloat as result. The integer division returns a BigFloat as result. + +@item The @code{^} operator is an alias to the power operator (@code{**}). + +@item The power operator (both @code{^} and @code{**}) grammar is modified so that @code{-2^2} is allowed and yields @code{-4}. + +@item The logical xor operator is still available with the @code{^^} operator. + +@item The modulo operator (@code{%}) returns the Euclidian remainder (always positive) instead of the truncated remainder. + +@item The integer division operator can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. + +@item The integer power operator with a non zero negative exponent can be overloaded with @code{Operators.updateBigIntOperators(dictionary)}. + +@end itemize + +@bye diff --git a/deps/quickjs/doc/quickjs.html b/deps/quickjs/doc/quickjs.html new file mode 100644 index 0000000..1ac9c54 --- /dev/null +++ b/deps/quickjs/doc/quickjs.html @@ -0,0 +1,1410 @@ + + + + +QuickJS Javascript Engine + + + + + + + + + + + + + + + +

QuickJS Javascript Engine

+ + +

Table of Contents

+ + + + + +

1 Introduction

+ +

QuickJS is a small and embeddable Javascript engine. It supports most of the +ES2023 specification +1 +including modules, asynchronous generators, proxies and BigInt. +

+

It supports mathematical extensions such as big decimal float float +numbers (BigDecimal), big binary floating point numbers (BigFloat), +and operator overloading. +

+ +

1.1 Main Features

+ +
    +
  • Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple “hello world” program. + +
  • Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite2 in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. + +
  • Almost complete ES2023 support including modules, asynchronous +generators and full Annex B support (legacy web compatibility). Some +features from the upcoming ES2024 specification +3 are also supported. + +
  • Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features. + +
  • Compile Javascript sources to executables with no external dependency. + +
  • Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal. + +
  • Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode. + +
  • Command line interpreter with contextual colorization and completion implemented in Javascript. + +
  • Small built-in standard library with C library wrappers. + +
+ + +

2 Usage

+ + +

2.1 Installation

+ +

A Makefile is provided to compile the engine on Linux or MacOS/X. A +preliminary Windows support is available thru cross compilation on a +Linux host with the MingGW tools. +

+

Edit the top of the Makefile if you wish to select specific +options then run make. +

+

You can type make install as root if you wish to install the binaries and support files to +/usr/local (this is not necessary to use QuickJS). +

+

Note: On some OSes atomic operations are not available or need a +specific library. If you get related errors, you should either add +-latomics in the Makefile LIBS variable or disable +CONFIG_ATOMICS in quickjs.c. +

+ +

2.2 Quick start

+ +

qjs is the command line interpreter (Read-Eval-Print Loop). You can pass +Javascript files and/or expressions as arguments to execute them: +

+
+
./qjs examples/hello.js
+
+ +

qjsc is the command line compiler: +

+
+
./qjsc -o hello examples/hello.js
+./hello
+
+ +

generates a hello executable with no external dependency. +

+ +

2.3 Command line options

+ + +

2.3.1 qjs interpreter

+ +
usage: qjs [options] [file [args]]
+
+

Options are: +

+
-h
+
--help
+

List options. +

+
+
-e EXPR
+
--eval EXPR
+

Evaluate EXPR. +

+
+
-i
+
--interactive
+

Go to interactive mode (it is not the default when files are provided on the command line). +

+
+
-m
+
--module
+

Load as ES6 module (default=autodetect). A module is autodetected if +the filename extension is .mjs or if the first keyword of the +source is import. +

+
+
--script
+

Load as ES6 script (default=autodetect). +

+
+
--bignum
+

Enable the bignum extensions: BigDecimal object, BigFloat object and +the "use math" directive. +

+
+
-I file
+
--include file
+

Include an additional file. +

+
+
+ +

Advanced options are: +

+
+
--std
+

Make the std and os modules available to the loaded +script even if it is not a module. +

+
+
-d
+
--dump
+

Dump the memory usage stats. +

+
+
-q
+
--quit
+

just instantiate the interpreter and quit. +

+
+
+ + +

2.3.2 qjsc compiler

+ +
usage: qjsc [options] [files]
+
+

Options are: +

+
-c
+

Only output bytecode in a C file. The default is to output an executable file. +

+
-e
+

Output main() and bytecode in a C file. The default is to output an +executable file. +

+
-o output
+

Set the output filename (default = out.c or a.out). +

+
+
-N cname
+

Set the C name of the generated data. +

+
+
-m
+

Compile as Javascript module (default=autodetect). +

+
+
-D module_name
+

Compile a dynamically loaded module and its dependencies. This option +is needed when your code uses the import keyword or the +os.Worker constructor because the compiler cannot statically +find the name of the dynamically loaded modules. +

+
+
-M module_name[,cname]
+

Add initialization code for an external C module. See the +c_module example. +

+
+
-x
+

Byte swapped output (only used for cross compilation). +

+
+
-flto
+

Use link time optimization. The compilation is slower but the +executable is smaller and faster. This option is automatically set +when the -fno-x options are used. +

+
+
-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]
+

Disable selected language features to produce a smaller executable file. +

+
+
-fbignum
+

Enable the bignum extensions: BigDecimal object, BigFloat object and +the "use math" directive. +

+
+
+ + +

2.4 qjscalc application

+ +

The qjscalc application is a superset of the qjs +command line interpreter implementing a Javascript calculator with +arbitrarily large integer and floating point numbers, fractions, +complex numbers, polynomials and matrices. The source code is in +qjscalc.js. More documentation and a web version are available at +http://numcalc.com. +

+ +

2.5 Built-in tests

+ +

Run make test to run the few built-in tests included in the +QuickJS archive. +

+ +

2.6 Test262 (ECMAScript Test Suite)

+ +

A test262 runner is included in the QuickJS archive. The test262 tests +can be installed in the QuickJS source directory with: +

+
+
git clone https://github.com/tc39/test262.git test262
+cd test262
+patch -p1 < ../tests/test262.patch
+cd ..
+
+ +

The patch adds the implementation specific harness functions +and optimizes the inefficient RegExp character classes and Unicode +property escapes tests (the tests themselves are not modified, only a +slow string initialization function is optimized). +

+

The tests can be run with +

+
make test2
+
+ +

The configuration files test262.conf +(resp. test262o.conf for the old ES5.1 tests4)) +contain the options to run the various tests. Tests can be excluded +based on features or filename. +

+

The file test262_errors.txt contains the current list of +errors. The runner displays a message when a new error appears or when +an existing error is corrected or modified. Use the -u option +to update the current list of errors (or make test2-update). +

+

The file test262_report.txt contains the logs of all the +tests. It is useful to have a clearer analysis of a particular +error. In case of crash, the last line corresponds to the failing +test. +

+

Use the syntax ./run-test262 -c test262.conf -f filename.js to +run a single test. Use the syntax ./run-test262 -c test262.conf +N to start testing at test number N. +

+

For more information, run ./run-test262 to see the command line +options of the test262 runner. +

+

run-test262 accepts the -N option to be invoked from +test262-harness5 +thru eshost. Unless you want to compare QuickJS with other +engines under the same conditions, we do not recommend to run the +tests this way as it is much slower (typically half an hour instead of +about 100 seconds). +

+ +

3 Specifications

+ + +

3.1 Language support

+ + +

3.1.1 ES2023 support

+ +

The ES2023 specification is almost fully supported including the Annex +B (legacy web compatibility) and the Unicode related features. +

+

The following features are not supported yet: +

+
    +
  • Tail calls6 + +
  • WeakRef and FinalizationRegistry objects + +
  • Symbols as WeakMap keys + +
+ + +

3.1.2 ECMA402

+ +

ECMA402 (Internationalization API) is not supported. +

+ +

3.1.3 Extensions

+ +
    +
  • The directive "use strip" indicates that the debug information (including the source code of the functions) should not be retained to save memory. As "use strict", the directive can be global to a script or local to a function. + +
  • The first line of a script beginning with #! is ignored. + +
+ + +

3.1.4 Mathematical extensions

+ +

The mathematical extensions are fully backward compatible with +standard Javascript. See jsbignum.pdf for more information. +

+
    +
  • BigDecimal support: arbitrary large floating point numbers in base 10. + +
  • BigFloat support: arbitrary large floating point numbers in base 2. + +
  • Operator overloading. + +
  • The directive "use bigint" enables the bigint mode where integers are BigInt by default. + +
  • The directive "use math" enables the math mode where the division and power operators on integers produce fractions. Floating point literals are BigFloat by default and integers are BigInt by default. + +
+ + +

3.2 Modules

+ +

ES6 modules are fully supported. The default name resolution is the +following: +

+
    +
  • Module names with a leading . or .. are relative +to the current module path. + +
  • Module names without a leading . or .. are system +modules, such as std or os. + +
  • Module names ending with .so are native modules using the +QuickJS C API. + +
+ + +

3.3 Standard library

+ +

The standard library is included by default in the command line +interpreter. It contains the two modules std and os and +a few global objects. +

+ +

3.3.1 Global objects

+ +
+
scriptArgs
+

Provides the command line arguments. The first argument is the script name. +

+
print(...args)
+

Print the arguments separated by spaces and a trailing newline. +

+
console.log(...args)
+

Same as print(). +

+
+
+ + +

3.3.2 std module

+ +

The std module provides wrappers to the libc stdlib.h +and stdio.h and a few other utilities. +

+

Available exports: +

+
+
exit(n)
+

Exit the process. +

+
+
evalScript(str, options = undefined)
+

Evaluate the string str as a script (global +eval). options is an optional object containing the following +optional properties: +

+
+
backtrace_barrier
+

Boolean (default = false). If true, error backtraces do not list the + stack frames below the evalScript. +

+
async
+

Boolean (default = false). If true, await is accepted in the + script and a promise is returned. +

+
+ +
+
loadScript(filename)
+

Evaluate the file filename as a script (global eval). +

+
+
loadFile(filename)
+

Load the file filename and return it as a string assuming UTF-8 +encoding. Return null in case of I/O error. +

+
+
open(filename, flags, errorObj = undefined)
+

Open a file (wrapper to the libc fopen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
popen(command, flags, errorObj = undefined)
+

Open a process by creating a pipe (wrapper to the libc +popen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
fdopen(fd, flags, errorObj = undefined)
+

Open a file from a file handle (wrapper to the libc +fdopen()). Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
tmpfile(errorObj = undefined)
+

Open a temporary file. Return the FILE +object or null in case of I/O error. If errorObj is not +undefined, set its errno property to the error code or to 0 if +no error occured. +

+
+
puts(str)
+

Equivalent to std.out.puts(str). +

+
+
printf(fmt, ...args)
+

Equivalent to std.out.printf(fmt, ...args). +

+
+
sprintf(fmt, ...args)
+

Equivalent to the libc sprintf(). +

+
+
in
+
out
+
err
+

Wrappers to the libc file stdin, stdout, stderr. +

+
+
SEEK_SET
+
SEEK_CUR
+
SEEK_END
+

Constants for seek(). +

+
+
Error
+
+

Enumeration object containing the integer value of common errors +(additional error codes may be defined): +

+
+
EINVAL
+
EIO
+
EACCES
+
EEXIST
+
ENOSPC
+
ENOSYS
+
EBUSY
+
ENOENT
+
EPERM
+
EPIPE
+
+ +
+
strerror(errno)
+

Return a string that describes the error errno. +

+
+
gc()
+

Manually invoke the cycle removal algorithm. The cycle removal +algorithm is automatically started when needed, so this function is +useful in case of specific memory constraints or for testing. +

+
+
getenv(name)
+

Return the value of the environment variable name or +undefined if it is not defined. +

+
+
setenv(name, value)
+

Set the value of the environment variable name to the string +value. +

+
+
unsetenv(name)
+

Delete the environment variable name. +

+
+
getenviron()
+

Return an object containing the environment variables as key-value pairs. +

+
+
urlGet(url, options = undefined)
+
+

Download url using the curl command line +utility. options is an optional object containing the following +optional properties: +

+
+
binary
+

Boolean (default = false). If true, the response is an ArrayBuffer + instead of a string. When a string is returned, the data is assumed + to be UTF-8 encoded. +

+
+
full
+
+

Boolean (default = false). If true, return the an object contains + the properties response (response content), + responseHeaders (headers separated by CRLF), status + (status code). response is null is case of protocol or + network error. If full is false, only the response is + returned if the status is between 200 and 299. Otherwise null + is returned. +

+
+
+ +
+
parseExtJSON(str)
+
+

Parse str using a superset of JSON.parse. The + following extensions are accepted: +

+
    +
  • Single line and multiline comments +
  • unquoted properties (ASCII-only Javascript identifiers) +
  • trailing comma in array and object definitions +
  • single quoted strings +
  • \f and \v are accepted as space characters +
  • leading plus in numbers +
  • octal (0o prefix) and hexadecimal (0x prefix) numbers +
+
+
+ +

FILE prototype: +

+
+
close()
+

Close the file. Return 0 if OK or -errno in case of I/O error. +

+
puts(str)
+

Outputs the string with the UTF-8 encoding. +

+
printf(fmt, ...args)
+

Formatted printf. +

+

The same formats as the standard C library printf are +supported. Integer format types (e.g. %d) truncate the Numbers +or BigInts to 32 bits. Use the l modifier (e.g. %ld) to +truncate to 64 bits. +

+
+
flush()
+

Flush the buffered file. +

+
seek(offset, whence)
+

Seek to a give file position (whence is +std.SEEK_*). offset can be a number or a bigint. Return +0 if OK or -errno in case of I/O error. +

+
tell()
+

Return the current file position. +

+
tello()
+

Return the current file position as a bigint. +

+
eof()
+

Return true if end of file. +

+
fileno()
+

Return the associated OS handle. +

+
error()
+

Return true if there was an error. +

+
clearerr()
+

Clear the error indication. +

+
+
read(buffer, position, length)
+

Read length bytes from the file to the ArrayBuffer buffer at byte +position position (wrapper to the libc fread). +

+
+
write(buffer, position, length)
+

Write length bytes to the file from the ArrayBuffer buffer at byte +position position (wrapper to the libc fwrite). +

+
+
getline()
+

Return the next line from the file, assuming UTF-8 encoding, excluding +the trailing line feed. +

+
+
readAsString(max_size = undefined)
+

Read max_size bytes from the file and return them as a string +assuming UTF-8 encoding. If max_size is not present, the file +is read up its end. +

+
+
getByte()
+

Return the next byte from the file. Return -1 if the end of file is reached. +

+
+
putByte(c)
+

Write one byte to the file. +

+
+ + +

3.3.3 os module

+ +

The os module provides Operating System specific functions: +

+
    +
  • low level file access +
  • signals +
  • timers +
  • asynchronous I/O +
  • workers (threads) +
+ +

The OS functions usually return 0 if OK or an OS specific negative +error code. +

+

Available exports: +

+
+
open(filename, flags, mode = 0o666)
+

Open a file. Return a handle or < 0 if error. +

+
+
O_RDONLY
+
O_WRONLY
+
O_RDWR
+
O_APPEND
+
O_CREAT
+
O_EXCL
+
O_TRUNC
+

POSIX open flags. +

+
+
O_TEXT
+

(Windows specific). Open the file in text mode. The default is binary mode. +

+
+
close(fd)
+

Close the file handle fd. +

+
+
seek(fd, offset, whence)
+

Seek in the file. Use std.SEEK_* for +whence. offset is either a number or a bigint. If +offset is a bigint, a bigint is returned too. +

+
+
read(fd, buffer, offset, length)
+

Read length bytes from the file handle fd to the +ArrayBuffer buffer at byte position offset. +Return the number of read bytes or < 0 if error. +

+
+
write(fd, buffer, offset, length)
+

Write length bytes to the file handle fd from the +ArrayBuffer buffer at byte position offset. +Return the number of written bytes or < 0 if error. +

+
+
isatty(fd)
+

Return true is fd is a TTY (terminal) handle. +

+
+
ttyGetWinSize(fd)
+

Return the TTY size as [width, height] or null if not available. +

+
+
ttySetRaw(fd)
+

Set the TTY in raw mode. +

+
+
remove(filename)
+

Remove a file. Return 0 if OK or -errno. +

+
+
rename(oldname, newname)
+

Rename a file. Return 0 if OK or -errno. +

+
+
realpath(path)
+

Return [str, err] where str is the canonicalized absolute +pathname of path and err the error code. +

+
+
getcwd()
+

Return [str, err] where str is the current working directory +and err the error code. +

+
+
chdir(path)
+

Change the current directory. Return 0 if OK or -errno. +

+
+
mkdir(path, mode = 0o777)
+

Create a directory at path. Return 0 if OK or -errno. +

+
+
stat(path)
+
lstat(path)
+
+

Return [obj, err] where obj is an object containing the +file status of path. err is the error code. The +following fields are defined in obj: dev, ino, mode, nlink, +uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are +specified in milliseconds since 1970. lstat() is the same as +stat() excepts that it returns information about the link +itself. +

+
+
S_IFMT
+
S_IFIFO
+
S_IFCHR
+
S_IFDIR
+
S_IFBLK
+
S_IFREG
+
S_IFSOCK
+
S_IFLNK
+
S_ISGID
+
S_ISUID
+

Constants to interpret the mode property returned by +stat(). They have the same value as in the C system header +sys/stat.h. +

+
+
utimes(path, atime, mtime)
+

Change the access and modification times of the file path. The +times are specified in milliseconds since 1970. Return 0 if OK or -errno. +

+
+
symlink(target, linkpath)
+

Create a link at linkpath containing the string target. Return 0 if OK or -errno. +

+
+
readlink(path)
+

Return [str, err] where str is the link target and err +the error code. +

+
+
readdir(path)
+

Return [array, err] where array is an array of strings +containing the filenames of the directory path. err is +the error code. +

+
+
setReadHandler(fd, func)
+

Add a read handler to the file handle fd. func is called +each time there is data pending for fd. A single read handler +per file handle is supported. Use func = null to remove the +handler. +

+
+
setWriteHandler(fd, func)
+

Add a write handler to the file handle fd. func is +called each time data can be written to fd. A single write +handler per file handle is supported. Use func = null to remove +the handler. +

+
+
signal(signal, func)
+

Call the function func when the signal signal +happens. Only a single handler per signal number is supported. Use +null to set the default handler or undefined to ignore +the signal. Signal handlers can only be defined in the main thread. +

+
+
SIGINT
+
SIGABRT
+
SIGFPE
+
SIGILL
+
SIGSEGV
+
SIGTERM
+

POSIX signal numbers. +

+
+
kill(pid, sig)
+

Send the signal sig to the process pid. +

+
+
exec(args[, options])
+

Execute a process with the arguments args. options is an +object containing optional parameters: +

+
+
block
+

Boolean (default = true). If true, wait until the process is + terminated. In this case, exec return the exit code if positive + or the negated signal number if the process was interrupted by a + signal. If false, do not block and return the process id of the child. +

+
+
usePath
+

Boolean (default = true). If true, the file is searched in the + PATH environment variable. +

+
+
file
+

String (default = args[0]). Set the file to be executed. +

+
+
cwd
+

String. If present, set the working directory of the new process. +

+
+
stdin
+
stdout
+
stderr
+

If present, set the handle in the child for stdin, stdout or stderr. +

+
+
env
+

Object. If present, set the process environment from the object + key-value pairs. Otherwise use the same environment as the current + process. +

+
+
uid
+

Integer. If present, the process uid with setuid. +

+
+
gid
+

Integer. If present, the process gid with setgid. +

+
+
+ +
+
getpid()
+

Return the current process ID. +

+
+
waitpid(pid, options)
+

waitpid Unix system call. Return the array [ret, +status]. ret contains -errno in case of error. +

+
+
WNOHANG
+

Constant for the options argument of waitpid. +

+
+
dup(fd)
+

dup Unix system call. +

+
+
dup2(oldfd, newfd)
+

dup2 Unix system call. +

+
+
pipe()
+

pipe Unix system call. Return two handles as [read_fd, +write_fd] or null in case of error. +

+
+
sleep(delay_ms)
+

Sleep during delay_ms milliseconds. +

+
+
sleepAsync(delay_ms)
+

Asynchronouse sleep during delay_ms milliseconds. Returns a promise. Example: +

+
await os.sleepAsync(500);
+
+ +
+
now()
+

Return a timestamp in milliseconds with more precision than +Date.now(). The time origin is unspecified and is normally not +impacted by system clock adjustments. +

+
+
setTimeout(func, delay)
+

Call the function func after delay ms. Return a handle +to the timer. +

+
+
clearTimeout(handle)
+

Cancel a timer. +

+
+
platform
+

Return a string representing the platform: "linux", "darwin", +"win32" or "js". +

+
+
Worker(module_filename)
+

Constructor to create a new thread (worker) with an API close to the +WebWorkers. module_filename is a string specifying the +module filename which is executed in the newly created thread. As for +dynamically imported module, it is relative to the current script or +module path. Threads normally don’t share any data and communicate +between each other with messages. Nested workers are not supported. An +example is available in tests/test_worker.js. +

+

The worker class has the following static properties: +

+
+
parent
+

In the created worker, Worker.parent represents the parent + worker and is used to send or receive messages. +

+
+ +

The worker instances have the following properties: +

+
+
postMessage(msg)
+
+

Send a message to the corresponding worker. msg is cloned in + the destination worker using an algorithm similar to the HTML + structured clone algorithm. SharedArrayBuffer are shared + between workers. +

+

Current limitations: Map and Set are not supported + yet. +

+
+
onmessage
+
+

Getter and setter. Set a function which is called each time a + message is received. The function is called with a single + argument. It is an object with a data property containing the + received message. The thread is not terminated if there is at least + one non null onmessage handler. +

+
+
+ +
+
+ + +

3.4 QuickJS C API

+ +

The C API was designed to be simple and efficient. The C API is +defined in the header quickjs.h. +

+ +

3.4.1 Runtime and contexts

+ +

JSRuntime represents a Javascript runtime corresponding to an +object heap. Several runtimes can exist at the same time but they +cannot exchange objects. Inside a given runtime, no multi-threading is +supported. +

+

JSContext represents a Javascript context (or Realm). Each +JSContext has its own global objects and system objects. There can be +several JSContexts per JSRuntime and they can share objects, similar +to frames of the same origin sharing Javascript objects in a +web browser. +

+ +

3.4.2 JSValue

+ +

JSValue represents a Javascript value which can be a primitive +type or an object. Reference counting is used, so it is important to +explicitly duplicate (JS_DupValue(), increment the reference +count) or free (JS_FreeValue(), decrement the reference count) +JSValues. +

+ +

3.4.3 C functions

+ +

C functions can be created with +JS_NewCFunction(). JS_SetPropertyFunctionList() is a +shortcut to easily add functions, setters and getters properties to a +given object. +

+

Unlike other embedded Javascript engines, there is no implicit stack, +so C functions get their parameters as normal C parameters. As a +general rule, C functions take constant JSValues as parameters +(so they don’t need to free them) and return a newly allocated (=live) +JSValue. +

+ +

3.4.4 Exceptions

+ +

Exceptions: most C functions can return a Javascript exception. It +must be explicitly tested and handled by the C code. The specific +JSValue JS_EXCEPTION indicates that an exception +occurred. The actual exception object is stored in the +JSContext and can be retrieved with JS_GetException(). +

+ +

3.4.5 Script evaluation

+ +

Use JS_Eval() to evaluate a script or module source. +

+

If the script or module was compiled to bytecode with qjsc, it +can be evaluated by calling js_std_eval_binary(). The advantage +is that no compilation is needed so it is faster and smaller because +the compiler can be removed from the executable if no eval is +required. +

+

Note: the bytecode format is linked to a given QuickJS +version. Moreover, no security check is done before its +execution. Hence the bytecode should not be loaded from untrusted +sources. That’s why there is no option to output the bytecode to a +binary file in qjsc. +

+ +

3.4.6 JS Classes

+ +

C opaque data can be attached to a Javascript object. The type of the +C opaque data is determined with the class ID (JSClassID) of +the object. Hence the first step is to register a new class ID and JS +class (JS_NewClassID(), JS_NewClass()). Then you can +create objects of this class with JS_NewObjectClass() and get or +set the C opaque point with +JS_GetOpaque()/JS_SetOpaque(). +

+

When defining a new JS class, it is possible to declare a finalizer +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A gc_mark method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors. +

+

The Class ID are globally allocated (i.e. for all runtimes). The +JSClass are allocated per JSRuntime. JS_SetClassProto() +is used to define a prototype for a given class in a given +JSContext. JS_NewObjectClass() sets this prototype in the +created object. +

+

Examples are available in quickjs-libc.c. +

+ +

3.4.7 C Modules

+ +

Native ES6 modules are supported and can be dynamically or statically +linked. Look at the test_bjson and bjson.so +examples. The standard library quickjs-libc.c is also a good example +of a native module. +

+ +

3.4.8 Memory handling

+ +

Use JS_SetMemoryLimit() to set a global memory allocation limit +to a given JSRuntime. +

+

Custom memory allocation functions can be provided with +JS_NewRuntime2(). +

+

The maximum system stack size can be set with JS_SetMaxStackSize(). +

+ +

3.4.9 Execution timeout and interrupts

+ +

Use JS_SetInterruptHandler() to set a callback which is +regularly called by the engine when it is executing code. This +callback can be used to implement an execution timeout. +

+

It is used by the command line interpreter to implement a +Ctrl-C handler. +

+ +

4 Internals

+ + +

4.1 Bytecode

+ +

The compiler generates bytecode directly with no intermediate +representation such as a parse tree, hence it is very fast. Several +optimizations passes are done over the generated bytecode. +

+

A stack-based bytecode was chosen because it is simple and generates +compact code. +

+

For each function, the maximum stack size is computed at compile time so that +no runtime stack overflow tests are needed. +

+

A separate compressed line number table is maintained for the debug +information. +

+

Access to closure variables is optimized and is almost as fast as local +variables. +

+

Direct eval in strict mode is optimized. +

+ +

4.2 Executable generation

+ + +

4.2.1 qjsc compiler

+ +

The qjsc compiler generates C sources from Javascript files. By +default the C sources are compiled with the system compiler +(gcc or clang). +

+

The generated C source contains the bytecode of the compiled functions +or modules. If a full complete executable is needed, it also +contains a main() function with the necessary C code to initialize the +Javascript engine and to load and execute the compiled functions and +modules. +

+

Javascript code can be mixed with C modules. +

+

In order to have smaller executables, specific Javascript features can +be disabled, in particular eval or the regular expressions. The +code removal relies on the Link Time Optimization of the system +compiler. +

+ +

4.2.2 Binary JSON

+ +

qjsc works by compiling scripts or modules and then serializing +them to a binary format. A subset of this format (without functions or +modules) can be used as binary JSON. The example test_bjson.js +shows how to use it. +

+

Warning: the binary JSON format may change without notice, so it +should not be used to store persistent data. The test_bjson.js +example is only used to test the binary object format functions. +

+ +

4.3 Runtime

+ + +

4.3.1 Strings

+ +

Strings are stored either as an 8 bit or a 16 bit array of +characters. Hence random access to characters is always fast. +

+

The C API provides functions to convert Javascript Strings to C UTF-8 encoded +strings. The most common case where the Javascript string contains +only ASCII characters involves no copying. +

+ +

4.3.2 Objects

+ +

The object shapes (object prototype, property names and flags) are shared +between objects to save memory. +

+

Arrays with no holes (except at the end of the array) are optimized. +

+

TypedArray accesses are optimized. +

+ +

4.3.3 Atoms

+ +

Object property names and some strings are stored as Atoms (unique +strings) to save memory and allow fast comparison. Atoms are +represented as a 32 bit integer. Half of the atom range is reserved for +immediate integer literals from 0 to 2^{31}-1. +

+ +

4.3.4 Numbers

+ +

Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 +floating point values. Most operations have fast paths for the 32-bit +integer case. +

+ +

4.3.5 Garbage collection

+ +

Reference counting is used to free objects automatically and +deterministically. A separate cycle removal pass is done when the allocated +memory becomes too large. The cycle removal algorithm only uses the +reference counts and the object content, so no explicit garbage +collection roots need to be manipulated in the C code. +

+ +

4.3.6 JSValue

+ +

It is a Javascript value which can be a primitive type (such as +Number, String, ...) or an Object. NaN boxing is used in the 32-bit version +to store 64-bit floating point numbers. The representation is +optimized so that 32-bit integers and reference counted values can be +efficiently tested. +

+

In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The +rationale is that in 64-bit code memory usage is less critical. +

+

In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, +so it can be efficiently returned by C functions. +

+ +

4.3.7 Function call

+ +

The engine is optimized so that function calls are fast. The system +stack holds the Javascript parameters and local variables. +

+ +

4.4 RegExp

+ +

A specific regular expression engine was developed. It is both small +and efficient and supports all the ES2023 features including the +Unicode properties. As the Javascript compiler, it directly generates +bytecode without a parse tree. +

+

Backtracking with an explicit stack is used so that there is no +recursion on the system stack. Simple quantifiers are specifically +optimized to avoid recursions. +

+

The full regexp library weights about 15 KiB (x86 code), excluding the +Unicode library. +

+ +

4.5 Unicode

+ +

A specific Unicode library was developed so that there is no +dependency on an external large Unicode library such as ICU. All the +Unicode tables are compressed while keeping a reasonable access +speed. +

+

The library supports case conversion, Unicode normalization, Unicode +script queries, Unicode general category queries and all Unicode +binary properties. +

+

The full Unicode library weights about 45 KiB (x86 code). +

+ +

4.6 BigInt, BigFloat, BigDecimal

+ +

BigInt, BigFloat and BigDecimal are implemented with the libbf +library7. It weights about 90 +KiB (x86 code) and provides arbitrary precision IEEE 754 floating +point operations and transcendental functions with exact rounding. +

+ +

5 License

+ +

QuickJS is released under the MIT license. +

+

Unless otherwise specified, the QuickJS sources are copyright Fabrice +Bellard and Charlie Gordon. +

+
+
+

Footnotes

+ +

(1)

+

https://tc39.es/ecma262/2023

+

(2)

+

https://github.com/tc39/test262

+

(3)

+

https://tc39.es/ecma262/

+

(4)

+

The old +ES5.1 tests can be extracted with git clone --single-branch +--branch es5-tests https://github.com/tc39/test262.git test262o

+

(5)

+

https://github.com/bterlson/test262-harness

+

(6)

+

We believe the current specification of tails calls is too complicated and presents limited practical interests.

+

(7)

+

https://bellard.org/libbf

+
+
+ + + + + diff --git a/deps/quickjs/doc/quickjs.pdf b/deps/quickjs/doc/quickjs.pdf new file mode 100644 index 0000000..2338d7a Binary files /dev/null and b/deps/quickjs/doc/quickjs.pdf differ diff --git a/deps/quickjs/doc/quickjs.texi b/deps/quickjs/doc/quickjs.texi new file mode 100644 index 0000000..898d46c --- /dev/null +++ b/deps/quickjs/doc/quickjs.texi @@ -0,0 +1,1120 @@ +\input texinfo + +@iftex +@afourpaper +@headings double +@end iftex + +@titlepage +@afourpaper +@sp 7 +@center @titlefont{QuickJS Javascript Engine} +@sp 3 +@end titlepage + +@setfilename spec.info +@settitle QuickJS Javascript Engine + +@contents + +@chapter Introduction + +QuickJS is a small and embeddable Javascript engine. It supports most of the +ES2023 specification +@footnote{@url{https://tc39.es/ecma262/2023 }} +including modules, asynchronous generators, proxies and BigInt. + +It supports mathematical extensions such as big decimal float float +numbers (BigDecimal), big binary floating point numbers (BigFloat), +and operator overloading. + +@section Main Features + +@itemize + +@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program. + +@item Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds. + +@item Almost complete ES2023 support including modules, asynchronous +generators and full Annex B support (legacy web compatibility). Some +features from the upcoming ES2024 specification +@footnote{@url{https://tc39.es/ecma262/}} are also supported. + +@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2023 features. + +@item Compile Javascript sources to executables with no external dependency. + +@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal. + +@item Mathematical extensions: BigDecimal, BigFloat, operator overloading, bigint mode, math mode. + +@item Command line interpreter with contextual colorization and completion implemented in Javascript. + +@item Small built-in standard library with C library wrappers. + +@end itemize + +@chapter Usage + +@section Installation + +A Makefile is provided to compile the engine on Linux or MacOS/X. A +preliminary Windows support is available thru cross compilation on a +Linux host with the MingGW tools. + +Edit the top of the @code{Makefile} if you wish to select specific +options then run @code{make}. + +You can type @code{make install} as root if you wish to install the binaries and support files to +@code{/usr/local} (this is not necessary to use QuickJS). + +Note: On some OSes atomic operations are not available or need a +specific library. If you get related errors, you should either add +@code{-latomics} in the Makefile @code{LIBS} variable or disable +@code{CONFIG_ATOMICS} in @file{quickjs.c}. + +@section Quick start + +@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass +Javascript files and/or expressions as arguments to execute them: + +@example +./qjs examples/hello.js +@end example + +@code{qjsc} is the command line compiler: + +@example +./qjsc -o hello examples/hello.js +./hello +@end example + +generates a @code{hello} executable with no external dependency. + +@section Command line options + +@subsection @code{qjs} interpreter + +@verbatim +usage: qjs [options] [file [args]] +@end verbatim + +Options are: +@table @code +@item -h +@item --help +List options. + +@item -e @code{EXPR} +@item --eval @code{EXPR} +Evaluate EXPR. + +@item -i +@item --interactive +Go to interactive mode (it is not the default when files are provided on the command line). + +@item -m +@item --module +Load as ES6 module (default=autodetect). A module is autodetected if +the filename extension is @code{.mjs} or if the first keyword of the +source is @code{import}. + +@item --script +Load as ES6 script (default=autodetect). + +@item --bignum +Enable the bignum extensions: BigDecimal object, BigFloat object and +the @code{"use math"} directive. + +@item -I file +@item --include file +Include an additional file. + +@end table + +Advanced options are: + +@table @code +@item --std +Make the @code{std} and @code{os} modules available to the loaded +script even if it is not a module. + +@item -d +@item --dump +Dump the memory usage stats. + +@item -q +@item --quit +just instantiate the interpreter and quit. + +@end table + +@subsection @code{qjsc} compiler + +@verbatim +usage: qjsc [options] [files] +@end verbatim + +Options are: +@table @code +@item -c +Only output bytecode in a C file. The default is to output an executable file. +@item -e +Output @code{main()} and bytecode in a C file. The default is to output an +executable file. +@item -o output +Set the output filename (default = @file{out.c} or @file{a.out}). + +@item -N cname +Set the C name of the generated data. + +@item -m +Compile as Javascript module (default=autodetect). + +@item -D module_name +Compile a dynamically loaded module and its dependencies. This option +is needed when your code uses the @code{import} keyword or the +@code{os.Worker} constructor because the compiler cannot statically +find the name of the dynamically loaded modules. + +@item -M module_name[,cname] +Add initialization code for an external C module. See the +@code{c_module} example. + +@item -x +Byte swapped output (only used for cross compilation). + +@item -flto +Use link time optimization. The compilation is slower but the +executable is smaller and faster. This option is automatically set +when the @code{-fno-x} options are used. + +@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint] +Disable selected language features to produce a smaller executable file. + +@item -fbignum +Enable the bignum extensions: BigDecimal object, BigFloat object and +the @code{"use math"} directive. + +@end table + +@section @code{qjscalc} application + +The @code{qjscalc} application is a superset of the @code{qjs} +command line interpreter implementing a Javascript calculator with +arbitrarily large integer and floating point numbers, fractions, +complex numbers, polynomials and matrices. The source code is in +@file{qjscalc.js}. More documentation and a web version are available at +@url{http://numcalc.com}. + +@section Built-in tests + +Run @code{make test} to run the few built-in tests included in the +QuickJS archive. + +@section Test262 (ECMAScript Test Suite) + +A test262 runner is included in the QuickJS archive. The test262 tests +can be installed in the QuickJS source directory with: + +@example +git clone https://github.com/tc39/test262.git test262 +cd test262 +patch -p1 < ../tests/test262.patch +cd .. +@end example + +The patch adds the implementation specific @code{harness} functions +and optimizes the inefficient RegExp character classes and Unicode +property escapes tests (the tests themselves are not modified, only a +slow string initialization function is optimized). + +The tests can be run with +@example +make test2 +@end example + +The configuration files @code{test262.conf} +(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old +ES5.1 tests can be extracted with @code{git clone --single-branch +--branch es5-tests https://github.com/tc39/test262.git test262o}})) +contain the options to run the various tests. Tests can be excluded +based on features or filename. + +The file @code{test262_errors.txt} contains the current list of +errors. The runner displays a message when a new error appears or when +an existing error is corrected or modified. Use the @code{-u} option +to update the current list of errors (or @code{make test2-update}). + +The file @code{test262_report.txt} contains the logs of all the +tests. It is useful to have a clearer analysis of a particular +error. In case of crash, the last line corresponds to the failing +test. + +Use the syntax @code{./run-test262 -c test262.conf -f filename.js} to +run a single test. Use the syntax @code{./run-test262 -c test262.conf +N} to start testing at test number @code{N}. + +For more information, run @code{./run-test262} to see the command line +options of the test262 runner. + +@code{run-test262} accepts the @code{-N} option to be invoked from +@code{test262-harness}@footnote{@url{https://github.com/bterlson/test262-harness}} +thru @code{eshost}. Unless you want to compare QuickJS with other +engines under the same conditions, we do not recommend to run the +tests this way as it is much slower (typically half an hour instead of +about 100 seconds). + +@chapter Specifications + +@section Language support + +@subsection ES2023 support + +The ES2023 specification is almost fully supported including the Annex +B (legacy web compatibility) and the Unicode related features. + +The following features are not supported yet: + +@itemize + +@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.} + +@item WeakRef and FinalizationRegistry objects + +@item Symbols as WeakMap keys + +@end itemize + +@subsection ECMA402 + +ECMA402 (Internationalization API) is not supported. + +@subsection Extensions + +@itemize + +@item The directive @code{"use strip"} indicates that the debug information (including the source code of the functions) should not be retained to save memory. As @code{"use strict"}, the directive can be global to a script or local to a function. + +@item The first line of a script beginning with @code{#!} is ignored. + +@end itemize + +@subsection Mathematical extensions + +The mathematical extensions are fully backward compatible with +standard Javascript. See @code{jsbignum.pdf} for more information. + +@itemize + +@item @code{BigDecimal} support: arbitrary large floating point numbers in base 10. + +@item @code{BigFloat} support: arbitrary large floating point numbers in base 2. + +@item Operator overloading. + +@item The directive @code{"use bigint"} enables the bigint mode where integers are @code{BigInt} by default. + +@item The directive @code{"use math"} enables the math mode where the division and power operators on integers produce fractions. Floating point literals are @code{BigFloat} by default and integers are @code{BigInt} by default. + +@end itemize + +@section Modules + +ES6 modules are fully supported. The default name resolution is the +following: + +@itemize + +@item Module names with a leading @code{.} or @code{..} are relative +to the current module path. + +@item Module names without a leading @code{.} or @code{..} are system +modules, such as @code{std} or @code{os}. + +@item Module names ending with @code{.so} are native modules using the +QuickJS C API. + +@end itemize + +@section Standard library + +The standard library is included by default in the command line +interpreter. It contains the two modules @code{std} and @code{os} and +a few global objects. + +@subsection Global objects + +@table @code +@item scriptArgs +Provides the command line arguments. The first argument is the script name. +@item print(...args) +Print the arguments separated by spaces and a trailing newline. +@item console.log(...args) +Same as print(). + +@end table + +@subsection @code{std} module + +The @code{std} module provides wrappers to the libc @file{stdlib.h} +and @file{stdio.h} and a few other utilities. + +Available exports: + +@table @code + +@item exit(n) +Exit the process. + +@item evalScript(str, options = undefined) +Evaluate the string @code{str} as a script (global +eval). @code{options} is an optional object containing the following +optional properties: + + @table @code + @item backtrace_barrier + Boolean (default = false). If true, error backtraces do not list the + stack frames below the evalScript. + @item async + Boolean (default = false). If true, @code{await} is accepted in the + script and a promise is returned. + @end table + +@item loadScript(filename) +Evaluate the file @code{filename} as a script (global eval). + +@item loadFile(filename) +Load the file @code{filename} and return it as a string assuming UTF-8 +encoding. Return @code{null} in case of I/O error. + +@item open(filename, flags, errorObj = undefined) +Open a file (wrapper to the libc @code{fopen()}). Return the FILE +object or @code{null} in case of I/O error. If @code{errorObj} is not +undefined, set its @code{errno} property to the error code or to 0 if +no error occured. + +@item popen(command, flags, errorObj = undefined) +Open a process by creating a pipe (wrapper to the libc +@code{popen()}). Return the FILE +object or @code{null} in case of I/O error. If @code{errorObj} is not +undefined, set its @code{errno} property to the error code or to 0 if +no error occured. + +@item fdopen(fd, flags, errorObj = undefined) +Open a file from a file handle (wrapper to the libc +@code{fdopen()}). Return the FILE +object or @code{null} in case of I/O error. If @code{errorObj} is not +undefined, set its @code{errno} property to the error code or to 0 if +no error occured. + +@item tmpfile(errorObj = undefined) +Open a temporary file. Return the FILE +object or @code{null} in case of I/O error. If @code{errorObj} is not +undefined, set its @code{errno} property to the error code or to 0 if +no error occured. + +@item puts(str) +Equivalent to @code{std.out.puts(str)}. + +@item printf(fmt, ...args) +Equivalent to @code{std.out.printf(fmt, ...args)}. + +@item sprintf(fmt, ...args) +Equivalent to the libc sprintf(). + +@item in +@item out +@item err +Wrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}. + +@item SEEK_SET +@item SEEK_CUR +@item SEEK_END +Constants for seek(). + +@item Error + +Enumeration object containing the integer value of common errors +(additional error codes may be defined): + + @table @code + @item EINVAL + @item EIO + @item EACCES + @item EEXIST + @item ENOSPC + @item ENOSYS + @item EBUSY + @item ENOENT + @item EPERM + @item EPIPE + @end table + +@item strerror(errno) +Return a string that describes the error @code{errno}. + +@item gc() +Manually invoke the cycle removal algorithm. The cycle removal +algorithm is automatically started when needed, so this function is +useful in case of specific memory constraints or for testing. + +@item getenv(name) +Return the value of the environment variable @code{name} or +@code{undefined} if it is not defined. + +@item setenv(name, value) +Set the value of the environment variable @code{name} to the string +@code{value}. + +@item unsetenv(name) +Delete the environment variable @code{name}. + +@item getenviron() +Return an object containing the environment variables as key-value pairs. + +@item urlGet(url, options = undefined) + +Download @code{url} using the @file{curl} command line +utility. @code{options} is an optional object containing the following +optional properties: + + @table @code + @item binary + Boolean (default = false). If true, the response is an ArrayBuffer + instead of a string. When a string is returned, the data is assumed + to be UTF-8 encoded. + + @item full + + Boolean (default = false). If true, return the an object contains + the properties @code{response} (response content), + @code{responseHeaders} (headers separated by CRLF), @code{status} + (status code). @code{response} is @code{null} is case of protocol or + network error. If @code{full} is false, only the response is + returned if the status is between 200 and 299. Otherwise @code{null} + is returned. + + @end table + +@item parseExtJSON(str) + + Parse @code{str} using a superset of @code{JSON.parse}. The + following extensions are accepted: + + @itemize + @item Single line and multiline comments + @item unquoted properties (ASCII-only Javascript identifiers) + @item trailing comma in array and object definitions + @item single quoted strings + @item @code{\f} and @code{\v} are accepted as space characters + @item leading plus in numbers + @item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers + @end itemize +@end table + +FILE prototype: + +@table @code +@item close() +Close the file. Return 0 if OK or @code{-errno} in case of I/O error. +@item puts(str) +Outputs the string with the UTF-8 encoding. +@item printf(fmt, ...args) +Formatted printf. + +The same formats as the standard C library @code{printf} are +supported. Integer format types (e.g. @code{%d}) truncate the Numbers +or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to +truncate to 64 bits. + +@item flush() +Flush the buffered file. +@item seek(offset, whence) +Seek to a give file position (whence is +@code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return +0 if OK or @code{-errno} in case of I/O error. +@item tell() +Return the current file position. +@item tello() +Return the current file position as a bigint. +@item eof() +Return true if end of file. +@item fileno() +Return the associated OS handle. +@item error() +Return true if there was an error. +@item clearerr() +Clear the error indication. + +@item read(buffer, position, length) +Read @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte +position @code{position} (wrapper to the libc @code{fread}). + +@item write(buffer, position, length) +Write @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte +position @code{position} (wrapper to the libc @code{fwrite}). + +@item getline() +Return the next line from the file, assuming UTF-8 encoding, excluding +the trailing line feed. + +@item readAsString(max_size = undefined) +Read @code{max_size} bytes from the file and return them as a string +assuming UTF-8 encoding. If @code{max_size} is not present, the file +is read up its end. + +@item getByte() +Return the next byte from the file. Return -1 if the end of file is reached. + +@item putByte(c) +Write one byte to the file. +@end table + +@subsection @code{os} module + +The @code{os} module provides Operating System specific functions: + +@itemize +@item low level file access +@item signals +@item timers +@item asynchronous I/O +@item workers (threads) +@end itemize + +The OS functions usually return 0 if OK or an OS specific negative +error code. + +Available exports: + +@table @code +@item open(filename, flags, mode = 0o666) +Open a file. Return a handle or < 0 if error. + +@item O_RDONLY +@item O_WRONLY +@item O_RDWR +@item O_APPEND +@item O_CREAT +@item O_EXCL +@item O_TRUNC +POSIX open flags. + +@item O_TEXT +(Windows specific). Open the file in text mode. The default is binary mode. + +@item close(fd) +Close the file handle @code{fd}. + +@item seek(fd, offset, whence) +Seek in the file. Use @code{std.SEEK_*} for +@code{whence}. @code{offset} is either a number or a bigint. If +@code{offset} is a bigint, a bigint is returned too. + +@item read(fd, buffer, offset, length) +Read @code{length} bytes from the file handle @code{fd} to the +ArrayBuffer @code{buffer} at byte position @code{offset}. +Return the number of read bytes or < 0 if error. + +@item write(fd, buffer, offset, length) +Write @code{length} bytes to the file handle @code{fd} from the +ArrayBuffer @code{buffer} at byte position @code{offset}. +Return the number of written bytes or < 0 if error. + +@item isatty(fd) +Return @code{true} is @code{fd} is a TTY (terminal) handle. + +@item ttyGetWinSize(fd) +Return the TTY size as @code{[width, height]} or @code{null} if not available. + +@item ttySetRaw(fd) +Set the TTY in raw mode. + +@item remove(filename) +Remove a file. Return 0 if OK or @code{-errno}. + +@item rename(oldname, newname) +Rename a file. Return 0 if OK or @code{-errno}. + +@item realpath(path) +Return @code{[str, err]} where @code{str} is the canonicalized absolute +pathname of @code{path} and @code{err} the error code. + +@item getcwd() +Return @code{[str, err]} where @code{str} is the current working directory +and @code{err} the error code. + +@item chdir(path) +Change the current directory. Return 0 if OK or @code{-errno}. + +@item mkdir(path, mode = 0o777) +Create a directory at @code{path}. Return 0 if OK or @code{-errno}. + +@item stat(path) +@item lstat(path) + +Return @code{[obj, err]} where @code{obj} is an object containing the +file status of @code{path}. @code{err} is the error code. The +following fields are defined in @code{obj}: dev, ino, mode, nlink, +uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are +specified in milliseconds since 1970. @code{lstat()} is the same as +@code{stat()} excepts that it returns information about the link +itself. + +@item S_IFMT +@item S_IFIFO +@item S_IFCHR +@item S_IFDIR +@item S_IFBLK +@item S_IFREG +@item S_IFSOCK +@item S_IFLNK +@item S_ISGID +@item S_ISUID +Constants to interpret the @code{mode} property returned by +@code{stat()}. They have the same value as in the C system header +@file{sys/stat.h}. + +@item utimes(path, atime, mtime) +Change the access and modification times of the file @code{path}. The +times are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}. + +@item symlink(target, linkpath) +Create a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}. + +@item readlink(path) +Return @code{[str, err]} where @code{str} is the link target and @code{err} +the error code. + +@item readdir(path) +Return @code{[array, err]} where @code{array} is an array of strings +containing the filenames of the directory @code{path}. @code{err} is +the error code. + +@item setReadHandler(fd, func) +Add a read handler to the file handle @code{fd}. @code{func} is called +each time there is data pending for @code{fd}. A single read handler +per file handle is supported. Use @code{func = null} to remove the +handler. + +@item setWriteHandler(fd, func) +Add a write handler to the file handle @code{fd}. @code{func} is +called each time data can be written to @code{fd}. A single write +handler per file handle is supported. Use @code{func = null} to remove +the handler. + +@item signal(signal, func) +Call the function @code{func} when the signal @code{signal} +happens. Only a single handler per signal number is supported. Use +@code{null} to set the default handler or @code{undefined} to ignore +the signal. Signal handlers can only be defined in the main thread. + +@item SIGINT +@item SIGABRT +@item SIGFPE +@item SIGILL +@item SIGSEGV +@item SIGTERM +POSIX signal numbers. + +@item kill(pid, sig) +Send the signal @code{sig} to the process @code{pid}. + +@item exec(args[, options]) +Execute a process with the arguments @code{args}. @code{options} is an +object containing optional parameters: + + @table @code + @item block + Boolean (default = true). If true, wait until the process is + terminated. In this case, @code{exec} return the exit code if positive + or the negated signal number if the process was interrupted by a + signal. If false, do not block and return the process id of the child. + + @item usePath + Boolean (default = true). If true, the file is searched in the + @code{PATH} environment variable. + + @item file + String (default = @code{args[0]}). Set the file to be executed. + + @item cwd + String. If present, set the working directory of the new process. + + @item stdin + @item stdout + @item stderr + If present, set the handle in the child for stdin, stdout or stderr. + + @item env + Object. If present, set the process environment from the object + key-value pairs. Otherwise use the same environment as the current + process. + + @item uid + Integer. If present, the process uid with @code{setuid}. + + @item gid + Integer. If present, the process gid with @code{setgid}. + + @end table + +@item getpid() +Return the current process ID. + +@item waitpid(pid, options) +@code{waitpid} Unix system call. Return the array @code{[ret, +status]}. @code{ret} contains @code{-errno} in case of error. + +@item WNOHANG +Constant for the @code{options} argument of @code{waitpid}. + +@item dup(fd) +@code{dup} Unix system call. + +@item dup2(oldfd, newfd) +@code{dup2} Unix system call. + +@item pipe() +@code{pipe} Unix system call. Return two handles as @code{[read_fd, +write_fd]} or null in case of error. + +@item sleep(delay_ms) +Sleep during @code{delay_ms} milliseconds. + +@item sleepAsync(delay_ms) +Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example: +@example +await os.sleepAsync(500); +@end example + +@item now() +Return a timestamp in milliseconds with more precision than +@code{Date.now()}. The time origin is unspecified and is normally not +impacted by system clock adjustments. + +@item setTimeout(func, delay) +Call the function @code{func} after @code{delay} ms. Return a handle +to the timer. + +@item clearTimeout(handle) +Cancel a timer. + +@item platform +Return a string representing the platform: @code{"linux"}, @code{"darwin"}, +@code{"win32"} or @code{"js"}. + +@item Worker(module_filename) +Constructor to create a new thread (worker) with an API close to the +@code{WebWorkers}. @code{module_filename} is a string specifying the +module filename which is executed in the newly created thread. As for +dynamically imported module, it is relative to the current script or +module path. Threads normally don't share any data and communicate +between each other with messages. Nested workers are not supported. An +example is available in @file{tests/test_worker.js}. + +The worker class has the following static properties: + + @table @code + @item parent + In the created worker, @code{Worker.parent} represents the parent + worker and is used to send or receive messages. + @end table + +The worker instances have the following properties: + + @table @code + @item postMessage(msg) + + Send a message to the corresponding worker. @code{msg} is cloned in + the destination worker using an algorithm similar to the @code{HTML} + structured clone algorithm. @code{SharedArrayBuffer} are shared + between workers. + + Current limitations: @code{Map} and @code{Set} are not supported + yet. + + @item onmessage + + Getter and setter. Set a function which is called each time a + message is received. The function is called with a single + argument. It is an object with a @code{data} property containing the + received message. The thread is not terminated if there is at least + one non @code{null} @code{onmessage} handler. + + @end table + +@end table + +@section QuickJS C API + +The C API was designed to be simple and efficient. The C API is +defined in the header @code{quickjs.h}. + +@subsection Runtime and contexts + +@code{JSRuntime} represents a Javascript runtime corresponding to an +object heap. Several runtimes can exist at the same time but they +cannot exchange objects. Inside a given runtime, no multi-threading is +supported. + +@code{JSContext} represents a Javascript context (or Realm). Each +JSContext has its own global objects and system objects. There can be +several JSContexts per JSRuntime and they can share objects, similar +to frames of the same origin sharing Javascript objects in a +web browser. + +@subsection JSValue + +@code{JSValue} represents a Javascript value which can be a primitive +type or an object. Reference counting is used, so it is important to +explicitly duplicate (@code{JS_DupValue()}, increment the reference +count) or free (@code{JS_FreeValue()}, decrement the reference count) +JSValues. + +@subsection C functions + +C functions can be created with +@code{JS_NewCFunction()}. @code{JS_SetPropertyFunctionList()} is a +shortcut to easily add functions, setters and getters properties to a +given object. + +Unlike other embedded Javascript engines, there is no implicit stack, +so C functions get their parameters as normal C parameters. As a +general rule, C functions take constant @code{JSValue}s as parameters +(so they don't need to free them) and return a newly allocated (=live) +@code{JSValue}. + +@subsection Exceptions + +Exceptions: most C functions can return a Javascript exception. It +must be explicitly tested and handled by the C code. The specific +@code{JSValue} @code{JS_EXCEPTION} indicates that an exception +occurred. The actual exception object is stored in the +@code{JSContext} and can be retrieved with @code{JS_GetException()}. + +@subsection Script evaluation + +Use @code{JS_Eval()} to evaluate a script or module source. + +If the script or module was compiled to bytecode with @code{qjsc}, it +can be evaluated by calling @code{js_std_eval_binary()}. The advantage +is that no compilation is needed so it is faster and smaller because +the compiler can be removed from the executable if no @code{eval} is +required. + +Note: the bytecode format is linked to a given QuickJS +version. Moreover, no security check is done before its +execution. Hence the bytecode should not be loaded from untrusted +sources. That's why there is no option to output the bytecode to a +binary file in @code{qjsc}. + +@subsection JS Classes + +C opaque data can be attached to a Javascript object. The type of the +C opaque data is determined with the class ID (@code{JSClassID}) of +the object. Hence the first step is to register a new class ID and JS +class (@code{JS_NewClassID()}, @code{JS_NewClass()}). Then you can +create objects of this class with @code{JS_NewObjectClass()} and get or +set the C opaque point with +@code{JS_GetOpaque()}/@code{JS_SetOpaque()}. + +When defining a new JS class, it is possible to declare a finalizer +which is called when the object is destroyed. The finalizer should be +used to release C resources. It is invalid to execute JS code from +it. A @code{gc_mark} method can be provided so that the cycle removal +algorithm can find the other objects referenced by this object. Other +methods are available to define exotic object behaviors. + +The Class ID are globally allocated (i.e. for all runtimes). The +JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()} +is used to define a prototype for a given class in a given +JSContext. @code{JS_NewObjectClass()} sets this prototype in the +created object. + +Examples are available in @file{quickjs-libc.c}. + +@subsection C Modules + +Native ES6 modules are supported and can be dynamically or statically +linked. Look at the @file{test_bjson} and @file{bjson.so} +examples. The standard library @file{quickjs-libc.c} is also a good example +of a native module. + +@subsection Memory handling + +Use @code{JS_SetMemoryLimit()} to set a global memory allocation limit +to a given JSRuntime. + +Custom memory allocation functions can be provided with +@code{JS_NewRuntime2()}. + +The maximum system stack size can be set with @code{JS_SetMaxStackSize()}. + +@subsection Execution timeout and interrupts + +Use @code{JS_SetInterruptHandler()} to set a callback which is +regularly called by the engine when it is executing code. This +callback can be used to implement an execution timeout. + +It is used by the command line interpreter to implement a +@code{Ctrl-C} handler. + +@chapter Internals + +@section Bytecode + +The compiler generates bytecode directly with no intermediate +representation such as a parse tree, hence it is very fast. Several +optimizations passes are done over the generated bytecode. + +A stack-based bytecode was chosen because it is simple and generates +compact code. + +For each function, the maximum stack size is computed at compile time so that +no runtime stack overflow tests are needed. + +A separate compressed line number table is maintained for the debug +information. + +Access to closure variables is optimized and is almost as fast as local +variables. + +Direct @code{eval} in strict mode is optimized. + +@section Executable generation + +@subsection @code{qjsc} compiler + +The @code{qjsc} compiler generates C sources from Javascript files. By +default the C sources are compiled with the system compiler +(@code{gcc} or @code{clang}). + +The generated C source contains the bytecode of the compiled functions +or modules. If a full complete executable is needed, it also +contains a @code{main()} function with the necessary C code to initialize the +Javascript engine and to load and execute the compiled functions and +modules. + +Javascript code can be mixed with C modules. + +In order to have smaller executables, specific Javascript features can +be disabled, in particular @code{eval} or the regular expressions. The +code removal relies on the Link Time Optimization of the system +compiler. + +@subsection Binary JSON + +@code{qjsc} works by compiling scripts or modules and then serializing +them to a binary format. A subset of this format (without functions or +modules) can be used as binary JSON. The example @file{test_bjson.js} +shows how to use it. + +Warning: the binary JSON format may change without notice, so it +should not be used to store persistent data. The @file{test_bjson.js} +example is only used to test the binary object format functions. + +@section Runtime + +@subsection Strings + +Strings are stored either as an 8 bit or a 16 bit array of +characters. Hence random access to characters is always fast. + +The C API provides functions to convert Javascript Strings to C UTF-8 encoded +strings. The most common case where the Javascript string contains +only ASCII characters involves no copying. + +@subsection Objects + +The object shapes (object prototype, property names and flags) are shared +between objects to save memory. + +Arrays with no holes (except at the end of the array) are optimized. + +TypedArray accesses are optimized. + +@subsection Atoms + +Object property names and some strings are stored as Atoms (unique +strings) to save memory and allow fast comparison. Atoms are +represented as a 32 bit integer. Half of the atom range is reserved for +immediate integer literals from @math{0} to @math{2^{31}-1}. + +@subsection Numbers + +Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 +floating point values. Most operations have fast paths for the 32-bit +integer case. + +@subsection Garbage collection + +Reference counting is used to free objects automatically and +deterministically. A separate cycle removal pass is done when the allocated +memory becomes too large. The cycle removal algorithm only uses the +reference counts and the object content, so no explicit garbage +collection roots need to be manipulated in the C code. + +@subsection JSValue + +It is a Javascript value which can be a primitive type (such as +Number, String, ...) or an Object. NaN boxing is used in the 32-bit version +to store 64-bit floating point numbers. The representation is +optimized so that 32-bit integers and reference counted values can be +efficiently tested. + +In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The +rationale is that in 64-bit code memory usage is less critical. + +In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, +so it can be efficiently returned by C functions. + +@subsection Function call + +The engine is optimized so that function calls are fast. The system +stack holds the Javascript parameters and local variables. + +@section RegExp + +A specific regular expression engine was developed. It is both small +and efficient and supports all the ES2023 features including the +Unicode properties. As the Javascript compiler, it directly generates +bytecode without a parse tree. + +Backtracking with an explicit stack is used so that there is no +recursion on the system stack. Simple quantifiers are specifically +optimized to avoid recursions. + +The full regexp library weights about 15 KiB (x86 code), excluding the +Unicode library. + +@section Unicode + +A specific Unicode library was developed so that there is no +dependency on an external large Unicode library such as ICU. All the +Unicode tables are compressed while keeping a reasonable access +speed. + +The library supports case conversion, Unicode normalization, Unicode +script queries, Unicode general category queries and all Unicode +binary properties. + +The full Unicode library weights about 45 KiB (x86 code). + +@section BigInt, BigFloat, BigDecimal + +BigInt, BigFloat and BigDecimal are implemented with the @code{libbf} +library@footnote{@url{https://bellard.org/libbf}}. It weights about 90 +KiB (x86 code) and provides arbitrary precision IEEE 754 floating +point operations and transcendental functions with exact rounding. + +@chapter License + +QuickJS is released under the MIT license. + +Unless otherwise specified, the QuickJS sources are copyright Fabrice +Bellard and Charlie Gordon. + +@bye diff --git a/deps/quickjs/examples/fib.c b/deps/quickjs/examples/fib.c new file mode 100644 index 0000000..c77b705 --- /dev/null +++ b/deps/quickjs/examples/fib.c @@ -0,0 +1,72 @@ +/* + * QuickJS: Example of C module + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../quickjs.h" + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +static int fib(int n) +{ + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib(n - 1) + fib(n - 2); +} + +static JSValue js_fib(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int n, res; + if (JS_ToInt32(ctx, &n, argv[0])) + return JS_EXCEPTION; + res = fib(n); + return JS_NewInt32(ctx, res); +} + +static const JSCFunctionListEntry js_fib_funcs[] = { + JS_CFUNC_DEF("fib", 1, js_fib ), +}; + +static int js_fib_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExportList(ctx, m, js_fib_funcs, + countof(js_fib_funcs)); +} + +#ifdef JS_SHARED_LIBRARY +#define JS_INIT_MODULE js_init_module +#else +#define JS_INIT_MODULE js_init_module_fib +#endif + +JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_fib_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); + return m; +} diff --git a/deps/quickjs/examples/fib_module.js b/deps/quickjs/examples/fib_module.js new file mode 100644 index 0000000..6a81071 --- /dev/null +++ b/deps/quickjs/examples/fib_module.js @@ -0,0 +1,10 @@ +/* fib module */ +export function fib(n) +{ + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib(n - 1) + fib(n - 2); +} diff --git a/deps/quickjs/examples/hello.js b/deps/quickjs/examples/hello.js new file mode 100644 index 0000000..accefce --- /dev/null +++ b/deps/quickjs/examples/hello.js @@ -0,0 +1 @@ +console.log("Hello World"); diff --git a/deps/quickjs/examples/hello_module.js b/deps/quickjs/examples/hello_module.js new file mode 100644 index 0000000..463660f --- /dev/null +++ b/deps/quickjs/examples/hello_module.js @@ -0,0 +1,6 @@ +/* example of JS module */ + +import { fib } from "./fib_module.js"; + +console.log("Hello World"); +console.log("fib(10)=", fib(10)); diff --git a/deps/quickjs/examples/pi_bigdecimal.js b/deps/quickjs/examples/pi_bigdecimal.js new file mode 100644 index 0000000..6a416b7 --- /dev/null +++ b/deps/quickjs/examples/pi_bigdecimal.js @@ -0,0 +1,68 @@ +/* + * PI computation in Javascript using the QuickJS bigdecimal type + * (decimal floating point) + */ +"use strict"; + +/* compute PI with a precision of 'prec' digits */ +function calc_pi(prec) { + const CHUD_A = 13591409m; + const CHUD_B = 545140134m; + const CHUD_C = 640320m; + const CHUD_C3 = 10939058860032000m; /* C^3/24 */ + const CHUD_DIGITS_PER_TERM = 14.18164746272548; /* log10(C/12)*3 */ + + /* return [P, Q, G] */ + function chud_bs(a, b, need_G) { + var c, P, Q, G, P1, Q1, G1, P2, Q2, G2, b1; + if (a == (b - 1n)) { + b1 = BigDecimal(b); + G = (2m * b1 - 1m) * (6m * b1 - 1m) * (6m * b1 - 5m); + P = G * (CHUD_B * b1 + CHUD_A); + if (b & 1n) + P = -P; + G = G; + Q = b1 * b1 * b1 * CHUD_C3; + } else { + c = (a + b) >> 1n; + [P1, Q1, G1] = chud_bs(a, c, true); + [P2, Q2, G2] = chud_bs(c, b, need_G); + P = P1 * Q2 + P2 * G1; + Q = Q1 * Q2; + if (need_G) + G = G1 * G2; + else + G = 0m; + } + return [P, Q, G]; + } + + var n, P, Q, G; + /* number of serie terms */ + n = BigInt(Math.ceil(prec / CHUD_DIGITS_PER_TERM)) + 10n; + [P, Q, G] = chud_bs(0n, n, false); + Q = BigDecimal.div(Q, (P + Q * CHUD_A), + { roundingMode: "half-even", + maximumSignificantDigits: prec }); + G = (CHUD_C / 12m) * BigDecimal.sqrt(CHUD_C, + { roundingMode: "half-even", + maximumSignificantDigits: prec }); + return Q * G; +} + +(function() { + var r, n_digits, n_bits; + if (typeof scriptArgs != "undefined") { + if (scriptArgs.length < 2) { + print("usage: pi n_digits"); + return; + } + n_digits = scriptArgs[1] | 0; + } else { + n_digits = 1000; + } + /* we add more digits to reduce the probability of bad rounding for + the last digits */ + r = calc_pi(n_digits + 20); + print(r.toFixed(n_digits, "down")); +})(); diff --git a/deps/quickjs/examples/pi_bigfloat.js b/deps/quickjs/examples/pi_bigfloat.js new file mode 100644 index 0000000..2bcda22 --- /dev/null +++ b/deps/quickjs/examples/pi_bigfloat.js @@ -0,0 +1,66 @@ +/* + * PI computation in Javascript using the QuickJS bigfloat type + * (binary floating point) + */ +"use strict"; + +/* compute PI with a precision of 'prec' bits */ +function calc_pi() { + const CHUD_A = 13591409n; + const CHUD_B = 545140134n; + const CHUD_C = 640320n; + const CHUD_C3 = 10939058860032000n; /* C^3/24 */ + const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ + + /* return [P, Q, G] */ + function chud_bs(a, b, need_G) { + var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; + if (a == (b - 1n)) { + G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); + P = BigFloat(G * (CHUD_B * b + CHUD_A)); + if (b & 1n) + P = -P; + G = BigFloat(G); + Q = BigFloat(b * b * b * CHUD_C3); + } else { + c = (a + b) >> 1n; + [P1, Q1, G1] = chud_bs(a, c, true); + [P2, Q2, G2] = chud_bs(c, b, need_G); + P = P1 * Q2 + P2 * G1; + Q = Q1 * Q2; + if (need_G) + G = G1 * G2; + else + G = 0l; + } + return [P, Q, G]; + } + + var n, P, Q, G; + /* number of serie terms */ + n = BigInt(Math.ceil(BigFloatEnv.prec / CHUD_BITS_PER_TERM)) + 10n; + [P, Q, G] = chud_bs(0n, n, false); + Q = Q / (P + Q * BigFloat(CHUD_A)); + G = BigFloat((CHUD_C / 12n)) * BigFloat.sqrt(BigFloat(CHUD_C)); + return Q * G; +} + +(function() { + var r, n_digits, n_bits; + if (typeof scriptArgs != "undefined") { + if (scriptArgs.length < 2) { + print("usage: pi n_digits"); + return; + } + n_digits = scriptArgs[1]; + } else { + n_digits = 1000; + } + n_bits = Math.ceil(n_digits * Math.log2(10)); + /* we add more bits to reduce the probability of bad rounding for + the last digits */ + BigFloatEnv.setPrec( () => { + r = calc_pi(); + print(r.toFixed(n_digits, BigFloatEnv.RNDZ)); + }, n_bits + 32); +})(); diff --git a/deps/quickjs/examples/pi_bigint.js b/deps/quickjs/examples/pi_bigint.js new file mode 100644 index 0000000..cbbb2c4 --- /dev/null +++ b/deps/quickjs/examples/pi_bigint.js @@ -0,0 +1,118 @@ +/* + * PI computation in Javascript using the BigInt type + */ +"use strict"; + +/* return floor(log2(a)) for a > 0 and 0 for a = 0 */ +function floor_log2(a) +{ + var k_max, a1, k, i; + k_max = 0n; + while ((a >> (2n ** k_max)) != 0n) { + k_max++; + } + k = 0n; + a1 = a; + for(i = k_max - 1n; i >= 0n; i--) { + a1 = a >> (2n ** i); + if (a1 != 0n) { + a = a1; + k |= (1n << i); + } + } + return k; +} + +/* return ceil(log2(a)) for a > 0 */ +function ceil_log2(a) +{ + return floor_log2(a - 1n) + 1n; +} + +/* return floor(sqrt(a)) (not efficient but simple) */ +function int_sqrt(a) +{ + var l, u, s; + if (a == 0n) + return a; + l = ceil_log2(a); + u = 1n << ((l + 1n) / 2n); + /* u >= floor(sqrt(a)) */ + for(;;) { + s = u; + u = ((a / s) + s) / 2n; + if (u >= s) + break; + } + return s; +} + +/* return pi * 2**prec */ +function calc_pi(prec) { + const CHUD_A = 13591409n; + const CHUD_B = 545140134n; + const CHUD_C = 640320n; + const CHUD_C3 = 10939058860032000n; /* C^3/24 */ + const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ + + /* return [P, Q, G] */ + function chud_bs(a, b, need_G) { + var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; + if (a == (b - 1n)) { + G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); + P = G * (CHUD_B * b + CHUD_A); + if (b & 1n) + P = -P; + Q = b * b * b * CHUD_C3; + } else { + c = (a + b) >> 1n; + [P1, Q1, G1] = chud_bs(a, c, true); + [P2, Q2, G2] = chud_bs(c, b, need_G); + P = P1 * Q2 + P2 * G1; + Q = Q1 * Q2; + if (need_G) + G = G1 * G2; + else + G = 0n; + } + return [P, Q, G]; + } + + var n, P, Q, G; + /* number of serie terms */ + n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; + [P, Q, G] = chud_bs(0n, n, false); + Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); + G = int_sqrt(CHUD_C << (2n * prec)); + return (Q * G) >> prec; +} + +function main(args) { + var r, n_digits, n_bits, out; + if (args.length < 1) { + print("usage: pi n_digits"); + return; + } + n_digits = args[0] | 0; + + /* we add more bits to reduce the probability of bad rounding for + the last digits */ + n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; + r = calc_pi(n_bits); + r = ((10n ** BigInt(n_digits)) * r) >> n_bits; + out = r.toString(); + print(out[0] + "." + out.slice(1)); +} + +var args; +if (typeof scriptArgs != "undefined") { + args = scriptArgs; + args.shift(); +} else if (typeof arguments != "undefined") { + args = arguments; +} else { + /* default: 1000 digits */ + args=[1000]; +} + +main(args); diff --git a/deps/quickjs/examples/point.c b/deps/quickjs/examples/point.c new file mode 100644 index 0000000..fbe2ce1 --- /dev/null +++ b/deps/quickjs/examples/point.c @@ -0,0 +1,151 @@ +/* + * QuickJS: Example of C module with a class + * + * Copyright (c) 2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../quickjs.h" +#include + +#define countof(x) (sizeof(x) / sizeof((x)[0])) + +/* Point Class */ + +typedef struct { + int x; + int y; +} JSPointData; + +static JSClassID js_point_class_id; + +static void js_point_finalizer(JSRuntime *rt, JSValue val) +{ + JSPointData *s = JS_GetOpaque(val, js_point_class_id); + /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ + js_free_rt(rt, s); +} + +static JSValue js_point_ctor(JSContext *ctx, + JSValueConst new_target, + int argc, JSValueConst *argv) +{ + JSPointData *s; + JSValue obj = JS_UNDEFINED; + JSValue proto; + + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &s->x, argv[0])) + goto fail; + if (JS_ToInt32(ctx, &s->y, argv[1])) + goto fail; + /* using new_target to get the prototype is necessary when the + class is extended. */ + proto = JS_GetPropertyStr(ctx, new_target, "prototype"); + if (JS_IsException(proto)) + goto fail; + obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); + JS_FreeValue(ctx, proto); + if (JS_IsException(obj)) + goto fail; + JS_SetOpaque(obj, s); + return obj; + fail: + js_free(ctx, s); + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + if (!s) + return JS_EXCEPTION; + if (magic == 0) + return JS_NewInt32(ctx, s->x); + else + return JS_NewInt32(ctx, s->y); +} + +static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + int v; + if (!s) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &v, val)) + return JS_EXCEPTION; + if (magic == 0) + s->x = v; + else + s->y = v; + return JS_UNDEFINED; +} + +static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); + if (!s) + return JS_EXCEPTION; + return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); +} + +static JSClassDef js_point_class = { + "Point", + .finalizer = js_point_finalizer, +}; + +static const JSCFunctionListEntry js_point_proto_funcs[] = { + JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), + JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), + JS_CFUNC_DEF("norm", 0, js_point_norm), +}; + +static int js_point_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue point_proto, point_class; + + /* create the Point class */ + JS_NewClassID(&js_point_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class); + + point_proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); + + point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); + /* set proto.constructor and ctor.prototype */ + JS_SetConstructor(ctx, point_class, point_proto); + JS_SetClassProto(ctx, js_point_class_id, point_proto); + + JS_SetModuleExport(ctx, m, "Point", point_class); + return 0; +} + +JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_point_init); + if (!m) + return NULL; + JS_AddModuleExport(ctx, m, "Point"); + return m; +} diff --git a/deps/quickjs/examples/test_fib.js b/deps/quickjs/examples/test_fib.js new file mode 100644 index 0000000..70d26bd --- /dev/null +++ b/deps/quickjs/examples/test_fib.js @@ -0,0 +1,6 @@ +/* example of JS module importing a C module */ + +import { fib } from "./fib.so"; + +console.log("Hello World"); +console.log("fib(10)=", fib(10)); diff --git a/deps/quickjs/examples/test_point.js b/deps/quickjs/examples/test_point.js new file mode 100644 index 0000000..0659bc3 --- /dev/null +++ b/deps/quickjs/examples/test_point.js @@ -0,0 +1,40 @@ +/* example of JS module importing a C module */ +import { Point } from "./point.so"; + +function assert(b, str) +{ + if (b) { + return; + } else { + throw Error("assertion failed: " + str); + } +} + +class ColorPoint extends Point { + constructor(x, y, color) { + super(x, y); + this.color = color; + } + get_color() { + return this.color; + } +}; + +function main() +{ + var pt, pt2; + + pt = new Point(2, 3); + assert(pt.x === 2); + assert(pt.y === 3); + pt.x = 4; + assert(pt.x === 4); + assert(pt.norm() == 5); + + pt2 = new ColorPoint(2, 3, 0xffffff); + assert(pt2.x === 2); + assert(pt2.color === 0xffffff); + assert(pt2.get_color() === 0xffffff); +} + +main(); diff --git a/quickjs/libbf.c b/deps/quickjs/libbf.c similarity index 99% rename from quickjs/libbf.c rename to deps/quickjs/libbf.c index d9601bf..234b956 100644 --- a/quickjs/libbf.c +++ b/deps/quickjs/libbf.c @@ -22,14 +22,11 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include -#include "my_stdint.h" -#include "my_inttypes.h" -#include +#include +#include #include -#include +#include #ifdef __AVX2__ #include @@ -40,10 +37,12 @@ /* enable it to check the multiplication result */ //#define USE_MUL_CHECK +#ifdef CONFIG_BIGNUM /* enable it to use FFT/NTT multiplication */ #define USE_FFT_MUL /* enable decimal floating point support */ #define USE_BF_DEC +#endif //#define inline __attribute__((always_inline)) @@ -167,6 +166,21 @@ static inline slimb_t sat_add(slimb_t a, slimb_t b) return r; } +static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift) +{ + if (shift != 0) + low = (low >> shift) | (high << (LIMB_BITS - shift)); + return low; +} + +static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift) +{ + if (shift != 0) + return (a1 << shift) | (a0 >> (LIMB_BITS - shift)); + else + return a1; +} + #define malloc(s) malloc_is_forbidden(s) #define free(p) free_is_forbidden(p) #define realloc(p, s) realloc_is_forbidden(p, s) @@ -239,7 +253,7 @@ int bf_set_ui(bf_t *r, uint64_t a) a1 = a >> 32; shift = clz(a1); r->tab[0] = a0 << shift; - r->tab[1] = (a1 << shift) | (a0 >> (LIMB_BITS - shift)); + r->tab[1] = shld(a1, a0, shift); r->expn = 2 * LIMB_BITS - shift; } #endif @@ -720,11 +734,10 @@ void bf_print_str(const char *str, const bf_t *a) if (a->expn == BF_EXP_NAN) { printf("NaN"); } else { - // TODO if (a->sign) - ;//putchar('-'); + putchar('-'); if (a->expn == BF_EXP_ZERO) { - ;//putchar('0'); + putchar('0'); } else if (a->expn == BF_EXP_INF) { printf("Inf"); } else { @@ -1589,7 +1602,9 @@ int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, r = &tmp; } if (bf_resize(r, a_len + b_len)) { +#ifdef USE_FFT_MUL fail: +#endif bf_set_nan(r); ret = BF_ST_MEM_ERROR; goto done; @@ -2286,11 +2301,14 @@ static int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, bf_t a; int ret; +#ifdef USE_BF_DEC if (a1 == 10 && b <= LIMB_DIGITS) { /* use precomputed powers. We do not round at this point because we expect the caller to do it */ ret = bf_set_ui(r, mp_pow_dec[b]); - } else { + } else +#endif + { bf_init(r->ctx, &a); ret = bf_set_ui(&a, a1); ret |= bf_pow_ui(r, &a, b, prec, flags); @@ -5396,21 +5414,6 @@ int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags) #endif /* LIMB_BITS != 64 */ -static inline __maybe_unused limb_t shrd(limb_t low, limb_t high, long shift) -{ - if (shift != 0) - low = (low >> shift) | (high << (LIMB_BITS - shift)); - return low; -} - -static inline __maybe_unused limb_t shld(limb_t a1, limb_t a0, long shift) -{ - if (shift != 0) - return (a1 << shift) | (a0 >> (LIMB_BITS - shift)); - else - return a1; -} - #if LIMB_DIGITS == 19 /* WARNING: hardcoded for b = 1e19. It is assumed that: @@ -6280,9 +6283,9 @@ void bfdec_print_str(const char *str, const bfdec_t *a) printf("NaN"); } else { if (a->sign) - ; //putchar('-'); + putchar('-'); if (a->expn == BF_EXP_ZERO) { - ; // putchar('0'); + putchar('0'); } else if (a->expn == BF_EXP_INF) { printf("Inf"); } else { diff --git a/quickjs/libbf.h b/deps/quickjs/libbf.h similarity index 99% rename from quickjs/libbf.h rename to deps/quickjs/libbf.h index 48e9d95..0457c18 100644 --- a/quickjs/libbf.h +++ b/deps/quickjs/libbf.h @@ -27,7 +27,7 @@ #include #include -#if INTPTR_MAX >= INT64_MAX +#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX) #define LIMB_LOG2_BITS 6 #else #define LIMB_LOG2_BITS 5 diff --git a/quickjs/libregexp-opcode.h b/deps/quickjs/libregexp-opcode.h similarity index 95% rename from quickjs/libregexp-opcode.h rename to deps/quickjs/libregexp-opcode.h index f90c23b..189d121 100644 --- a/quickjs/libregexp-opcode.h +++ b/deps/quickjs/libregexp-opcode.h @@ -50,8 +50,7 @@ DEF(range32, 3) /* variable length */ DEF(lookahead, 5) DEF(negative_lookahead, 5) DEF(push_char_pos, 1) /* push the character position on the stack */ -DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character - position */ +DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ DEF(prev, 1) /* go to the previous char */ DEF(simple_greedy_quant, 17) diff --git a/quickjs/libregexp.c b/deps/quickjs/libregexp.c similarity index 94% rename from quickjs/libregexp.c rename to deps/quickjs/libregexp.c index 6aef656..b6af454 100644 --- a/quickjs/libregexp.c +++ b/deps/quickjs/libregexp.c @@ -22,15 +22,11 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" #include -// #include -#include +#include #include -#include "my_string.h" -#include "my_assert.h" +#include #include "cutils.h" #include "libregexp.h" @@ -38,9 +34,6 @@ /* TODO: - - Add full unicode canonicalize rules for character ranges (not - really useful but needed for exact "ignorecase" compatibility). - - Add a lock step execution mode (=linear time execution guaranteed) when the regular expression is "simple" i.e. no backreference nor complicated lookahead. The opcodes are designed for this execution @@ -124,33 +117,6 @@ static int dbuf_insert(DynBuf *s, int pos, int len) return 0; } -/* canonicalize with the specific JS regexp rules */ -static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16) -{ - uint32_t res[LRE_CC_RES_LEN_MAX]; - int len; - if (is_utf16) { - if (likely(c < 128)) { - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - } else { - lre_case_conv(res, c, 2); - c = res[0]; - } - } else { - if (likely(c < 128)) { - if (c >= 'a' && c <= 'z') - c = c - 'a' + 'A'; - } else { - /* legacy regexp: to upper case if single char >= 128 */ - len = lre_case_conv(res, c, FALSE); - if (len == 1 && res[0] >= 128) - c = res[0]; - } - } - return c; -} - static const uint16_t char_range_d[] = { 1, 0x0030, 0x0039 + 1, @@ -249,31 +215,6 @@ static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) return -1; } -static int cr_canonicalize(CharRange *cr) -{ - CharRange a; - uint32_t pt[2]; - int i, ret; - - cr_init(&a, cr->mem_opaque, lre_realloc); - pt[0] = 'a'; - pt[1] = 'z' + 1; - ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER); - if (ret) - goto fail; - /* convert to upper case */ - /* XXX: the generic unicode case would be much more complicated - and not really useful */ - for(i = 0; i < a.len; i++) { - a.points[i] += 'A' - 'a'; - } - /* Note: for simplicity we keep the lower case ranges */ - ret = cr_union1(cr, a.points, a.len); - fail: - cr_free(&a); - return ret; -} - #ifdef DUMP_REOP static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, int buf_len) @@ -339,7 +280,6 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, case REOP_loop: case REOP_lookahead: case REOP_negative_lookahead: - case REOP_bne_char_pos: val = get_u32(buf + pos + 1); val += (pos + 5); printf(" %u", val); @@ -926,7 +866,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) } } if (s->ignore_case) { - if (cr_canonicalize(cr)) + if (cr_regexp_canonicalize(cr, s->is_utf16)) goto memory_error; } if (invert) { @@ -947,22 +887,17 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) } /* Return: - 1 if the opcodes in bc_buf[] always advance the character pointer. - 0 if the character pointer may not be advanced. - -1 if the code may depend on side effects of its previous execution (backreference) + - true if the opcodes may not advance the char pointer + - false if the opcodes always advance the char pointer */ -static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) +static BOOL re_need_check_advance(const uint8_t *bc_buf, int bc_buf_len) { - int pos, opcode, ret, len, i; - uint32_t val, last; - BOOL has_back_reference; - uint8_t capture_bitmap[CAPTURE_COUNT_MAX]; + int pos, opcode, len; + uint32_t val; + BOOL ret; - ret = -2; /* not known yet */ + ret = TRUE; pos = 0; - has_back_reference = FALSE; - memset(capture_bitmap, 0, sizeof(capture_bitmap)); - while (pos < bc_buf_len) { opcode = bc_buf[pos]; len = reopcode_info[opcode].size; @@ -980,8 +915,7 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) case REOP_dot: case REOP_any: simple_char: - if (ret == -2) - ret = 1; + ret = FALSE; break; case REOP_line_start: case REOP_line_end: @@ -995,41 +929,16 @@ static int re_check_advance(const uint8_t *bc_buf, int bc_buf_len) break; case REOP_save_start: case REOP_save_end: - val = bc_buf[pos + 1]; - capture_bitmap[val] |= 1; - break; case REOP_save_reset: - { - val = bc_buf[pos + 1]; - last = bc_buf[pos + 2]; - while (val < last) - capture_bitmap[val++] |= 1; - } - break; case REOP_back_reference: case REOP_backward_back_reference: - val = bc_buf[pos + 1]; - capture_bitmap[val] |= 2; - has_back_reference = TRUE; break; default: /* safe behvior: we cannot predict the outcome */ - if (ret == -2) - ret = 0; - break; + return TRUE; } pos += len; } - if (has_back_reference) { - /* check if there is back reference which references a capture - made in the some code */ - for(i = 0; i < CAPTURE_COUNT_MAX; i++) { - if (capture_bitmap[i] == 3) - return -1; - } - } - if (ret == -2) - ret = 0; return ret; } @@ -1075,11 +984,10 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len) } /* '*pp' is the first char after '<' */ -static int re_parse_group_name(char *buf, int buf_size, - const uint8_t **pp, BOOL is_utf16) +static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) { - const uint8_t *p; - uint32_t c; + const uint8_t *p, *p1; + uint32_t c, d; char *q; p = *pp; @@ -1090,11 +998,18 @@ static int re_parse_group_name(char *buf, int buf_size, p++; if (*p != 'u') return -1; - c = lre_parse_escape(&p, is_utf16 * 2); + c = lre_parse_escape(&p, 2); // accept surrogate pairs } else if (c == '>') { break; } else if (c >= 128) { c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + if (c >= 0xD800 && c <= 0xDBFF) { + d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); + if (d >= 0xDC00 && d <= 0xDFFF) { + c = 0x10000 + 0x400 * (c - 0xD800) + (d - 0xDC00); + p = p1; + } + } } else { p++; } @@ -1144,8 +1059,7 @@ static int re_parse_captures(REParseState *s, int *phas_named_captures, /* potential named capture */ if (capture_name) { p += 3; - if (re_parse_group_name(name, sizeof(name), &p, - s->is_utf16) == 0) { + if (re_parse_group_name(name, sizeof(name), &p) == 0) { if (!strcmp(name, capture_name)) return capture_index; } @@ -1318,7 +1232,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } else if (p[2] == '<') { p += 3; if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p, s->is_utf16)) { + &p)) { return re_parse_error(s, "invalid group name"); } if (find_group_name(s, s->u.tmp_buf) > 0) { @@ -1382,7 +1296,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } p1 += 3; if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), - &p1, s->is_utf16)) { + &p1)) { if (s->is_utf16 || re_has_named_captures(s)) return re_parse_error(s, "invalid group name"); else @@ -1595,8 +1509,12 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (dbuf_error(&s->byte_code)) goto out_of_memory; - add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start, - s->byte_code.size - last_atom_start) == 0); + /* the spec tells that if there is no advance when + running the atom after the first quant_min times, + then there is no match. We remove this test when we + are sure the atom always advances the position. */ + add_zero_advance_check = re_need_check_advance(s->byte_code.buf + last_atom_start, + s->byte_code.size - last_atom_start); } else { add_zero_advance_check = FALSE; } @@ -1616,38 +1534,34 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) } if (quant_max == 0) { s->byte_code.size = last_atom_start; - } else if (quant_max == 1) { - if (dbuf_insert(&s->byte_code, last_atom_start, 5)) - goto out_of_memory; - s->byte_code.buf[last_atom_start] = REOP_split_goto_first + - greedy; - put_u32(s->byte_code.buf + last_atom_start + 1, len); - } else if (quant_max == INT32_MAX) { + } else if (quant_max == 1 || quant_max == INT32_MAX) { + BOOL has_goto = (quant_max == INT32_MAX); if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check)) goto out_of_memory; s->byte_code.buf[last_atom_start] = REOP_split_goto_first + greedy; put_u32(s->byte_code.buf + last_atom_start + 1, - len + 5 + add_zero_advance_check); + len + 5 * has_goto + add_zero_advance_check * 2); if (add_zero_advance_check) { - /* avoid infinite loop by stoping the - recursion if no advance was made in the - atom (only works if the atom has no - side effect) */ s->byte_code.buf[last_atom_start + 1 + 4] = REOP_push_char_pos; - re_emit_goto(s, REOP_bne_char_pos, last_atom_start); - } else { - re_emit_goto(s, REOP_goto, last_atom_start); + re_emit_op(s, REOP_check_advance); } + if (has_goto) + re_emit_goto(s, REOP_goto, last_atom_start); } else { - if (dbuf_insert(&s->byte_code, last_atom_start, 10)) + if (dbuf_insert(&s->byte_code, last_atom_start, 10 + add_zero_advance_check)) goto out_of_memory; pos = last_atom_start; s->byte_code.buf[pos++] = REOP_push_i32; put_u32(s->byte_code.buf + pos, quant_max); pos += 4; s->byte_code.buf[pos++] = REOP_split_goto_first + greedy; - put_u32(s->byte_code.buf + pos, len + 5); + put_u32(s->byte_code.buf + pos, len + 5 + add_zero_advance_check * 2); + pos += 4; + if (add_zero_advance_check) { + s->byte_code.buf[pos++] = REOP_push_char_pos; + re_emit_op(s, REOP_check_advance); + } re_emit_goto(s, REOP_loop, last_atom_start + 5); re_emit_op(s, REOP_drop); } @@ -1671,22 +1585,25 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) if (quant_max == INT32_MAX) { pos = s->byte_code.size; re_emit_op_u32(s, REOP_split_goto_first + greedy, - len + 5 + add_zero_advance_check); + len + 5 + add_zero_advance_check * 2); if (add_zero_advance_check) re_emit_op(s, REOP_push_char_pos); /* copy the atom */ dbuf_put_self(&s->byte_code, last_atom_start, len); if (add_zero_advance_check) - re_emit_goto(s, REOP_bne_char_pos, pos); - else - re_emit_goto(s, REOP_goto, pos); + re_emit_op(s, REOP_check_advance); + re_emit_goto(s, REOP_goto, pos); } else if (quant_max > quant_min) { re_emit_op_u32(s, REOP_push_i32, quant_max - quant_min); pos = s->byte_code.size; - re_emit_op_u32(s, REOP_split_goto_first + greedy, len + 5); + re_emit_op_u32(s, REOP_split_goto_first + greedy, + len + 5 + add_zero_advance_check * 2); + if (add_zero_advance_check) + re_emit_op(s, REOP_push_char_pos); /* copy the atom */ dbuf_put_self(&s->byte_code, last_atom_start, len); - + if (add_zero_advance_check) + re_emit_op(s, REOP_check_advance); re_emit_goto(s, REOP_loop, pos); re_emit_op(s, REOP_drop); } @@ -1800,7 +1717,7 @@ static int compute_stack_size(const uint8_t *bc_buf, int bc_buf_len) } break; case REOP_drop: - case REOP_bne_char_pos: + case REOP_check_advance: assert(stack_size > 0); stack_size--; break; @@ -2296,11 +2213,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture, case REOP_push_char_pos: stack[stack_len++] = (uintptr_t)cptr; break; - case REOP_bne_char_pos: - val = get_u32(pc); - pc += 4; - if (stack[--stack_len] != (uintptr_t)cptr) - pc += (int)val; + case REOP_check_advance: + if (stack[--stack_len] == (uintptr_t)cptr) + goto no_match; break; case REOP_word_boundary: case REOP_not_word_boundary: diff --git a/quickjs/libregexp.h b/deps/quickjs/libregexp.h similarity index 97% rename from quickjs/libregexp.h rename to deps/quickjs/libregexp.h index 9aedb7e..c0bc58d 100644 --- a/quickjs/libregexp.h +++ b/deps/quickjs/libregexp.h @@ -36,6 +36,7 @@ #define LRE_FLAG_DOTALL (1 << 3) #define LRE_FLAG_UTF16 (1 << 4) #define LRE_FLAG_STICKY (1 << 5) +#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ diff --git a/quickjs/libunicode-table.h b/deps/quickjs/libunicode-table.h similarity index 69% rename from quickjs/libunicode-table.h rename to deps/quickjs/libunicode-table.h index 1727525..513ed94 100644 --- a/quickjs/libunicode-table.h +++ b/deps/quickjs/libunicode-table.h @@ -160,40 +160,41 @@ static const uint16_t case_conv_ext[58] = { 0x006b, 0x00e5, }; -static const uint8_t unicode_prop_Cased1_table[188] = { +static const uint8_t unicode_prop_Cased1_table[196] = { 0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3, 0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31, 0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6, - 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x57, 0x76, - 0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb, - 0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f, - 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28, - 0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b, - 0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79, - 0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94, - 0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0xa1, - 0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8c, 0x60, - 0x5c, 0x16, 0x01, 0x10, 0xa9, 0x80, 0x88, 0x60, - 0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, - 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, - 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, - 0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, + 0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x4b, 0x72, + 0x80, 0x4c, 0x02, 0xf8, 0x02, 0x80, 0x8f, 0x80, + 0xb0, 0x40, 0xdb, 0x08, 0x80, 0x41, 0xd0, 0x80, + 0x8c, 0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, + 0x00, 0x14, 0x28, 0x10, 0x11, 0x02, 0x01, 0x18, + 0x0b, 0x24, 0x4b, 0x26, 0x01, 0x01, 0x86, 0xe5, + 0x80, 0x60, 0x79, 0xb6, 0x81, 0x40, 0x91, 0x81, + 0xbd, 0x88, 0x94, 0x05, 0x80, 0x98, 0x80, 0xa2, + 0x00, 0x80, 0x9b, 0x12, 0x82, 0x43, 0x34, 0xa2, + 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15, 0x01, 0x10, + 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44, 0xd4, 0x80, + 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, + 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, + 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, + 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, - 0x47, 0x33, 0x89, 0x80, 0x93, 0x52, 0x10, 0x99, + 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x89, 0x80, + 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50, 0xc1, 0x99, 0x85, 0x99, 0x85, 0x99, }; -static const uint8_t unicode_prop_Cased1_index[18] = { - 0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6, - 0x40, 0x55, 0xd4, 0x61, 0xfb, 0xd6, 0x21, 0x8a, - 0xf1, 0x01, +static const uint8_t unicode_prop_Cased1_index[21] = { + 0xb9, 0x02, 0xe0, 0xc0, 0x1d, 0x20, 0xe5, 0x2c, + 0x20, 0xb1, 0x07, 0x21, 0xc1, 0xd6, 0x21, 0x4a, + 0xf1, 0x01, 0x8a, 0xf1, 0x01, }; -static const uint8_t unicode_prop_Case_Ignorable_table[720] = { +static const uint8_t unicode_prop_Case_Ignorable_table[737] = { 0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, 0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6, 0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40, @@ -215,7 +216,7 @@ static const uint8_t unicode_prop_Case_Ignorable_table[720] = { 0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81, 0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80, 0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a, - 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x85, 0xc9, + 0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8, 0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5, 0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f, @@ -256,34 +257,37 @@ static const uint8_t unicode_prop_Case_Ignorable_table[720] = { 0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9, 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83, - 0x41, 0x82, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83, - 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89, - 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, 0x80, - 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b, - 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11, - 0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94, - 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40, - 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28, - 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81, - 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00, - 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, 0x84, 0x41, - 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80, - 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7, - 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c, - 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95, - 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30, - 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81, - 0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba, - 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90, - 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, 0x18, 0x30, - 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad, - 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e, - 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, - 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, - 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x41, - 0x04, 0x8d, 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x45, - 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, 0x6c, - 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, 0xef, + 0x41, 0x82, 0x81, 0xcf, 0x82, 0xc5, 0x8a, 0xb0, + 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, + 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, + 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, + 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, + 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c, 0x02, + 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, + 0x84, 0x40, 0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, + 0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, + 0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, + 0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, + 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff, 0x08, + 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, + 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, + 0xad, 0x8c, 0x01, 0x41, 0x95, 0x30, 0x28, 0x80, + 0xd1, 0x95, 0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, + 0x08, 0x30, 0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, + 0x5a, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80, + 0x54, 0xec, 0x90, 0x85, 0x8e, 0x60, 0x36, 0x99, + 0x84, 0xba, 0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, + 0xbe, 0x90, 0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, + 0x18, 0x30, 0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, + 0x5b, 0xad, 0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, + 0x8f, 0x0e, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, + 0xba, 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, + 0x20, 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, + 0x04, 0x84, 0xbd, 0xa0, 0x80, 0x40, 0x9f, 0x8d, + 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x41, 0xfa, 0x84, + 0x43, 0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, + 0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, + 0xef, }; static const uint8_t unicode_prop_Case_Ignorable_index[69] = { @@ -292,13 +296,13 @@ static const uint8_t unicode_prop_Case_Ignorable_index[69] = { 0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20, 0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0, 0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56, - 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x82, 0x10, 0x21, - 0x02, 0x13, 0x21, 0xb8, 0x16, 0x61, 0x97, 0x1a, - 0x01, 0x37, 0x6b, 0x21, 0x8c, 0xd1, 0x01, 0xd7, - 0xe8, 0x41, 0xf0, 0x01, 0x0e, + 0xfe, 0x20, 0xb1, 0x07, 0x01, 0x75, 0x10, 0x01, + 0xeb, 0x12, 0x21, 0x41, 0x16, 0x01, 0x5c, 0x1a, + 0x01, 0x43, 0x1f, 0x01, 0x2e, 0xcf, 0x41, 0x25, + 0xe0, 0x01, 0xf0, 0x01, 0x0e, }; -static const uint8_t unicode_prop_ID_Start_table[1079] = { +static const uint8_t unicode_prop_ID_Start_table[1100] = { 0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03, 0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83, 0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20, @@ -392,51 +396,54 @@ static const uint8_t unicode_prop_ID_Start_table[1079] = { 0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, 0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, - 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0xd3, - 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, 0xae, - 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, 0x10, - 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 0xb4, 0x91, - 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, 0x08, 0x80, - 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, 0xaf, 0x93, - 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, 0x9a, 0xa4, - 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, 0x9e, 0x39, - 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd, - 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89, - 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80, - 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90, - 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94, - 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41, - 0x46, 0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99, - 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, - 0x8e, 0x44, 0x2e, 0x4f, 0xd0, 0x42, 0x46, 0x60, + 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, + 0x81, 0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, + 0x86, 0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, + 0x04, 0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, + 0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, + 0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, + 0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, + 0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, + 0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, + 0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, + 0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, + 0x92, 0x80, 0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, + 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, + 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, + 0x80, 0x41, 0x46, 0x92, 0x8e, 0x00, 0x8c, 0x80, + 0xa1, 0xfb, 0x80, 0xce, 0x43, 0x99, 0xe5, 0xee, + 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0, 0x8e, 0x44, + 0x2f, 0x90, 0x85, 0x4f, 0xb8, 0x42, 0x46, 0x60, 0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce, 0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94, 0x84, 0x92, 0x42, 0xaf, 0xbf, 0xff, 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x22, 0xe6, - 0x18, 0x30, 0x08, 0x41, 0x22, 0xac, 0x82, 0x90, - 0x1f, 0x41, 0x8b, 0x49, 0x03, 0xea, 0x84, 0x8c, - 0x82, 0x88, 0x86, 0x89, 0x57, 0x65, 0xd4, 0x80, - 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, - 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, - 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, - 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, - 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x9e, 0x41, - 0xe0, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, - 0x9d, 0x91, 0xab, 0x44, 0xf3, 0x30, 0x18, 0x08, - 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, - 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, - 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, - 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, - 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, - 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40, - 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c, - 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, 0x4a, + 0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c, + 0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03, + 0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57, + 0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, + 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, + 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, + 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, + 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, + 0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91, + 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d, + 0x91, 0xab, 0x41, 0xe3, 0x9b, 0x42, 0xf3, 0x30, + 0x18, 0x08, 0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, + 0x30, 0x44, 0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, + 0x51, 0x43, 0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x39, + 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, + 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, + 0x4a, 0x84, 0x50, 0x5f, }; -static const uint8_t unicode_prop_ID_Start_index[102] = { +static const uint8_t unicode_prop_ID_Start_index[105] = { 0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09, 0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b, 0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00, @@ -445,14 +452,15 @@ static const uint8_t unicode_prop_ID_Start_index[102] = { 0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20, 0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02, 0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3, - 0x0c, 0x21, 0x73, 0x11, 0x61, 0x3e, 0x13, 0x01, - 0x47, 0x17, 0x21, 0x9e, 0x1a, 0x01, 0x9a, 0x23, - 0x01, 0x78, 0x6b, 0x01, 0xfc, 0xb2, 0x61, 0x3a, - 0xd5, 0x01, 0x2d, 0xe1, 0x41, 0x33, 0xee, 0x01, - 0xe0, 0xa6, 0x62, 0x4b, 0x13, 0x03, + 0x0c, 0x21, 0x73, 0x11, 0x61, 0x34, 0x13, 0x01, + 0x1b, 0x17, 0x21, 0x8a, 0x1a, 0x01, 0x34, 0x1f, + 0x21, 0xbf, 0x6a, 0x01, 0x23, 0xb1, 0xa1, 0xad, + 0xd4, 0x01, 0x6f, 0xd7, 0x01, 0xff, 0xe7, 0x61, + 0x5e, 0xee, 0x01, 0xe1, 0xeb, 0x22, 0xb0, 0x23, + 0x03, }; -static const uint8_t unicode_prop_ID_Continue1_table[640] = { +static const uint8_t unicode_prop_ID_Continue1_table[660] = { 0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47, 0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08, 0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, @@ -470,85 +478,88 @@ static const uint8_t unicode_prop_ID_Continue1_table[640] = { 0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, 0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30, - 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x8f, 0x83, - 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, 0x89, - 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, 0x00, - 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, 0x38, - 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x29, 0x89, 0xbd, - 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, 0xb0, - 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, - 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, 0x11, - 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, 0xbe, - 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, 0x82, - 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, 0x01, - 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, 0xf5, - 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, 0xbb, - 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, 0x85, - 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, 0xae, - 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, 0x9d, - 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, 0x87, - 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, 0x28, - 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, 0x92, - 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, 0xfd, - 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, 0x29, - 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, 0xc4, - 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, 0x0f, - 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, 0x81, - 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, 0x8a, - 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, 0x8d, - 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, 0x8d, - 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, 0x00, - 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, 0x40, - 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, 0x80, - 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, 0x82, - 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, 0x80, - 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24, - 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13, - 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89, - 0x41, 0x70, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83, - 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89, - 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3, - 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, 0x8b, 0x82, - 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28, - 0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b, 0xb6, 0x08, - 0x31, 0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x32, - 0x84, 0x40, 0xbf, 0x91, 0x88, 0x89, 0x18, 0xd0, - 0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31, 0x88, 0x9a, - 0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0, 0x8c, 0x87, - 0x89, 0xd2, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e, - 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00, - 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b, - 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad, - 0x8f, 0x41, 0x94, 0x38, 0x87, 0x8f, 0x89, 0xb7, - 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, 0x30, - 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89, 0x41, - 0x48, 0x83, 0x60, 0x4b, 0x68, 0x89, 0xd5, 0x89, - 0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, - 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, - 0x4c, 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, - 0x42, 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, - 0x40, 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, - 0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, - 0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, - 0x41, 0x04, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, - 0xbc, 0x8d, 0x45, 0xd5, 0x86, 0xec, 0x34, 0x89, - 0x52, 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef, + 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b, + 0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, + 0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, + 0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, + 0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89, + 0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, + 0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, + 0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, + 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, + 0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, + 0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, + 0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, + 0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, + 0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, + 0x85, 0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, + 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, + 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, + 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, + 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, + 0x92, 0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, + 0xfd, 0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, + 0x29, 0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, + 0xc4, 0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, + 0x0f, 0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, + 0x81, 0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, + 0x8a, 0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, + 0x8d, 0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, + 0x8d, 0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, + 0x00, 0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, + 0x40, 0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, + 0x80, 0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, + 0x82, 0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, + 0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, + 0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, + 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, + 0x89, 0x41, 0x70, 0x81, 0xcf, 0x82, 0xc5, 0x8a, + 0xb0, 0x83, 0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, + 0x09, 0x89, 0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, + 0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, + 0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, + 0x8b, 0x28, 0x08, 0x40, 0x9c, 0x8b, 0x84, 0x89, + 0x2b, 0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, + 0x89, 0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, + 0x89, 0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, + 0x31, 0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, + 0xd0, 0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89, + 0x40, 0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, + 0x09, 0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, + 0x32, 0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, + 0x88, 0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87, + 0x8f, 0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, + 0x00, 0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, + 0x27, 0x89, 0x41, 0x48, 0x83, 0x88, 0x08, 0x80, + 0xaf, 0x32, 0x84, 0x8c, 0x89, 0x54, 0xe5, 0x05, + 0x8e, 0x60, 0x36, 0x09, 0x89, 0xd5, 0x89, 0xa5, + 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4, 0x00, + 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60, 0x4c, + 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96, 0x42, + 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, + 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, + 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, + 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, + 0x80, 0x40, 0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, + 0x80, 0xbc, 0x8d, 0x41, 0xf1, 0x8d, 0x43, 0xd5, + 0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, + 0x05, 0x05, 0x40, 0xef, }; -static const uint8_t unicode_prop_ID_Continue1_index[60] = { +static const uint8_t unicode_prop_ID_Continue1_index[63] = { 0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a, - 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x40, 0xc7, - 0x0f, 0x00, 0xea, 0x17, 0x20, 0x45, 0x1b, 0x20, - 0x55, 0x20, 0x20, 0x0c, 0xa8, 0x60, 0x37, 0xaa, - 0x00, 0x50, 0xfe, 0x00, 0x3a, 0x0d, 0x01, 0x83, - 0x11, 0x01, 0xc4, 0x14, 0x21, 0x44, 0x19, 0x21, - 0x5a, 0x1d, 0x41, 0x9f, 0xbc, 0x61, 0xb0, 0xda, - 0x21, 0xf0, 0x01, 0x0e, + 0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x60, 0xc7, + 0x0f, 0x20, 0xea, 0x17, 0x40, 0x05, 0x1b, 0x00, + 0x41, 0x20, 0x00, 0x0c, 0xa8, 0x80, 0x37, 0xaa, + 0x20, 0x50, 0xfe, 0x20, 0x3a, 0x0d, 0x21, 0x74, + 0x11, 0x01, 0x5a, 0x14, 0x21, 0x44, 0x19, 0x81, + 0x5a, 0x1d, 0xa1, 0xf5, 0x6a, 0x21, 0x45, 0xd2, + 0x41, 0xaf, 0xe2, 0x21, 0xf0, 0x01, 0x0e, }; #ifdef CONFIG_ALL_UNICODE -static const uint8_t unicode_cc_table[881] = { +static const uint8_t unicode_cc_table[899] = { 0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00, 0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03, 0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03, @@ -631,38 +642,40 @@ static const uint8_t unicode_cc_table[881] = { 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, - 0x52, 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00, - 0xdc, 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00, - 0xdc, 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09, - 0xa8, 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08, - 0x00, 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf, - 0x01, 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b, - 0x00, 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00, - 0x09, 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00, - 0x09, 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09, - 0x97, 0xc6, 0x82, 0xc4, 0xb0, 0x9c, 0x00, 0x09, - 0x82, 0x00, 0x07, 0x96, 0xc0, 0xb0, 0x32, 0x00, - 0x09, 0x00, 0x07, 0xb0, 0xca, 0x00, 0x09, 0x00, - 0x07, 0xb0, 0x4d, 0x00, 0x09, 0xb0, 0x45, 0x00, - 0x09, 0x00, 0x07, 0xb0, 0x42, 0x00, 0x09, 0xb0, - 0xdc, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xd1, 0x01, - 0x09, 0x83, 0x00, 0x07, 0xb0, 0x6b, 0x00, 0x09, - 0xb0, 0x22, 0x00, 0x09, 0x91, 0x00, 0x09, 0xb0, - 0x20, 0x00, 0x09, 0xb1, 0x74, 0x00, 0x09, 0xb0, - 0xd1, 0x00, 0x07, 0x80, 0x01, 0x09, 0xb0, 0x20, - 0x00, 0x09, 0xb8, 0x45, 0x27, 0x04, 0x01, 0xb0, + 0x52, 0xc1, 0xb0, 0x1f, 0x02, 0xdc, 0xb0, 0x15, + 0x01, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc, + 0xb0, 0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, + 0xb0, 0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d, + 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07, + 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d, + 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00, + 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01, + 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4, + 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07, 0x96, + 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d, 0x00, + 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07, 0xb0, + 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09, 0x00, + 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00, 0x07, + 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00, 0x09, + 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, + 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07, 0x80, + 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb1, 0x78, + 0x01, 0x09, 0xb8, 0x43, 0x7c, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0, - 0xd4, 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3, - 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00, - 0x07, + 0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0, + 0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00, + 0xdc, 0xc0, 0xb3, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, + 0xc5, 0x00, 0x07, }; -static const uint8_t unicode_cc_index[84] = { +static const uint8_t unicode_cc_index[87] = { 0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05, 0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c, 0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00, @@ -670,13 +683,13 @@ static const uint8_t unicode_cc_index[84] = { 0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3, 0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00, 0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab, - 0x00, 0x39, 0x0a, 0x01, 0x84, 0x0f, 0x21, 0xc0, - 0x11, 0x01, 0x43, 0x14, 0x01, 0x39, 0x18, 0x21, - 0x42, 0x1d, 0x21, 0x67, 0xd1, 0x01, 0x30, 0xe1, - 0x21, 0x4b, 0xe9, 0x01, + 0x00, 0x39, 0x0a, 0x01, 0x51, 0x0f, 0x01, 0x73, + 0x11, 0x01, 0x75, 0x13, 0x01, 0x2b, 0x17, 0x21, + 0x3f, 0x1c, 0x21, 0x9e, 0xbc, 0x21, 0x08, 0xe0, + 0x01, 0x44, 0xe9, 0x01, 0x4b, 0xe9, 0x01, }; -static const uint32_t unicode_decomp_table1[693] = { +static const uint32_t unicode_decomp_table1[699] = { 0x00280081, 0x002a0097, 0x002a8081, 0x002bc097, 0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097, 0x002e4115, 0x002f0199, 0x00302016, 0x00400842, @@ -840,20 +853,21 @@ static const uint32_t unicode_decomp_table1[693] = { 0x75e24081, 0x75e2832d, 0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081, 0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f, 0x75f6051f, 0x75f8851f, - 0x75fb051f, 0x75fd851f, 0x7b80022d, 0x7b814dad, - 0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403, - 0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad, - 0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521, - 0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117, - 0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097, - 0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081, - 0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f, - 0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910, - 0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90, - 0xbe69bc10, + 0x75fb051f, 0x75fd851f, 0x780c049f, 0x780e419f, + 0x780f059f, 0x7811c203, 0x7812d0ad, 0x781b0103, + 0x7b80022d, 0x7b814dad, 0x7b884203, 0x7b89c081, + 0x7b8a452d, 0x7b8d0403, 0x7b908081, 0x7b91dc03, + 0x7ba0052d, 0x7ba2c8ad, 0x7ba84483, 0x7baac8ad, + 0x7c400097, 0x7c404521, 0x7c440d25, 0x7c4a8087, + 0x7c4ac115, 0x7c4b4117, 0x7c4c0d1f, 0x7c528217, + 0x7c538099, 0x7c53c097, 0x7c5a8197, 0x7c640097, + 0x7c80012f, 0x7c808081, 0x7c841603, 0x7c9004c1, + 0x7c940103, 0x7efc051f, 0xbe0001ac, 0xbe00d110, + 0xbe0947ac, 0xbe0d3910, 0xbe29872c, 0xbe2d022c, + 0xbe2e3790, 0xbe49ff90, 0xbe69bc10, }; -static const uint16_t unicode_decomp_table2[693] = { +static const uint16_t unicode_decomp_table2[699] = { 0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008, 0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3, 0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8, @@ -935,15 +949,16 @@ static const uint16_t unicode_decomp_table2[693] = { 0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207, 0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4, 0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202, - 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0e, - 0x1e2b, 0x062d, 0x1e33, 0x1e3f, 0x062c, 0x1e4f, 0x1ebf, 0x1ecb, - 0x1ede, 0x1ef0, 0x1f03, 0x1f05, 0x1f09, 0x1f0f, 0x1f15, 0x1f17, - 0x1f1b, 0x1f1d, 0x1f25, 0x1f28, 0x1f2a, 0x1f30, 0x1f32, 0x30b5, - 0x1f38, 0x1f90, 0x1fa6, 0x1faa, 0x1fac, 0x1fb1, 0x1ffe, 0x200f, - 0x2110, 0x2120, 0x2126, 0x2220, 0x233e, + 0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0a, + 0x1e0c, 0x1e0e, 0x1e16, 0x1e39, 0x1e3d, 0x1e43, 0x1e60, 0x062d, + 0x1e68, 0x1e74, 0x062c, 0x1e84, 0x1ef4, 0x1f00, 0x1f13, 0x1f25, + 0x1f38, 0x1f3a, 0x1f3e, 0x1f44, 0x1f4a, 0x1f4c, 0x1f50, 0x1f52, + 0x1f5a, 0x1f5d, 0x1f5f, 0x1f65, 0x1f67, 0x30b5, 0x1f6d, 0x1fc5, + 0x1fdb, 0x1fdf, 0x1fe1, 0x1fe6, 0x2033, 0x2044, 0x2145, 0x2155, + 0x215b, 0x2255, 0x2373, }; -static const uint8_t unicode_decomp_data[9292] = { +static const uint8_t unicode_decomp_data[9345] = { 0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81, 0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31, 0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41, @@ -1905,207 +1920,214 @@ static const uint8_t unicode_decomp_data[9292] = { 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, - 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06, - 0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b, - 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, - 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44, - 0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00, - 0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11, - 0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34, - 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, - 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d, - 0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44, - 0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39, - 0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00, - 0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e, - 0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, - 0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f, - 0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00, - 0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d, - 0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00, - 0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39, - 0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00, - 0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, - 0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a, - 0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27, - 0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b, - 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, - 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, - 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06, - 0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06, - 0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, + 0x30, 0x04, 0x3a, 0x04, 0x3e, 0x04, 0x4b, 0x04, + 0x4d, 0x04, 0x4e, 0x04, 0x89, 0xa6, 0x30, 0x04, + 0xa9, 0x26, 0x28, 0xb9, 0x7f, 0x9f, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0a, + 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x1a, 0x1b, 0x61, 0x26, 0x25, 0x2f, + 0x7b, 0x51, 0xa6, 0xb1, 0x04, 0x27, 0x06, 0x00, + 0x01, 0x05, 0x08, 0x2a, 0x06, 0x1e, 0x08, 0x03, + 0x0d, 0x20, 0x19, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, + 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, + 0x06, 0x0c, 0x0e, 0x10, 0x44, 0x90, 0x77, 0x45, + 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, + 0x33, 0x06, 0x17, 0x10, 0x11, 0x12, 0x13, 0x00, + 0x06, 0x0e, 0x02, 0x0f, 0x34, 0x06, 0x2a, 0x06, + 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, + 0x00, 0x00, 0x3a, 0x06, 0x2d, 0x06, 0x00, 0x00, + 0x4a, 0x06, 0x00, 0x00, 0x44, 0x06, 0x00, 0x00, + 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x00, 0x00, + 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x2e, 0x06, 0x00, 0x00, + 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x00, 0x00, + 0xba, 0x06, 0x00, 0x00, 0x6f, 0x06, 0x00, 0x00, + 0x28, 0x06, 0x2c, 0x06, 0x00, 0x00, 0x47, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x2d, 0x06, 0x37, 0x06, + 0x4a, 0x06, 0x43, 0x06, 0x00, 0x00, 0x45, 0x06, + 0x46, 0x06, 0x33, 0x06, 0x39, 0x06, 0x41, 0x06, + 0x35, 0x06, 0x42, 0x06, 0x00, 0x00, 0x34, 0x06, + 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00, 0x00, + 0x36, 0x06, 0x38, 0x06, 0x3a, 0x06, 0x6e, 0x06, + 0x00, 0x00, 0xa1, 0x06, 0x27, 0x06, 0x00, 0x01, + 0x05, 0x08, 0x20, 0x21, 0x0b, 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06, - 0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c, - 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14, - 0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43, - 0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d, - 0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56, - 0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52, - 0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68, - 0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30, - 0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59, - 0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65, - 0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65, - 0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c, - 0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62, - 0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90, - 0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63, - 0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a, - 0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67, - 0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91, - 0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e, - 0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62, - 0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f, - 0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00, - 0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb, - 0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7, - 0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d, - 0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c, - 0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b, - 0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac, - 0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03, - 0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72, - 0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20, - 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52, - 0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82, - 0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, - 0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63, - 0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e, - 0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2, - 0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63, - 0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab, - 0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06, - 0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07, - 0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d, - 0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac, - 0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06, - 0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8, - 0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27, - 0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc, - 0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, - 0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, - 0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53, - 0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e, - 0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43, - 0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, - 0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd, - 0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62, - 0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3, - 0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe, - 0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22, - 0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda, - 0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a, - 0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81, - 0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4, - 0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, - 0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, - 0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02, - 0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46, - 0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3, - 0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b, - 0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63, - 0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63, - 0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64, - 0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65, - 0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66, - 0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b, - 0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67, - 0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67, - 0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67, - 0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67, - 0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68, - 0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69, - 0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36, - 0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38, - 0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b, - 0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, - 0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, - 0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d, - 0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d, - 0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e, - 0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, - 0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, - 0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70, - 0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70, - 0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71, - 0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72, - 0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72, - 0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, - 0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20, - 0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20, - 0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e, - 0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74, - 0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74, - 0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75, - 0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76, - 0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f, - 0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50, - 0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77, - 0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77, - 0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78, - 0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56, - 0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79, - 0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a, - 0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a, - 0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b, - 0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c, - 0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d, - 0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d, - 0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62, - 0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f, - 0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80, - 0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65, - 0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80, - 0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a, - 0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33, - 0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44, - 0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52, - 0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82, - 0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83, - 0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83, - 0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83, - 0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00, - 0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20, - 0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02, - 0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c, - 0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85, - 0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45, - 0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45, - 0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86, - 0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86, - 0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87, - 0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45, - 0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88, - 0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34, - 0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46, - 0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c, - 0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, - 0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d, - 0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e, - 0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90, - 0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91, - 0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92, - 0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95, - 0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49, - 0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91, - 0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97, - 0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98, - 0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98, - 0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99, - 0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b, - 0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c, - 0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1, - 0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d, - 0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f, - 0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88, - 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28, - 0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80, - 0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00, - 0x20, 0x2a, 0x00, 0x80, + 0x0c, 0x0e, 0x10, 0x28, 0x06, 0x2c, 0x06, 0x2f, + 0x06, 0x00, 0x00, 0x48, 0x06, 0x32, 0x06, 0x2d, + 0x06, 0x37, 0x06, 0x4a, 0x06, 0x2a, 0x06, 0x1a, + 0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, + 0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, + 0x30, 0x2e, 0x30, 0x00, 0x2c, 0x00, 0x28, 0x00, + 0x41, 0x00, 0x29, 0x00, 0x14, 0x30, 0x53, 0x00, + 0x15, 0x30, 0x43, 0x52, 0x43, 0x44, 0x57, 0x5a, + 0x41, 0x00, 0x48, 0x56, 0x4d, 0x56, 0x53, 0x44, + 0x53, 0x53, 0x50, 0x50, 0x56, 0x57, 0x43, 0x4d, + 0x43, 0x4d, 0x44, 0x4d, 0x52, 0x44, 0x4a, 0x4b, + 0x30, 0x30, 0x00, 0x68, 0x68, 0x4b, 0x62, 0x57, + 0x5b, 0xcc, 0x53, 0xc7, 0x30, 0x8c, 0x4e, 0x1a, + 0x59, 0xe3, 0x89, 0x29, 0x59, 0xa4, 0x4e, 0x20, + 0x66, 0x21, 0x71, 0x99, 0x65, 0x4d, 0x52, 0x8c, + 0x5f, 0x8d, 0x51, 0xb0, 0x65, 0x1d, 0x52, 0x42, + 0x7d, 0x1f, 0x75, 0xa9, 0x8c, 0xf0, 0x58, 0x39, + 0x54, 0x14, 0x6f, 0x95, 0x62, 0x55, 0x63, 0x00, + 0x4e, 0x09, 0x4e, 0x4a, 0x90, 0xe6, 0x5d, 0x2d, + 0x4e, 0xf3, 0x53, 0x07, 0x63, 0x70, 0x8d, 0x53, + 0x62, 0x81, 0x79, 0x7a, 0x7a, 0x08, 0x54, 0x80, + 0x6e, 0x09, 0x67, 0x08, 0x67, 0x33, 0x75, 0x72, + 0x52, 0xb6, 0x55, 0x4d, 0x91, 0x14, 0x30, 0x15, + 0x30, 0x2c, 0x67, 0x09, 0x4e, 0x8c, 0x4e, 0x89, + 0x5b, 0xb9, 0x70, 0x53, 0x62, 0xd7, 0x76, 0xdd, + 0x52, 0x57, 0x65, 0x97, 0x5f, 0xef, 0x53, 0x30, + 0x00, 0x38, 0x4e, 0x05, 0x00, 0x09, 0x22, 0x01, + 0x60, 0x4f, 0xae, 0x4f, 0xbb, 0x4f, 0x02, 0x50, + 0x7a, 0x50, 0x99, 0x50, 0xe7, 0x50, 0xcf, 0x50, + 0x9e, 0x34, 0x3a, 0x06, 0x4d, 0x51, 0x54, 0x51, + 0x64, 0x51, 0x77, 0x51, 0x1c, 0x05, 0xb9, 0x34, + 0x67, 0x51, 0x8d, 0x51, 0x4b, 0x05, 0x97, 0x51, + 0xa4, 0x51, 0xcc, 0x4e, 0xac, 0x51, 0xb5, 0x51, + 0xdf, 0x91, 0xf5, 0x51, 0x03, 0x52, 0xdf, 0x34, + 0x3b, 0x52, 0x46, 0x52, 0x72, 0x52, 0x77, 0x52, + 0x15, 0x35, 0x02, 0x00, 0x20, 0x80, 0x80, 0x00, + 0x08, 0x00, 0x00, 0xc7, 0x52, 0x00, 0x02, 0x1d, + 0x33, 0x3e, 0x3f, 0x50, 0x82, 0x8a, 0x93, 0xac, + 0xb6, 0xb8, 0xb8, 0xb8, 0x2c, 0x0a, 0x70, 0x70, + 0xca, 0x53, 0xdf, 0x53, 0x63, 0x0b, 0xeb, 0x53, + 0xf1, 0x53, 0x06, 0x54, 0x9e, 0x54, 0x38, 0x54, + 0x48, 0x54, 0x68, 0x54, 0xa2, 0x54, 0xf6, 0x54, + 0x10, 0x55, 0x53, 0x55, 0x63, 0x55, 0x84, 0x55, + 0x84, 0x55, 0x99, 0x55, 0xab, 0x55, 0xb3, 0x55, + 0xc2, 0x55, 0x16, 0x57, 0x06, 0x56, 0x17, 0x57, + 0x51, 0x56, 0x74, 0x56, 0x07, 0x52, 0xee, 0x58, + 0xce, 0x57, 0xf4, 0x57, 0x0d, 0x58, 0x8b, 0x57, + 0x32, 0x58, 0x31, 0x58, 0xac, 0x58, 0xe4, 0x14, + 0xf2, 0x58, 0xf7, 0x58, 0x06, 0x59, 0x1a, 0x59, + 0x22, 0x59, 0x62, 0x59, 0xa8, 0x16, 0xea, 0x16, + 0xec, 0x59, 0x1b, 0x5a, 0x27, 0x5a, 0xd8, 0x59, + 0x66, 0x5a, 0xee, 0x36, 0xfc, 0x36, 0x08, 0x5b, + 0x3e, 0x5b, 0x3e, 0x5b, 0xc8, 0x19, 0xc3, 0x5b, + 0xd8, 0x5b, 0xe7, 0x5b, 0xf3, 0x5b, 0x18, 0x1b, + 0xff, 0x5b, 0x06, 0x5c, 0x53, 0x5f, 0x22, 0x5c, + 0x81, 0x37, 0x60, 0x5c, 0x6e, 0x5c, 0xc0, 0x5c, + 0x8d, 0x5c, 0xe4, 0x1d, 0x43, 0x5d, 0xe6, 0x1d, + 0x6e, 0x5d, 0x6b, 0x5d, 0x7c, 0x5d, 0xe1, 0x5d, + 0xe2, 0x5d, 0x2f, 0x38, 0xfd, 0x5d, 0x28, 0x5e, + 0x3d, 0x5e, 0x69, 0x5e, 0x62, 0x38, 0x83, 0x21, + 0x7c, 0x38, 0xb0, 0x5e, 0xb3, 0x5e, 0xb6, 0x5e, + 0xca, 0x5e, 0x92, 0xa3, 0xfe, 0x5e, 0x31, 0x23, + 0x31, 0x23, 0x01, 0x82, 0x22, 0x5f, 0x22, 0x5f, + 0xc7, 0x38, 0xb8, 0x32, 0xda, 0x61, 0x62, 0x5f, + 0x6b, 0x5f, 0xe3, 0x38, 0x9a, 0x5f, 0xcd, 0x5f, + 0xd7, 0x5f, 0xf9, 0x5f, 0x81, 0x60, 0x3a, 0x39, + 0x1c, 0x39, 0x94, 0x60, 0xd4, 0x26, 0xc7, 0x60, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x02, 0x08, + 0x00, 0x80, 0x08, 0x00, 0x00, 0x08, 0x80, 0x28, + 0x80, 0x02, 0x00, 0x00, 0x02, 0x48, 0x61, 0x00, + 0x04, 0x06, 0x04, 0x32, 0x46, 0x6a, 0x5c, 0x67, + 0x96, 0xaa, 0xae, 0xc8, 0xd3, 0x5d, 0x62, 0x00, + 0x54, 0x77, 0xf3, 0x0c, 0x2b, 0x3d, 0x63, 0xfc, + 0x62, 0x68, 0x63, 0x83, 0x63, 0xe4, 0x63, 0xf1, + 0x2b, 0x22, 0x64, 0xc5, 0x63, 0xa9, 0x63, 0x2e, + 0x3a, 0x69, 0x64, 0x7e, 0x64, 0x9d, 0x64, 0x77, + 0x64, 0x6c, 0x3a, 0x4f, 0x65, 0x6c, 0x65, 0x0a, + 0x30, 0xe3, 0x65, 0xf8, 0x66, 0x49, 0x66, 0x19, + 0x3b, 0x91, 0x66, 0x08, 0x3b, 0xe4, 0x3a, 0x92, + 0x51, 0x95, 0x51, 0x00, 0x67, 0x9c, 0x66, 0xad, + 0x80, 0xd9, 0x43, 0x17, 0x67, 0x1b, 0x67, 0x21, + 0x67, 0x5e, 0x67, 0x53, 0x67, 0xc3, 0x33, 0x49, + 0x3b, 0xfa, 0x67, 0x85, 0x67, 0x52, 0x68, 0x85, + 0x68, 0x6d, 0x34, 0x8e, 0x68, 0x1f, 0x68, 0x14, + 0x69, 0x9d, 0x3b, 0x42, 0x69, 0xa3, 0x69, 0xea, + 0x69, 0xa8, 0x6a, 0xa3, 0x36, 0xdb, 0x6a, 0x18, + 0x3c, 0x21, 0x6b, 0xa7, 0x38, 0x54, 0x6b, 0x4e, + 0x3c, 0x72, 0x6b, 0x9f, 0x6b, 0xba, 0x6b, 0xbb, + 0x6b, 0x8d, 0x3a, 0x0b, 0x1d, 0xfa, 0x3a, 0x4e, + 0x6c, 0xbc, 0x3c, 0xbf, 0x6c, 0xcd, 0x6c, 0x67, + 0x6c, 0x16, 0x6d, 0x3e, 0x6d, 0x77, 0x6d, 0x41, + 0x6d, 0x69, 0x6d, 0x78, 0x6d, 0x85, 0x6d, 0x1e, + 0x3d, 0x34, 0x6d, 0x2f, 0x6e, 0x6e, 0x6e, 0x33, + 0x3d, 0xcb, 0x6e, 0xc7, 0x6e, 0xd1, 0x3e, 0xf9, + 0x6d, 0x6e, 0x6f, 0x5e, 0x3f, 0x8e, 0x3f, 0xc6, + 0x6f, 0x39, 0x70, 0x1e, 0x70, 0x1b, 0x70, 0x96, + 0x3d, 0x4a, 0x70, 0x7d, 0x70, 0x77, 0x70, 0xad, + 0x70, 0x25, 0x05, 0x45, 0x71, 0x63, 0x42, 0x9c, + 0x71, 0xab, 0x43, 0x28, 0x72, 0x35, 0x72, 0x50, + 0x72, 0x08, 0x46, 0x80, 0x72, 0x95, 0x72, 0x35, + 0x47, 0x02, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x02, 0x02, + 0x80, 0x8a, 0x00, 0x00, 0x20, 0x00, 0x08, 0x0a, + 0x00, 0x80, 0x88, 0x80, 0x20, 0x14, 0x48, 0x7a, + 0x73, 0x8b, 0x73, 0xac, 0x3e, 0xa5, 0x73, 0xb8, + 0x3e, 0xb8, 0x3e, 0x47, 0x74, 0x5c, 0x74, 0x71, + 0x74, 0x85, 0x74, 0xca, 0x74, 0x1b, 0x3f, 0x24, + 0x75, 0x36, 0x4c, 0x3e, 0x75, 0x92, 0x4c, 0x70, + 0x75, 0x9f, 0x21, 0x10, 0x76, 0xa1, 0x4f, 0xb8, + 0x4f, 0x44, 0x50, 0xfc, 0x3f, 0x08, 0x40, 0xf4, + 0x76, 0xf3, 0x50, 0xf2, 0x50, 0x19, 0x51, 0x33, + 0x51, 0x1e, 0x77, 0x1f, 0x77, 0x1f, 0x77, 0x4a, + 0x77, 0x39, 0x40, 0x8b, 0x77, 0x46, 0x40, 0x96, + 0x40, 0x1d, 0x54, 0x4e, 0x78, 0x8c, 0x78, 0xcc, + 0x78, 0xe3, 0x40, 0x26, 0x56, 0x56, 0x79, 0x9a, + 0x56, 0xc5, 0x56, 0x8f, 0x79, 0xeb, 0x79, 0x2f, + 0x41, 0x40, 0x7a, 0x4a, 0x7a, 0x4f, 0x7a, 0x7c, + 0x59, 0xa7, 0x5a, 0xa7, 0x5a, 0xee, 0x7a, 0x02, + 0x42, 0xab, 0x5b, 0xc6, 0x7b, 0xc9, 0x7b, 0x27, + 0x42, 0x80, 0x5c, 0xd2, 0x7c, 0xa0, 0x42, 0xe8, + 0x7c, 0xe3, 0x7c, 0x00, 0x7d, 0x86, 0x5f, 0x63, + 0x7d, 0x01, 0x43, 0xc7, 0x7d, 0x02, 0x7e, 0x45, + 0x7e, 0x34, 0x43, 0x28, 0x62, 0x47, 0x62, 0x59, + 0x43, 0xd9, 0x62, 0x7a, 0x7f, 0x3e, 0x63, 0x95, + 0x7f, 0xfa, 0x7f, 0x05, 0x80, 0xda, 0x64, 0x23, + 0x65, 0x60, 0x80, 0xa8, 0x65, 0x70, 0x80, 0x5f, + 0x33, 0xd5, 0x43, 0xb2, 0x80, 0x03, 0x81, 0x0b, + 0x44, 0x3e, 0x81, 0xb5, 0x5a, 0xa7, 0x67, 0xb5, + 0x67, 0x93, 0x33, 0x9c, 0x33, 0x01, 0x82, 0x04, + 0x82, 0x9e, 0x8f, 0x6b, 0x44, 0x91, 0x82, 0x8b, + 0x82, 0x9d, 0x82, 0xb3, 0x52, 0xb1, 0x82, 0xb3, + 0x82, 0xbd, 0x82, 0xe6, 0x82, 0x3c, 0x6b, 0xe5, + 0x82, 0x1d, 0x83, 0x63, 0x83, 0xad, 0x83, 0x23, + 0x83, 0xbd, 0x83, 0xe7, 0x83, 0x57, 0x84, 0x53, + 0x83, 0xca, 0x83, 0xcc, 0x83, 0xdc, 0x83, 0x36, + 0x6c, 0x6b, 0x6d, 0x02, 0x00, 0x00, 0x20, 0x22, + 0x2a, 0xa0, 0x0a, 0x00, 0x20, 0x80, 0x28, 0x00, + 0xa8, 0x20, 0x20, 0x00, 0x02, 0x80, 0x22, 0x02, + 0x8a, 0x08, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x28, 0xd5, 0x6c, 0x2b, 0x45, 0xf1, + 0x84, 0xf3, 0x84, 0x16, 0x85, 0xca, 0x73, 0x64, + 0x85, 0x2c, 0x6f, 0x5d, 0x45, 0x61, 0x45, 0xb1, + 0x6f, 0xd2, 0x70, 0x6b, 0x45, 0x50, 0x86, 0x5c, + 0x86, 0x67, 0x86, 0x69, 0x86, 0xa9, 0x86, 0x88, + 0x86, 0x0e, 0x87, 0xe2, 0x86, 0x79, 0x87, 0x28, + 0x87, 0x6b, 0x87, 0x86, 0x87, 0xd7, 0x45, 0xe1, + 0x87, 0x01, 0x88, 0xf9, 0x45, 0x60, 0x88, 0x63, + 0x88, 0x67, 0x76, 0xd7, 0x88, 0xde, 0x88, 0x35, + 0x46, 0xfa, 0x88, 0xbb, 0x34, 0xae, 0x78, 0x66, + 0x79, 0xbe, 0x46, 0xc7, 0x46, 0xa0, 0x8a, 0xed, + 0x8a, 0x8a, 0x8b, 0x55, 0x8c, 0xa8, 0x7c, 0xab, + 0x8c, 0xc1, 0x8c, 0x1b, 0x8d, 0x77, 0x8d, 0x2f, + 0x7f, 0x04, 0x08, 0xcb, 0x8d, 0xbc, 0x8d, 0xf0, + 0x8d, 0xde, 0x08, 0xd4, 0x8e, 0x38, 0x8f, 0xd2, + 0x85, 0xed, 0x85, 0x94, 0x90, 0xf1, 0x90, 0x11, + 0x91, 0x2e, 0x87, 0x1b, 0x91, 0x38, 0x92, 0xd7, + 0x92, 0xd8, 0x92, 0x7c, 0x92, 0xf9, 0x93, 0x15, + 0x94, 0xfa, 0x8b, 0x8b, 0x95, 0x95, 0x49, 0xb7, + 0x95, 0x77, 0x8d, 0xe6, 0x49, 0xc3, 0x96, 0xb2, + 0x5d, 0x23, 0x97, 0x45, 0x91, 0x1a, 0x92, 0x6e, + 0x4a, 0x76, 0x4a, 0xe0, 0x97, 0x0a, 0x94, 0xb2, + 0x4a, 0x96, 0x94, 0x0b, 0x98, 0x0b, 0x98, 0x29, + 0x98, 0xb6, 0x95, 0xe2, 0x98, 0x33, 0x4b, 0x29, + 0x99, 0xa7, 0x99, 0xc2, 0x99, 0xfe, 0x99, 0xce, + 0x4b, 0x30, 0x9b, 0x12, 0x9b, 0x40, 0x9c, 0xfd, + 0x9c, 0xce, 0x4c, 0xed, 0x4c, 0x67, 0x9d, 0xce, + 0xa0, 0xf8, 0x4c, 0x05, 0xa1, 0x0e, 0xa2, 0x91, + 0xa2, 0xbb, 0x9e, 0x56, 0x4d, 0xf9, 0x9e, 0xfe, + 0x9e, 0x05, 0x9f, 0x0f, 0x9f, 0x16, 0x9f, 0x3b, + 0x9f, 0x00, 0xa6, 0x02, 0x88, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x28, 0x00, 0x08, 0xa0, + 0x80, 0xa0, 0x80, 0x00, 0x80, 0x80, 0x00, 0x0a, + 0x88, 0x80, 0x00, 0x80, 0x00, 0x20, 0x2a, 0x00, + 0x80, }; static const uint16_t unicode_comp_table[945] = { @@ -2313,7 +2335,7 @@ static const char unicode_gc_name_table[] = "C,Other" "\0" ; -static const uint8_t unicode_gc_table[3897] = { +static const uint8_t unicode_gc_table[3948] = { 0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e, @@ -2399,409 +2421,415 @@ static const uint8_t unicode_gc_table[3897] = { 0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0, 0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, - 0x25, 0xe0, 0x05, 0x26, 0x27, 0xe5, 0x01, 0x00, - 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, 0x66, - 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, 0x60, - 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, 0x02, - 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, 0x00, - 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, 0x01, - 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, 0x47, - 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, 0xe9, - 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, 0x28, - 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, 0xe6, - 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, 0x25, - 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, 0x00, - 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, 0x01, - 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xa6, 0x20, - 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, 0x4f, - 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, 0xe9, - 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, 0x0f, - 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, 0x00, - 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, 0x86, - 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, 0x1c, - 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, 0x96, - 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, 0x66, - 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, 0xe9, - 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, 0x05, - 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, 0x06, - 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, 0x02, - 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, 0x80, - 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, 0xe5, - 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05, - 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, 0x20, - 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05, - 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, 0x31, - 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, 0xf6, - 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, 0x02, - 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, 0xe5, - 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, 0xe5, - 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, 0x4a, - 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, 0xe0, - 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01, - 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00, - 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26, - 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03, - 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9, - 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76, - 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b, - 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a, - 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5, - 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27, - 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9, - 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5, - 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b, - 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06, - 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6, - 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7, - 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9, - 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06, - 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, 0xe5, - 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, 0x06, - 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, 0xef, - 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, 0x26, - 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07, - 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07, - 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00, - 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27, - 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9, - 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, 0xc0, - 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, 0x00, - 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, 0x06, - 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, 0xe2, - 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, 0x1a, - 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, 0xe2, - 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, 0xa2, - 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, 0xe2, - 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, 0xe2, - 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0xe2, - 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, 0x03, - 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, 0x03, - 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, 0xe2, - 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, 0x61, - 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, 0x36, - 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, 0xf6, - 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, 0x14, - 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, 0xf6, - 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, 0x9b, - 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, 0x4c, - 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, 0x13, - 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, 0x07, - 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, 0xe0, - 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, 0x41, - 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, 0x81, - 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x61, - 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, 0x22, - 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, 0x02, - 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, 0x0b, - 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, 0x2f, - 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, 0x2c, - 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, 0x80, - 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, 0xef, - 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, 0x0c, - 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, 0xef, - 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, 0xeb, - 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, 0x2f, - 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, 0x00, - 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, 0x24, - 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, - 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, 0x13, + 0x25, 0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01, + 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, + 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, + 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, + 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, + 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, + 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, + 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, + 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, + 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, + 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, + 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, + 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, + 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6, + 0x00, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, + 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, + 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, + 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, + 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, + 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, + 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, + 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, + 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, + 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, + 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, + 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, + 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, + 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, + 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, + 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, + 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, + 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, + 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, + 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, + 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, + 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, + 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, + 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, + 0xe0, 0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, + 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, + 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, + 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, + 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, + 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, + 0x76, 0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, + 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, + 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, + 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, + 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, + 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, + 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, + 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, + 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, + 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, + 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, + 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, + 0x06, 0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, + 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, + 0x06, 0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, + 0xef, 0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, + 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, + 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, + 0x07, 0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, + 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, + 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, + 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, + 0xc0, 0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, + 0x00, 0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, + 0x06, 0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, + 0xe2, 0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, + 0x1a, 0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, + 0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, + 0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, + 0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, + 0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, + 0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, + 0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, + 0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, + 0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, + 0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, + 0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, + 0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, + 0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, + 0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, + 0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, + 0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, + 0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, + 0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, + 0x07, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, + 0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, + 0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, + 0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, + 0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, + 0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, + 0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, + 0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, + 0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, + 0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, + 0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, + 0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, + 0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, + 0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, + 0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, + 0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, + 0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, + 0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, 0x13, - 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, 0x80, - 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, 0xef, - 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, 0xe1, - 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, 0x41, - 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, 0x02, - 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, 0x80, - 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, 0x80, - 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, 0xe0, - 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, 0x18, - 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, 0x15, - 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, 0x11, - 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, 0x04, - 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, 0xf6, - 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, 0x12, - 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, 0x4e, - 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, 0x0f, - 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, 0x12, - 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0x12, - 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, 0x84, - 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, 0xe5, - 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, 0xe5, - 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, 0x00, - 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, 0xe5, - 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, 0xef, - 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, 0x00, - 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, 0xef, - 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, 0x99, - 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, 0x04, - 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, 0x01, - 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, 0x04, - 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, 0x0c, - 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, 0x02, - 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, 0x3e, - 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, 0x0f, - 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, 0x36, - 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, 0x2e, - 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, 0x02, - 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, 0x80, - 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, 0x10, - 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45, - 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07, - 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0, - 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a, - 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02, - 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25, - 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36, - 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16, - 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06, - 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00, - 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04, - 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21, - 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45, - 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02, - 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05, - 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46, - 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0, - 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26, - 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02, - 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5, - 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2, - 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b, - 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06, - 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0, - 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc, - 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6, - 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04, - 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5, - 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00, - 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, 0x08, - 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, 0xe5, - 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, 0x18, - 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, 0x12, - 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, - 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, 0x76, - 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x56, - 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60, - 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56, - 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, - 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, - 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12, - 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, 0x12, - 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24, - 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5, - 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d, - 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f, - 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5, - 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5, - 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60, - 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b, - 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40, - 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a, - 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06, - 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01, - 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5, - 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5, - 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22, - 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9, - 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60, - 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03, - 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, 0xc1, - 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, 0x07, - 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, 0x80, - 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5, - 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00, - 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00, - 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5, - 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f, - 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0, - 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5, - 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16, - 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb, - 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26, - 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15, - 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6, - 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15, - 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14, - 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e, - 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5, - 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76, - 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0, - 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0, - 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02, - 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, 0x22, - 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x46, 0xe5, - 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, 0xe5, 0x0e, - 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, 0xe5, 0x0a, - 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0, - 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, - 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, - 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, 0xe0, 0x01, - 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, 0x27, 0x26, - 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20, - 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5, - 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02, - 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b, - 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5, - 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76, 0x66, - 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16, 0x05, - 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a, - 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06, 0x07, - 0x26, 0xb6, 0x06, 0xe0, 0x39, 0xc5, 0x00, 0x05, - 0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x02, - 0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, 0x00, - 0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, 0xe5, - 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, - 0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, 0x27, - 0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, 0x05, - 0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, 0x40, - 0x86, 0xe0, 0x80, 0x03, 0xe5, 0x2d, 0x47, 0xe6, - 0x00, 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9, - 0x02, 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16, - 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26, - 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9, - 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66, - 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65, - 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00, - 0x27, 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03, - 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5, - 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06, - 0x05, 0x16, 0xa0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5, - 0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60, - 0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80, - 0x31, 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, - 0x16, 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, - 0x02, 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, - 0x05, 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, - 0x10, 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, - 0x05, 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, - 0xe9, 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, - 0x1f, 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, - 0x16, 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, - 0xe5, 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, - 0x06, 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, - 0x26, 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, - 0xe0, 0x05, 0xe5, 0x41, 0xe0, 0x80, 0x7f, 0xe5, - 0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, - 0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, - 0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, - 0x0e, 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, - 0xe0, 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, - 0xa6, 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, - 0x06, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, - 0x25, 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, - 0x27, 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, - 0xe0, 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, - 0xe0, 0x80, 0x2f, 0x05, 0xe0, 0x07, 0xeb, 0x0d, - 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, 0x05, 0x16, - 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, 0x67, 0x00, - 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, 0xe0, 0x89, - 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, 0xe5, 0x83, - 0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f, 0x3f, 0xe5, - 0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5, 0x81, 0xb1, - 0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02, 0x60, 0x36, - 0xe5, 0x47, 0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16, - 0x20, 0x86, 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, - 0x96, 0x6f, 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, - 0x02, 0x00, 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, - 0x0b, 0xe0, 0x82, 0x28, 0xe1, 0x18, 0xe2, 0x18, - 0xeb, 0x0f, 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, - 0x06, 0x05, 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, - 0xe0, 0x38, 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, - 0x27, 0xe0, 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, - 0xe5, 0x84, 0x4e, 0xe0, 0x22, 0xe5, 0x01, 0xe0, - 0xa2, 0x5f, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, - 0xe5, 0x80, 0x9b, 0xe0, 0x25, 0x45, 0xe0, 0x09, - 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, 0xe0, 0x88, - 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, 0x40, 0xe5, - 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, 0x26, 0x16, - 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, 0x20, 0xe6, - 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef, - 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef, - 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6, - 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35, - 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x80, - 0x12, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f, 0xe0, - 0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12, 0xe2, - 0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a, 0xe1, - 0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20, 0x01, - 0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00, 0x62, - 0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03, 0xe1, - 0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20, 0xe1, - 0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21, 0x00, - 0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1, 0x00, - 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, - 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, - 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, - 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, 0x11, - 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, - 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, + 0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, + 0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, + 0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, + 0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, + 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, + 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, + 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, + 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, + 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, + 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, + 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, + 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, + 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, + 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, + 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, + 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, + 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, + 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, + 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, + 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, + 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, + 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, + 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, + 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, + 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, + 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, + 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, + 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, + 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, + 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, + 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, + 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, + 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, + 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, + 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, + 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, + 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, + 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, + 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, + 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, + 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, + 0x80, 0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, + 0x10, 0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, + 0x45, 0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, + 0x07, 0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, + 0xa0, 0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, + 0x2a, 0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, + 0x02, 0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, + 0x25, 0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, + 0x36, 0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, + 0x16, 0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, + 0x06, 0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, + 0x00, 0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, + 0x04, 0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, + 0x21, 0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, + 0x45, 0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, + 0x02, 0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, + 0x05, 0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, + 0x46, 0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, + 0xe0, 0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, + 0x26, 0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, + 0x02, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, + 0xc5, 0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, + 0xe2, 0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, + 0x1b, 0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, + 0x06, 0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, + 0xe0, 0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, + 0xfc, 0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, + 0xe6, 0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, + 0x04, 0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, + 0xe5, 0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, + 0x00, 0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, + 0x08, 0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, + 0xe5, 0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, + 0x18, 0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, + 0x12, 0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, + 0x30, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, + 0x13, 0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, + 0x76, 0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, + 0x56, 0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, + 0x60, 0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, + 0x56, 0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, + 0x11, 0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, + 0x12, 0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, + 0x12, 0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, + 0x12, 0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, + 0x24, 0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, + 0xa5, 0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, + 0x2d, 0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, + 0x2f, 0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, + 0xe5, 0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, + 0xe5, 0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, + 0x60, 0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, + 0x6b, 0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, + 0x40, 0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, + 0x7a, 0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, + 0x06, 0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, + 0x01, 0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, + 0xe5, 0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, + 0xe5, 0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, + 0x22, 0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, + 0xe9, 0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, + 0x60, 0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, + 0x03, 0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, + 0xc1, 0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, + 0x07, 0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, + 0x80, 0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, + 0xe5, 0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, + 0x00, 0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, + 0x00, 0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, + 0xe5, 0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, + 0x2f, 0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, + 0xe0, 0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, + 0xe5, 0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, + 0x16, 0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, + 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, + 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, + 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, + 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, + 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, + 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, + 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, + 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, + 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, + 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, + 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, + 0x02, 0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, + 0x22, 0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x43, + 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, + 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, + 0xe5, 0x0a, 0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, + 0xcb, 0xe0, 0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, + 0x06, 0x07, 0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, + 0xeb, 0x0c, 0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, + 0xe0, 0x01, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, + 0x27, 0x26, 0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, + 0x1b, 0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, + 0x46, 0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, + 0xe9, 0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, + 0xe5, 0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, + 0x07, 0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, + 0x76, 0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, + 0x16, 0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, + 0xe5, 0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, + 0x06, 0x07, 0x26, 0xb6, 0x06, 0x25, 0x06, 0xe0, + 0x36, 0xc5, 0x00, 0x05, 0x00, 0x65, 0x00, 0xe5, + 0x07, 0x00, 0xe5, 0x02, 0x16, 0xa0, 0xe5, 0x27, + 0x06, 0x47, 0xe6, 0x00, 0x80, 0xe9, 0x02, 0xa0, + 0x26, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20, + 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85, + 0x00, 0x26, 0x05, 0x27, 0x06, 0x67, 0x20, 0x27, + 0x20, 0x47, 0x20, 0x05, 0xa0, 0x07, 0x80, 0x85, + 0x27, 0x20, 0xc6, 0x40, 0x86, 0xe0, 0x80, 0x03, + 0xe5, 0x2d, 0x47, 0xe6, 0x00, 0x27, 0x46, 0x07, + 0x06, 0x65, 0x96, 0xe9, 0x02, 0x36, 0x00, 0x16, + 0x06, 0x45, 0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6, + 0x07, 0x06, 0x67, 0x26, 0x07, 0x26, 0x25, 0x16, + 0x05, 0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e, + 0xe5, 0x27, 0x47, 0x66, 0x20, 0x67, 0x26, 0x07, + 0x26, 0xf6, 0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5, + 0x28, 0x47, 0xe6, 0x00, 0x27, 0x06, 0x07, 0x26, + 0x56, 0x05, 0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6, + 0x05, 0xe0, 0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06, + 0x27, 0xa6, 0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9, + 0x02, 0xe0, 0x2e, 0xe5, 0x13, 0x20, 0x46, 0x27, + 0x66, 0x07, 0x86, 0x60, 0xe9, 0x02, 0x2b, 0x56, + 0x0f, 0xc5, 0xe0, 0x80, 0x31, 0xe5, 0x24, 0x47, + 0xe6, 0x01, 0x07, 0x26, 0x16, 0xe0, 0x5c, 0xe1, + 0x18, 0xe2, 0x18, 0xe9, 0x02, 0xeb, 0x01, 0xe0, + 0x04, 0xe5, 0x00, 0x20, 0x05, 0x20, 0xe5, 0x00, + 0x00, 0x25, 0x00, 0xe5, 0x10, 0xa7, 0x00, 0x27, + 0x20, 0x26, 0x07, 0x06, 0x05, 0x07, 0x05, 0x07, + 0x06, 0x56, 0xe0, 0x01, 0xe9, 0x02, 0xe0, 0x3e, + 0xe5, 0x00, 0x20, 0xe5, 0x1f, 0x47, 0x66, 0x20, + 0x26, 0x67, 0x06, 0x05, 0x16, 0x05, 0x07, 0xe0, + 0x13, 0x05, 0xe6, 0x02, 0xe5, 0x20, 0xa6, 0x07, + 0x05, 0x66, 0xf6, 0x00, 0x06, 0xe0, 0x00, 0x05, + 0xa6, 0x27, 0x46, 0xe5, 0x26, 0xe6, 0x05, 0x07, + 0x26, 0x56, 0x05, 0x96, 0xe0, 0x05, 0xe5, 0x41, + 0xc0, 0xf6, 0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x01, + 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07, + 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb, + 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e, + 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0, + 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6, + 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06, + 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25, + 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27, + 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, + 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xc0, + 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00, 0xe5, 0x1a, + 0x27, 0x86, 0x40, 0x27, 0x06, 0x07, 0x06, 0xf6, + 0x05, 0xe9, 0x02, 0xe0, 0x4e, 0x05, 0xe0, 0x07, + 0xeb, 0x0d, 0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, + 0x05, 0x16, 0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, + 0x67, 0x00, 0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, + 0xe0, 0x89, 0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, + 0xe5, 0x83, 0xa8, 0xfb, 0x08, 0x06, 0xa5, 0xe6, + 0x07, 0xe0, 0x8f, 0x22, 0xe5, 0x81, 0xbf, 0xe0, + 0xa1, 0x31, 0xe5, 0x81, 0xb1, 0xc0, 0xe5, 0x17, + 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47, 0x00, + 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86, 0x16, + 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f, 0x64, + 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00, 0xcb, + 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0, 0x82, + 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f, 0x76, + 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05, 0xe7, + 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38, 0x24, + 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0, 0x06, + 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84, 0x4e, + 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x5f, 0x64, + 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5, 0x80, 0x9b, + 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45, 0x20, 0x05, + 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, + 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, + 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, + 0x26, 0x16, 0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, + 0x20, 0xe6, 0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, + 0x34, 0xef, 0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, + 0x20, 0xef, 0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, + 0x00, 0xe6, 0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, + 0xef, 0x35, 0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, + 0xe0, 0x72, 0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c, + 0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, + 0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, + 0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, + 0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20, + 0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, + 0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, + 0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, + 0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81, + 0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, + 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, - 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f, 0x20, - 0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f, 0x6f, - 0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06, 0x06, - 0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6, 0x07, - 0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, 0x0c, - 0xe0, 0x80, 0x59, 0xc6, 0x00, 0xe6, 0x09, 0x20, - 0xc6, 0x00, 0x26, 0x00, 0x86, 0xe0, 0x80, 0x4d, - 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02, - 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16, - 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02, - 0x80, 0x0d, 0xe0, 0x84, 0x58, 0xc5, 0x00, 0x65, - 0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80, - 0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1, - 0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02, - 0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f, - 0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f, - 0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5, - 0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, - 0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05, - 0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05, - 0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, - 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, - 0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5, - 0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5, - 0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85, - 0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80, - 0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04, - 0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07, - 0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef, - 0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05, - 0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0, - 0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73, - 0x8e, 0xef, 0x82, 0x50, 0x80, 0xef, 0x08, 0x40, - 0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef, - 0x51, 0xc0, 0xef, 0x04, 0x60, 0x0f, 0xe0, 0x07, - 0xef, 0x04, 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef, - 0x02, 0xa0, 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16, - 0x20, 0x2f, 0xe0, 0x46, 0xef, 0x80, 0xcc, 0xe0, - 0x04, 0xef, 0x06, 0x20, 0x8f, 0x40, 0x8f, 0x40, - 0xcf, 0xe0, 0x01, 0xef, 0x15, 0x40, 0xef, 0x03, - 0x80, 0xaf, 0xe0, 0x02, 0xef, 0x02, 0xa0, 0xef, - 0x00, 0xe0, 0x00, 0xcf, 0xe0, 0x01, 0xef, 0x80, - 0x0b, 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, - 0xe0, 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, - 0x18, 0xe5, 0x8f, 0xb1, 0xc0, 0xe5, 0x80, 0x56, - 0x20, 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, - 0xa9, 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, - 0x85, 0x5a, 0xe5, 0x92, 0xc3, 0xe0, 0xca, 0xac, - 0x2e, 0x1b, 0xe0, 0x16, 0xfb, 0x58, 0xe0, 0x78, - 0xe6, 0x80, 0x68, 0xe0, 0xc0, 0xbd, 0x88, 0xfd, - 0xc0, 0xbf, 0x76, 0x20, 0xfd, 0xc0, 0xbf, 0x76, - 0x20, + 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, + 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, + 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, + 0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, + 0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, + 0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, + 0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8, + 0xe2, 0x02, 0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0, + 0x80, 0x4d, 0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, + 0x00, 0x26, 0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0, + 0x19, 0x06, 0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6, + 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0, + 0x80, 0xb8, 0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5, + 0x24, 0x66, 0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81, + 0x48, 0xe5, 0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0, + 0x82, 0x5e, 0xc5, 0x00, 0x65, 0x00, 0x25, 0x00, + 0xe5, 0x07, 0x00, 0xe5, 0x80, 0x3d, 0x20, 0xeb, + 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a, 0xe2, 0x1a, + 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60, 0x36, 0xe0, + 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b, 0x0d, 0x6b, + 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb, 0x07, 0xe0, + 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13, 0x00, 0x25, + 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5, 0x02, 0x00, + 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0, 0x05, 0x60, + 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x45, 0x00, + 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0x05, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x25, 0x00, + 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00, 0x65, 0x00, + 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x00, 0xe5, + 0x09, 0x80, 0x45, 0x00, 0x85, 0x00, 0xe5, 0x09, + 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86, 0xef, 0x24, + 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef, 0x07, 0x20, + 0xef, 0x07, 0x00, 0xef, 0x07, 0x00, 0xef, 0x1d, + 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80, 0x19, 0xe0, + 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef, 0x24, 0x60, + 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06, 0xaf, 0xe0, + 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e, 0xef, 0x82, + 0x50, 0x60, 0xef, 0x09, 0x40, 0xef, 0x05, 0x40, + 0xef, 0x6f, 0x60, 0xef, 0x57, 0xa0, 0xef, 0x04, + 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60, 0xef, + 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef, 0x20, + 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f, 0xe0, 0x46, + 0xef, 0x80, 0xcc, 0xe0, 0x04, 0xef, 0x06, 0x20, + 0xef, 0x05, 0x40, 0xef, 0x01, 0xc0, 0xef, 0x26, + 0x00, 0xcf, 0xe0, 0x00, 0xef, 0x06, 0x60, 0xef, + 0x01, 0xc0, 0xef, 0x01, 0xc0, 0xef, 0x80, 0x0b, + 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02, 0xe0, + 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18, + 0xe5, 0x8f, 0xb2, 0xa0, 0xe5, 0x80, 0x56, 0x20, + 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, + 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, + 0x5a, 0xe5, 0x92, 0xc3, 0x80, 0xe5, 0x8f, 0xd8, + 0xe0, 0xca, 0x9b, 0xc9, 0x1b, 0xe0, 0x16, 0xfb, + 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0, + 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd, + 0xc0, 0xbf, 0x76, 0x20, }; typedef enum { @@ -2868,6 +2896,7 @@ typedef enum { UNICODE_SCRIPT_Kaithi, UNICODE_SCRIPT_Kannada, UNICODE_SCRIPT_Katakana, + UNICODE_SCRIPT_Kawi, UNICODE_SCRIPT_Kayah_Li, UNICODE_SCRIPT_Kharoshthi, UNICODE_SCRIPT_Khmer, @@ -2902,6 +2931,7 @@ typedef enum { UNICODE_SCRIPT_Multani, UNICODE_SCRIPT_Myanmar, UNICODE_SCRIPT_Nabataean, + UNICODE_SCRIPT_Nag_Mundari, UNICODE_SCRIPT_Nandinagari, UNICODE_SCRIPT_New_Tai_Lue, UNICODE_SCRIPT_Newa, @@ -3033,6 +3063,7 @@ static const char unicode_script_name_table[] = "Kaithi,Kthi" "\0" "Kannada,Knda" "\0" "Katakana,Kana" "\0" + "Kawi,Kawi" "\0" "Kayah_Li,Kali" "\0" "Kharoshthi,Khar" "\0" "Khmer,Khmr" "\0" @@ -3067,6 +3098,7 @@ static const char unicode_script_name_table[] = "Multani,Mult" "\0" "Myanmar,Mymr" "\0" "Nabataean,Nbat" "\0" + "Nag_Mundari,Nagm" "\0" "Nandinagari,Nand" "\0" "New_Tai_Lue,Talu" "\0" "Newa,Newa" "\0" @@ -3134,12 +3166,12 @@ static const char unicode_script_name_table[] = "Zanabazar_Square,Zanb" "\0" ; -static const uint8_t unicode_script_table[2690] = { - 0xc0, 0x19, 0x99, 0x46, 0x85, 0x19, 0x99, 0x46, - 0xae, 0x19, 0x80, 0x46, 0x8e, 0x19, 0x80, 0x46, - 0x84, 0x19, 0x96, 0x46, 0x80, 0x19, 0x9e, 0x46, - 0x80, 0x19, 0xe1, 0x60, 0x46, 0xa6, 0x19, 0x84, - 0x46, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, +static const uint8_t unicode_script_table[2720] = { + 0xc0, 0x19, 0x99, 0x47, 0x85, 0x19, 0x99, 0x47, + 0xae, 0x19, 0x80, 0x47, 0x8e, 0x19, 0x80, 0x47, + 0x84, 0x19, 0x96, 0x47, 0x80, 0x19, 0x9e, 0x47, + 0x80, 0x19, 0xe1, 0x60, 0x47, 0xa6, 0x19, 0x84, + 0x47, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0, 0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c, 0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03, 0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19, @@ -3152,11 +3184,11 @@ static const uint8_t unicode_script_table[2690] = { 0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04, 0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04, 0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b, - 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x89, 0x00, - 0xbb, 0x89, 0x01, 0x82, 0x89, 0xaf, 0x04, 0xb1, - 0x93, 0x0d, 0xba, 0x64, 0x01, 0x82, 0x64, 0xad, - 0x7d, 0x01, 0x8e, 0x7d, 0x00, 0x9b, 0x51, 0x01, - 0x80, 0x51, 0x00, 0x8a, 0x89, 0x04, 0x9e, 0x04, + 0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x8b, 0x00, + 0xbb, 0x8b, 0x01, 0x82, 0x8b, 0xaf, 0x04, 0xb1, + 0x95, 0x0d, 0xba, 0x66, 0x01, 0x82, 0x66, 0xad, + 0x7f, 0x01, 0x8e, 0x7f, 0x00, 0x9b, 0x52, 0x01, + 0x80, 0x52, 0x00, 0x8a, 0x8b, 0x04, 0x9e, 0x04, 0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19, 0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20, 0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87, @@ -3176,43 +3208,43 @@ static const uint8_t unicode_script_table[2690] = { 0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d, 0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83, 0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00, - 0x82, 0x72, 0x00, 0x87, 0x72, 0x01, 0x81, 0x72, - 0x01, 0x95, 0x72, 0x00, 0x86, 0x72, 0x00, 0x81, - 0x72, 0x00, 0x84, 0x72, 0x01, 0x88, 0x72, 0x01, - 0x81, 0x72, 0x01, 0x82, 0x72, 0x06, 0x82, 0x72, - 0x03, 0x81, 0x72, 0x00, 0x84, 0x72, 0x01, 0x91, - 0x72, 0x09, 0x81, 0x90, 0x00, 0x85, 0x90, 0x02, - 0x82, 0x90, 0x00, 0x83, 0x90, 0x02, 0x81, 0x90, - 0x00, 0x80, 0x90, 0x00, 0x81, 0x90, 0x02, 0x81, - 0x90, 0x02, 0x82, 0x90, 0x02, 0x8b, 0x90, 0x03, - 0x84, 0x90, 0x02, 0x82, 0x90, 0x00, 0x83, 0x90, - 0x01, 0x80, 0x90, 0x05, 0x80, 0x90, 0x0d, 0x94, - 0x90, 0x04, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00, - 0x96, 0x92, 0x00, 0x8f, 0x92, 0x01, 0x88, 0x92, - 0x00, 0x82, 0x92, 0x00, 0x83, 0x92, 0x06, 0x81, - 0x92, 0x00, 0x82, 0x92, 0x01, 0x80, 0x92, 0x01, - 0x83, 0x92, 0x01, 0x89, 0x92, 0x06, 0x88, 0x92, + 0x82, 0x74, 0x00, 0x87, 0x74, 0x01, 0x81, 0x74, + 0x01, 0x95, 0x74, 0x00, 0x86, 0x74, 0x00, 0x81, + 0x74, 0x00, 0x84, 0x74, 0x01, 0x88, 0x74, 0x01, + 0x81, 0x74, 0x01, 0x82, 0x74, 0x06, 0x82, 0x74, + 0x03, 0x81, 0x74, 0x00, 0x84, 0x74, 0x01, 0x91, + 0x74, 0x09, 0x81, 0x92, 0x00, 0x85, 0x92, 0x02, + 0x82, 0x92, 0x00, 0x83, 0x92, 0x02, 0x81, 0x92, + 0x00, 0x80, 0x92, 0x00, 0x81, 0x92, 0x02, 0x81, + 0x92, 0x02, 0x82, 0x92, 0x02, 0x8b, 0x92, 0x03, + 0x84, 0x92, 0x02, 0x82, 0x92, 0x00, 0x83, 0x92, + 0x01, 0x80, 0x92, 0x05, 0x80, 0x92, 0x0d, 0x94, + 0x92, 0x04, 0x8c, 0x94, 0x00, 0x82, 0x94, 0x00, + 0x96, 0x94, 0x00, 0x8f, 0x94, 0x01, 0x88, 0x94, + 0x00, 0x82, 0x94, 0x00, 0x83, 0x94, 0x06, 0x81, + 0x94, 0x00, 0x82, 0x94, 0x01, 0x80, 0x94, 0x01, + 0x83, 0x94, 0x01, 0x89, 0x94, 0x06, 0x88, 0x94, 0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d, 0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06, 0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d, - 0x01, 0x89, 0x3d, 0x00, 0x81, 0x3d, 0x0c, 0x8c, - 0x50, 0x00, 0x82, 0x50, 0x00, 0xb2, 0x50, 0x00, - 0x82, 0x50, 0x00, 0x85, 0x50, 0x03, 0x8f, 0x50, - 0x01, 0x99, 0x50, 0x00, 0x82, 0x83, 0x00, 0x91, - 0x83, 0x02, 0x97, 0x83, 0x00, 0x88, 0x83, 0x00, - 0x80, 0x83, 0x01, 0x86, 0x83, 0x02, 0x80, 0x83, - 0x03, 0x85, 0x83, 0x00, 0x80, 0x83, 0x00, 0x87, - 0x83, 0x05, 0x89, 0x83, 0x01, 0x82, 0x83, 0x0b, - 0xb9, 0x94, 0x03, 0x80, 0x19, 0x9b, 0x94, 0x24, - 0x81, 0x45, 0x00, 0x80, 0x45, 0x00, 0x84, 0x45, - 0x00, 0x97, 0x45, 0x00, 0x80, 0x45, 0x00, 0x96, - 0x45, 0x01, 0x84, 0x45, 0x00, 0x80, 0x45, 0x00, - 0x85, 0x45, 0x01, 0x89, 0x45, 0x01, 0x83, 0x45, - 0x1f, 0xc7, 0x95, 0x00, 0xa3, 0x95, 0x03, 0xa6, - 0x95, 0x00, 0xa3, 0x95, 0x00, 0x8e, 0x95, 0x00, - 0x86, 0x95, 0x83, 0x19, 0x81, 0x95, 0x24, 0xe0, - 0x3f, 0x5f, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, + 0x01, 0x89, 0x3d, 0x00, 0x82, 0x3d, 0x0b, 0x8c, + 0x51, 0x00, 0x82, 0x51, 0x00, 0xb2, 0x51, 0x00, + 0x82, 0x51, 0x00, 0x85, 0x51, 0x03, 0x8f, 0x51, + 0x01, 0x99, 0x51, 0x00, 0x82, 0x85, 0x00, 0x91, + 0x85, 0x02, 0x97, 0x85, 0x00, 0x88, 0x85, 0x00, + 0x80, 0x85, 0x01, 0x86, 0x85, 0x02, 0x80, 0x85, + 0x03, 0x85, 0x85, 0x00, 0x80, 0x85, 0x00, 0x87, + 0x85, 0x05, 0x89, 0x85, 0x01, 0x82, 0x85, 0x0b, + 0xb9, 0x96, 0x03, 0x80, 0x19, 0x9b, 0x96, 0x24, + 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46, + 0x00, 0x97, 0x46, 0x00, 0x80, 0x46, 0x00, 0x96, + 0x46, 0x01, 0x84, 0x46, 0x00, 0x80, 0x46, 0x00, + 0x86, 0x46, 0x00, 0x89, 0x46, 0x01, 0x83, 0x46, + 0x1f, 0xc7, 0x97, 0x00, 0xa3, 0x97, 0x03, 0xa6, + 0x97, 0x00, 0xa3, 0x97, 0x00, 0x8e, 0x97, 0x00, + 0x86, 0x97, 0x83, 0x19, 0x81, 0x97, 0x24, 0xe0, + 0x3f, 0x60, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, 0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83, 0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00, @@ -3222,32 +3254,32 @@ static const uint8_t unicode_script_table[2690] = { 0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27, 0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99, 0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01, - 0xe2, 0x1f, 0x12, 0x9c, 0x67, 0x02, 0xca, 0x7c, - 0x82, 0x19, 0x8a, 0x7c, 0x06, 0x95, 0x8a, 0x08, - 0x80, 0x8a, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93, - 0x11, 0x0b, 0x8c, 0x8b, 0x00, 0x82, 0x8b, 0x00, - 0x81, 0x8b, 0x0b, 0xdd, 0x41, 0x01, 0x89, 0x41, - 0x05, 0x89, 0x41, 0x05, 0x81, 0x5c, 0x81, 0x19, - 0x80, 0x5c, 0x80, 0x19, 0x93, 0x5c, 0x05, 0xd8, - 0x5c, 0x06, 0xaa, 0x5c, 0x04, 0xc5, 0x12, 0x09, - 0x9e, 0x48, 0x00, 0x8b, 0x48, 0x03, 0x8b, 0x48, - 0x03, 0x80, 0x48, 0x02, 0x8b, 0x48, 0x9d, 0x8c, - 0x01, 0x84, 0x8c, 0x0a, 0xab, 0x62, 0x03, 0x99, - 0x62, 0x05, 0x8a, 0x62, 0x02, 0x81, 0x62, 0x9f, - 0x41, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8d, - 0x00, 0x9c, 0x8d, 0x01, 0x8a, 0x8d, 0x05, 0x89, - 0x8d, 0x05, 0x8d, 0x8d, 0x01, 0x9e, 0x38, 0x30, - 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x87, - 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x47, 0x02, - 0x8e, 0x47, 0x02, 0x82, 0x47, 0xaf, 0x68, 0x88, + 0xe2, 0x1f, 0x12, 0x9c, 0x69, 0x02, 0xca, 0x7e, + 0x82, 0x19, 0x8a, 0x7e, 0x06, 0x95, 0x8c, 0x08, + 0x80, 0x8c, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93, + 0x11, 0x0b, 0x8c, 0x8d, 0x00, 0x82, 0x8d, 0x00, + 0x81, 0x8d, 0x0b, 0xdd, 0x42, 0x01, 0x89, 0x42, + 0x05, 0x89, 0x42, 0x05, 0x81, 0x5d, 0x81, 0x19, + 0x80, 0x5d, 0x80, 0x19, 0x93, 0x5d, 0x05, 0xd8, + 0x5d, 0x06, 0xaa, 0x5d, 0x04, 0xc5, 0x12, 0x09, + 0x9e, 0x49, 0x00, 0x8b, 0x49, 0x03, 0x8b, 0x49, + 0x03, 0x80, 0x49, 0x02, 0x8b, 0x49, 0x9d, 0x8e, + 0x01, 0x84, 0x8e, 0x0a, 0xab, 0x64, 0x03, 0x99, + 0x64, 0x05, 0x8a, 0x64, 0x02, 0x81, 0x64, 0x9f, + 0x42, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8f, + 0x00, 0x9c, 0x8f, 0x01, 0x8a, 0x8f, 0x05, 0x89, + 0x8f, 0x05, 0x8d, 0x8f, 0x01, 0x9e, 0x38, 0x30, + 0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x89, + 0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x48, 0x02, + 0x8e, 0x48, 0x02, 0x82, 0x48, 0xaf, 0x6a, 0x88, 0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87, - 0x87, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38, + 0x89, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38, 0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38, 0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38, - 0x80, 0x19, 0x04, 0xa5, 0x46, 0x84, 0x2c, 0x80, - 0x1d, 0xb0, 0x46, 0x84, 0x2c, 0x83, 0x46, 0x84, - 0x2c, 0x8c, 0x46, 0x80, 0x1d, 0xc5, 0x46, 0x80, - 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x46, 0x95, 0x2c, + 0x80, 0x19, 0x04, 0xa5, 0x47, 0x84, 0x2c, 0x80, + 0x1d, 0xb0, 0x47, 0x84, 0x2c, 0x83, 0x47, 0x84, + 0x2c, 0x8c, 0x47, 0x80, 0x1d, 0xc5, 0x47, 0x80, + 0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x47, 0x95, 0x2c, 0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85, 0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c, @@ -3255,18 +3287,18 @@ static const uint8_t unicode_script_table[2690] = { 0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01, 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19, 0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, - 0x46, 0x01, 0x8a, 0x19, 0x80, 0x46, 0x8e, 0x19, - 0x00, 0x8c, 0x46, 0x02, 0xa0, 0x19, 0x0e, 0xa0, + 0x47, 0x01, 0x8a, 0x19, 0x80, 0x47, 0x8e, 0x19, + 0x00, 0x8c, 0x47, 0x02, 0xa0, 0x19, 0x0e, 0xa0, 0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19, - 0x81, 0x46, 0x85, 0x19, 0x80, 0x46, 0x9a, 0x19, - 0x80, 0x46, 0x90, 0x19, 0xa8, 0x46, 0x82, 0x19, + 0x81, 0x47, 0x85, 0x19, 0x80, 0x47, 0x9a, 0x19, + 0x80, 0x47, 0x90, 0x19, 0xa8, 0x47, 0x82, 0x19, 0x03, 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, 0xe3, 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19, 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, - 0xdf, 0x29, 0x9f, 0x46, 0xe0, 0x13, 0x1a, 0x04, + 0xdf, 0x29, 0x9f, 0x47, 0xe0, 0x13, 0x1a, 0x04, 0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04, - 0x80, 0x28, 0x01, 0xb7, 0x96, 0x06, 0x81, 0x96, - 0x0d, 0x80, 0x96, 0x96, 0x27, 0x08, 0x86, 0x27, + 0x80, 0x28, 0x01, 0xb7, 0x98, 0x06, 0x81, 0x98, + 0x0d, 0x80, 0x98, 0x96, 0x27, 0x08, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d, @@ -3282,27 +3314,27 @@ static const uint8_t unicode_script_table[2690] = { 0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0, 0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0, 0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19, - 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa0, 0x02, - 0xb6, 0xa0, 0x08, 0xaf, 0x4b, 0xe0, 0xcb, 0x9b, + 0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa2, 0x02, + 0xb6, 0xa2, 0x08, 0xaf, 0x4c, 0xe0, 0xcb, 0x9d, 0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19, - 0xe0, 0x05, 0x46, 0x82, 0x19, 0xbf, 0x46, 0x04, - 0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46, - 0x17, 0x8d, 0x46, 0xac, 0x88, 0x02, 0x89, 0x19, - 0x05, 0xb7, 0x78, 0x07, 0xc5, 0x7e, 0x07, 0x8b, - 0x7e, 0x05, 0x9f, 0x20, 0xad, 0x3f, 0x80, 0x19, - 0x80, 0x3f, 0xa3, 0x7b, 0x0a, 0x80, 0x7b, 0x9c, + 0xe0, 0x05, 0x47, 0x82, 0x19, 0xbf, 0x47, 0x04, + 0x81, 0x47, 0x00, 0x80, 0x47, 0x00, 0x84, 0x47, + 0x17, 0x8d, 0x47, 0xac, 0x8a, 0x02, 0x89, 0x19, + 0x05, 0xb7, 0x7a, 0x07, 0xc5, 0x80, 0x07, 0x8b, + 0x80, 0x05, 0x9f, 0x20, 0xad, 0x40, 0x80, 0x19, + 0x80, 0x40, 0xa3, 0x7d, 0x0a, 0x80, 0x7d, 0x9c, 0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89, - 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x5f, 0x00, 0xb6, + 0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x60, 0x00, 0xb6, 0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, - 0x83, 0x16, 0x9f, 0x5f, 0xc2, 0x8e, 0x17, 0x84, - 0x8e, 0x96, 0x56, 0x09, 0x85, 0x27, 0x01, 0x85, + 0x83, 0x16, 0x9f, 0x60, 0xc2, 0x90, 0x17, 0x84, + 0x90, 0x96, 0x57, 0x09, 0x85, 0x27, 0x01, 0x85, 0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00, - 0x86, 0x27, 0x00, 0xaa, 0x46, 0x80, 0x19, 0x88, - 0x46, 0x80, 0x2c, 0x83, 0x46, 0x81, 0x19, 0x03, - 0xcf, 0x17, 0xad, 0x56, 0x01, 0x89, 0x56, 0x05, + 0x86, 0x27, 0x00, 0xaa, 0x47, 0x80, 0x19, 0x88, + 0x47, 0x80, 0x2c, 0x83, 0x47, 0x81, 0x19, 0x03, + 0xcf, 0x17, 0xad, 0x57, 0x01, 0x89, 0x57, 0x05, 0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03, 0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30, - 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x46, 0x0b, + 0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x47, 0x0b, 0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35, 0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81, 0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f, @@ -3311,130 +3343,134 @@ static const uint8_t unicode_script_table[2690] = { 0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81, 0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04, - 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x46, - 0x85, 0x19, 0x99, 0x46, 0x8a, 0x19, 0x89, 0x3e, + 0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x47, + 0x85, 0x19, 0x99, 0x47, 0x8a, 0x19, 0x89, 0x3e, 0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31, 0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00, - 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4a, - 0x00, 0x99, 0x4a, 0x00, 0x92, 0x4a, 0x00, 0x81, - 0x4a, 0x00, 0x8e, 0x4a, 0x01, 0x8d, 0x4a, 0x21, - 0xe0, 0x1a, 0x4a, 0x04, 0x82, 0x19, 0x03, 0xac, + 0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4b, + 0x00, 0x99, 0x4b, 0x00, 0x92, 0x4b, 0x00, 0x81, + 0x4b, 0x00, 0x8e, 0x4b, 0x01, 0x8d, 0x4b, 0x21, + 0xe0, 0x1a, 0x4b, 0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c, 0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80, - 0x38, 0x60, 0x21, 0x9c, 0x4c, 0x02, 0xb0, 0x13, - 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6a, - 0x08, 0x82, 0x6a, 0x9a, 0x2a, 0x04, 0xaa, 0x6c, - 0x04, 0x9d, 0x9a, 0x00, 0x80, 0x9a, 0xa3, 0x6d, - 0x03, 0x8d, 0x6d, 0x29, 0xcf, 0x1f, 0xaf, 0x80, - 0x9d, 0x74, 0x01, 0x89, 0x74, 0x05, 0xa3, 0x73, - 0x03, 0xa3, 0x73, 0x03, 0xa7, 0x25, 0x07, 0xb3, - 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9c, 0x00, 0x8e, - 0x9c, 0x00, 0x86, 0x9c, 0x00, 0x81, 0x9c, 0x00, - 0x8a, 0x9c, 0x00, 0x8e, 0x9c, 0x00, 0x86, 0x9c, - 0x00, 0x81, 0x9c, 0x42, 0xe0, 0xd6, 0x49, 0x08, - 0x95, 0x49, 0x09, 0x87, 0x49, 0x17, 0x85, 0x46, - 0x00, 0xa9, 0x46, 0x00, 0x88, 0x46, 0x44, 0x85, + 0x38, 0x60, 0x21, 0x9c, 0x4d, 0x02, 0xb0, 0x13, + 0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6c, + 0x08, 0x82, 0x6c, 0x9a, 0x2a, 0x04, 0xaa, 0x6e, + 0x04, 0x9d, 0x9c, 0x00, 0x80, 0x9c, 0xa3, 0x6f, + 0x03, 0x8d, 0x6f, 0x29, 0xcf, 0x1f, 0xaf, 0x82, + 0x9d, 0x76, 0x01, 0x89, 0x76, 0x05, 0xa3, 0x75, + 0x03, 0xa3, 0x75, 0x03, 0xa7, 0x25, 0x07, 0xb3, + 0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9e, 0x00, 0x8e, + 0x9e, 0x00, 0x86, 0x9e, 0x00, 0x81, 0x9e, 0x00, + 0x8a, 0x9e, 0x00, 0x8e, 0x9e, 0x00, 0x86, 0x9e, + 0x00, 0x81, 0x9e, 0x42, 0xe0, 0xd6, 0x4a, 0x08, + 0x95, 0x4a, 0x09, 0x87, 0x4a, 0x17, 0x85, 0x47, + 0x00, 0xa9, 0x47, 0x00, 0x88, 0x47, 0x44, 0x85, 0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, 0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, - 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x76, 0x9e, - 0x60, 0x07, 0x88, 0x60, 0x2f, 0x92, 0x34, 0x00, - 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x79, 0x02, - 0x80, 0x79, 0x99, 0x4d, 0x04, 0x80, 0x4d, 0x3f, - 0x9f, 0x59, 0x97, 0x58, 0x03, 0x93, 0x58, 0x01, - 0xad, 0x58, 0x83, 0x40, 0x00, 0x81, 0x40, 0x04, - 0x87, 0x40, 0x00, 0x82, 0x40, 0x00, 0x9c, 0x40, - 0x01, 0x82, 0x40, 0x03, 0x89, 0x40, 0x06, 0x88, - 0x40, 0x06, 0x9f, 0x6f, 0x9f, 0x6b, 0x1f, 0xa6, - 0x52, 0x03, 0x8b, 0x52, 0x08, 0xb5, 0x06, 0x02, + 0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x78, 0x9e, + 0x61, 0x07, 0x88, 0x61, 0x2f, 0x92, 0x34, 0x00, + 0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x7b, 0x02, + 0x80, 0x7b, 0x99, 0x4e, 0x04, 0x80, 0x4e, 0x3f, + 0x9f, 0x5a, 0x97, 0x59, 0x03, 0x93, 0x59, 0x01, + 0xad, 0x59, 0x83, 0x41, 0x00, 0x81, 0x41, 0x04, + 0x87, 0x41, 0x00, 0x82, 0x41, 0x00, 0x9c, 0x41, + 0x01, 0x82, 0x41, 0x03, 0x89, 0x41, 0x06, 0x88, + 0x41, 0x06, 0x9f, 0x71, 0x9f, 0x6d, 0x1f, 0xa6, + 0x53, 0x03, 0x8b, 0x53, 0x08, 0xb5, 0x06, 0x02, 0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92, - 0x39, 0x04, 0x87, 0x39, 0x91, 0x7a, 0x06, 0x83, - 0x7a, 0x0b, 0x86, 0x7a, 0x4f, 0xc8, 0x70, 0x36, - 0xb2, 0x69, 0x0c, 0xb2, 0x69, 0x06, 0x85, 0x69, + 0x39, 0x04, 0x87, 0x39, 0x91, 0x7c, 0x06, 0x83, + 0x7c, 0x0b, 0x86, 0x7c, 0x4f, 0xc8, 0x72, 0x36, + 0xb2, 0x6b, 0x0c, 0xb2, 0x6b, 0x06, 0x85, 0x6b, 0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e, - 0x04, 0x00, 0xa9, 0x9f, 0x00, 0x82, 0x9f, 0x01, - 0x81, 0x9f, 0x4d, 0xa7, 0x6e, 0x07, 0xa9, 0x84, - 0x15, 0x99, 0x71, 0x25, 0x9b, 0x18, 0x13, 0x96, - 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08, - 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, 0x3c, 0x01, - 0x98, 0x85, 0x06, 0x89, 0x85, 0x05, 0xb4, 0x15, - 0x00, 0x91, 0x15, 0x07, 0xa6, 0x4f, 0x08, 0xdf, - 0x7f, 0x00, 0x93, 0x83, 0x0a, 0x91, 0x42, 0x00, - 0xab, 0x42, 0x40, 0x86, 0x5e, 0x00, 0x80, 0x5e, - 0x00, 0x83, 0x5e, 0x00, 0x8e, 0x5e, 0x00, 0x8a, - 0x5e, 0x05, 0xba, 0x44, 0x04, 0x89, 0x44, 0x05, - 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, 0x81, 0x2b, - 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, 0x00, 0x81, - 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, 0x38, 0x88, - 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, 0x2b, 0x01, - 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, 0x86, 0x2b, - 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, 0x60, 0x2a, - 0xdb, 0x63, 0x00, 0x84, 0x63, 0x1d, 0xc7, 0x97, - 0x07, 0x89, 0x97, 0x60, 0x45, 0xb5, 0x81, 0x01, - 0xa5, 0x81, 0x21, 0xc4, 0x5b, 0x0a, 0x89, 0x5b, - 0x05, 0x8c, 0x5c, 0x12, 0xb9, 0x8f, 0x05, 0x89, - 0x8f, 0x35, 0x9a, 0x02, 0x01, 0x8e, 0x02, 0x03, - 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, 0x60, 0x03, - 0xd2, 0x9e, 0x0b, 0x80, 0x9e, 0x86, 0x21, 0x01, - 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, 0x81, 0x21, - 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, 0x01, 0x8b, - 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, 0x61, 0x01, - 0xad, 0x61, 0x01, 0x8a, 0x61, 0x1a, 0xc7, 0xa1, - 0x07, 0xd2, 0x86, 0x0c, 0x8f, 0x12, 0xb8, 0x77, - 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac, 0x0c, 0x00, - 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02, 0x9f, 0x53, - 0x01, 0x95, 0x53, 0x00, 0x8d, 0x53, 0x48, 0x86, - 0x54, 0x00, 0x81, 0x54, 0x00, 0xab, 0x54, 0x02, - 0x80, 0x54, 0x00, 0x81, 0x54, 0x00, 0x88, 0x54, - 0x07, 0x89, 0x54, 0x05, 0x85, 0x2e, 0x00, 0x81, - 0x2e, 0x00, 0xa4, 0x2e, 0x00, 0x81, 0x2e, 0x00, - 0x85, 0x2e, 0x06, 0x89, 0x2e, 0x60, 0xd5, 0x98, - 0x4e, 0x60, 0x56, 0x80, 0x4b, 0x0e, 0xb1, 0x90, - 0x0c, 0x80, 0x90, 0xe3, 0x39, 0x1b, 0x60, 0x05, - 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b, 0x0a, 0xe0, - 0x63, 0x1b, 0x69, 0xeb, 0xe0, 0x02, 0x1e, 0x0c, - 0xe3, 0xce, 0x24, 0x00, 0x88, 0x24, 0x6f, 0x66, - 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8, - 0x08, 0x06, 0x9e, 0x5d, 0x00, 0x89, 0x5d, 0x03, - 0x81, 0x5d, 0xce, 0x98, 0x00, 0x89, 0x98, 0x05, - 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x75, - 0x09, 0x89, 0x75, 0x00, 0x86, 0x75, 0x00, 0x94, - 0x75, 0x04, 0x92, 0x75, 0x62, 0x4f, 0xda, 0x55, - 0x60, 0x04, 0xca, 0x5a, 0x03, 0xb8, 0x5a, 0x06, - 0x90, 0x5a, 0x3f, 0x80, 0x91, 0x80, 0x65, 0x81, - 0x30, 0x80, 0x43, 0x0a, 0x81, 0x30, 0x0d, 0xf0, - 0x07, 0x97, 0x91, 0x07, 0xe2, 0x9f, 0x91, 0xe1, - 0x75, 0x43, 0x29, 0x88, 0x91, 0x70, 0x12, 0x86, - 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, 0x81, 0x3e, - 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, 0x82, 0x3e, - 0x2c, 0x82, 0x36, 0x10, 0x83, 0x3e, 0x07, 0xe1, - 0x2b, 0x65, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04, + 0x04, 0x00, 0xa9, 0xa1, 0x00, 0x82, 0xa1, 0x01, + 0x81, 0xa1, 0x4a, 0x82, 0x04, 0xa7, 0x70, 0x07, + 0xa9, 0x86, 0x15, 0x99, 0x73, 0x25, 0x9b, 0x18, + 0x13, 0x96, 0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, + 0x0e, 0x08, 0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, + 0x3c, 0x01, 0x98, 0x87, 0x06, 0x89, 0x87, 0x05, + 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07, 0xa6, 0x50, + 0x08, 0xdf, 0x81, 0x00, 0x93, 0x85, 0x0a, 0x91, + 0x43, 0x00, 0xae, 0x43, 0x3d, 0x86, 0x5f, 0x00, + 0x80, 0x5f, 0x00, 0x83, 0x5f, 0x00, 0x8e, 0x5f, + 0x00, 0x8a, 0x5f, 0x05, 0xba, 0x45, 0x04, 0x89, + 0x45, 0x05, 0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, + 0x81, 0x2b, 0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, + 0x00, 0x81, 0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, + 0x38, 0x88, 0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, + 0x2b, 0x01, 0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, + 0x86, 0x2b, 0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, + 0x60, 0x2a, 0xdb, 0x65, 0x00, 0x84, 0x65, 0x1d, + 0xc7, 0x99, 0x07, 0x89, 0x99, 0x60, 0x45, 0xb5, + 0x83, 0x01, 0xa5, 0x83, 0x21, 0xc4, 0x5c, 0x0a, + 0x89, 0x5c, 0x05, 0x8c, 0x5d, 0x12, 0xb9, 0x91, + 0x05, 0x89, 0x91, 0x35, 0x9a, 0x02, 0x01, 0x8e, + 0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, + 0x60, 0x03, 0xd2, 0xa0, 0x0b, 0x80, 0xa0, 0x86, + 0x21, 0x01, 0x80, 0x21, 0x01, 0x87, 0x21, 0x00, + 0x81, 0x21, 0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, + 0x01, 0x8b, 0x21, 0x08, 0x89, 0x21, 0x45, 0x87, + 0x63, 0x01, 0xad, 0x63, 0x01, 0x8a, 0x63, 0x1a, + 0xc7, 0xa3, 0x07, 0xd2, 0x88, 0x0c, 0x8f, 0x12, + 0xb8, 0x79, 0x06, 0x89, 0x20, 0x60, 0x95, 0x88, + 0x0c, 0x00, 0xac, 0x0c, 0x00, 0x8d, 0x0c, 0x09, + 0x9c, 0x0c, 0x02, 0x9f, 0x54, 0x01, 0x95, 0x54, + 0x00, 0x8d, 0x54, 0x48, 0x86, 0x55, 0x00, 0x81, + 0x55, 0x00, 0xab, 0x55, 0x02, 0x80, 0x55, 0x00, + 0x81, 0x55, 0x00, 0x88, 0x55, 0x07, 0x89, 0x55, + 0x05, 0x85, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0xa4, + 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x85, 0x2e, 0x06, + 0x89, 0x2e, 0x60, 0xd5, 0x98, 0x4f, 0x06, 0x90, + 0x3f, 0x00, 0xa8, 0x3f, 0x02, 0x9b, 0x3f, 0x55, + 0x80, 0x4c, 0x0e, 0xb1, 0x92, 0x0c, 0x80, 0x92, + 0xe3, 0x39, 0x1b, 0x60, 0x05, 0xe0, 0x0e, 0x1b, + 0x00, 0x84, 0x1b, 0x0a, 0xe0, 0x63, 0x1b, 0x69, + 0xeb, 0xe0, 0x02, 0x1e, 0x0c, 0xe3, 0xf5, 0x24, + 0x6f, 0x49, 0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, + 0xe1, 0xd8, 0x08, 0x06, 0x9e, 0x5e, 0x00, 0x89, + 0x5e, 0x03, 0x81, 0x5e, 0xce, 0x9a, 0x00, 0x89, + 0x9a, 0x05, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, + 0xc5, 0x77, 0x09, 0x89, 0x77, 0x00, 0x86, 0x77, + 0x00, 0x94, 0x77, 0x04, 0x92, 0x77, 0x62, 0x4f, + 0xda, 0x56, 0x60, 0x04, 0xca, 0x5b, 0x03, 0xb8, + 0x5b, 0x06, 0x90, 0x5b, 0x3f, 0x80, 0x93, 0x80, + 0x67, 0x81, 0x30, 0x80, 0x44, 0x0a, 0x81, 0x30, + 0x0d, 0xf0, 0x07, 0x97, 0x93, 0x07, 0xe2, 0x9f, + 0x93, 0xe1, 0x75, 0x44, 0x29, 0x88, 0x93, 0x70, + 0x12, 0x86, 0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, + 0x81, 0x3e, 0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, + 0x82, 0x3e, 0x0e, 0x80, 0x36, 0x1c, 0x82, 0x36, + 0x01, 0x80, 0x3e, 0x0d, 0x83, 0x3e, 0x07, 0xe1, + 0x2b, 0x67, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04, 0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23, 0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb, 0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13, 0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87, 0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83, - 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x39, - 0x93, 0x19, 0x0b, 0xd6, 0x19, 0x08, 0x98, 0x19, - 0x60, 0x26, 0xd4, 0x19, 0x00, 0xc6, 0x19, 0x00, - 0x81, 0x19, 0x01, 0x80, 0x19, 0x01, 0x81, 0x19, - 0x01, 0x83, 0x19, 0x00, 0x8b, 0x19, 0x00, 0x80, - 0x19, 0x00, 0x86, 0x19, 0x00, 0xc0, 0x19, 0x00, - 0x83, 0x19, 0x01, 0x87, 0x19, 0x00, 0x86, 0x19, - 0x00, 0x9b, 0x19, 0x00, 0x83, 0x19, 0x00, 0x84, - 0x19, 0x00, 0x80, 0x19, 0x02, 0x86, 0x19, 0x00, - 0xe0, 0xf3, 0x19, 0x01, 0xe0, 0xc3, 0x19, 0x01, - 0xb1, 0x19, 0xe2, 0x2b, 0x82, 0x0e, 0x84, 0x82, - 0x00, 0x8e, 0x82, 0x63, 0xef, 0x9e, 0x46, 0x60, - 0x80, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, - 0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x60, - 0x74, 0xac, 0x66, 0x02, 0x8d, 0x66, 0x01, 0x89, - 0x66, 0x03, 0x81, 0x66, 0x60, 0xdf, 0x9e, 0x99, - 0x10, 0xb9, 0x9d, 0x04, 0x80, 0x9d, 0x64, 0x7f, + 0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x19, + 0x93, 0x19, 0x0b, 0x93, 0x19, 0x0b, 0xd6, 0x19, + 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19, 0x00, + 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80, 0x19, + 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00, 0x8b, + 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19, 0x00, + 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87, 0x19, + 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00, 0x83, + 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19, 0x02, + 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01, 0xe0, + 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b, 0x84, + 0x0e, 0x84, 0x84, 0x00, 0x8e, 0x84, 0x63, 0xef, + 0x9e, 0x47, 0x05, 0x85, 0x47, 0x60, 0x74, 0x86, + 0x29, 0x00, 0x90, 0x29, 0x01, 0x86, 0x29, 0x00, + 0x81, 0x29, 0x00, 0x84, 0x29, 0x04, 0xbd, 0x1d, + 0x20, 0x80, 0x1d, 0x60, 0x0f, 0xac, 0x68, 0x02, + 0x8d, 0x68, 0x01, 0x89, 0x68, 0x03, 0x81, 0x68, + 0x60, 0xdf, 0x9e, 0x9b, 0x10, 0xb9, 0x9f, 0x04, + 0x80, 0x9f, 0x61, 0x6f, 0xa9, 0x62, 0x62, 0x85, 0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27, - 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x57, 0x01, - 0x8f, 0x57, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, + 0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x58, 0x01, + 0x8f, 0x58, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, 0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, @@ -3455,86 +3491,85 @@ static const uint8_t unicode_script_table[2690] = { 0x19, 0x37, 0x99, 0x19, 0x80, 0x36, 0x81, 0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77, - 0x19, 0x04, 0x8f, 0x19, 0x02, 0x8c, 0x19, 0x02, - 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06, 0x8b, + 0x19, 0x03, 0x90, 0x19, 0x02, 0x8c, 0x19, 0x02, + 0xe0, 0x16, 0x19, 0x03, 0xde, 0x19, 0x05, 0x8b, 0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03, 0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, 0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, - 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x84, 0x19, - 0x02, 0x84, 0x19, 0x02, 0x86, 0x19, 0x08, 0x9c, - 0x19, 0x02, 0x8a, 0x19, 0x04, 0x85, 0x19, 0x09, - 0x89, 0x19, 0x05, 0x87, 0x19, 0x07, 0x86, 0x19, - 0x08, 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24, - 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, 0x30, - 0x1f, 0xef, 0xd8, 0x30, 0x06, 0xe0, 0x7d, 0x30, - 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, 0xf0, 0x0c, - 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, 0x30, 0x65, - 0x81, 0xf0, 0x02, 0xea, 0x30, 0x7a, 0xdc, 0x55, - 0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, - 0x8f, 0x38, + 0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x8c, 0x19, + 0x02, 0x88, 0x19, 0x06, 0xad, 0x19, 0x00, 0x86, + 0x19, 0x07, 0x8d, 0x19, 0x03, 0x88, 0x19, 0x06, + 0x88, 0x19, 0x06, 0xe0, 0x32, 0x19, 0x00, 0xb6, + 0x19, 0x24, 0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, + 0x7f, 0x30, 0x1f, 0xef, 0xd9, 0x30, 0x05, 0xe0, + 0x7d, 0x30, 0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, + 0xf0, 0x0c, 0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, + 0x30, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x30, 0x04, + 0xef, 0xff, 0x30, 0x7a, 0xcb, 0xf0, 0x80, 0x19, + 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f, 0x38, }; static const uint8_t unicode_script_ext_table[828] = { 0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00, - 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x46, - 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6c, 0x00, - 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x46, 0x00, + 0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x47, + 0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6e, 0x00, + 0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x47, 0x00, 0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06, - 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, 0x0d, 0x00, - 0x00, 0x06, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, - 0x00, 0x03, 0x04, 0x89, 0x93, 0x01, 0x00, 0x00, - 0x07, 0x01, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, - 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x51, 0x52, - 0x71, 0x7a, 0x32, 0x84, 0x89, 0x09, 0x00, 0x0a, - 0x02, 0x04, 0x89, 0x09, 0x00, 0x09, 0x03, 0x04, - 0x93, 0x9f, 0x05, 0x00, 0x00, 0x02, 0x04, 0x89, + 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, 0x0d, 0x00, + 0x00, 0x06, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, + 0x00, 0x03, 0x04, 0x8b, 0x95, 0x01, 0x00, 0x00, + 0x07, 0x01, 0x04, 0x66, 0x32, 0x8b, 0x95, 0xa1, + 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x52, 0x53, + 0x73, 0x7c, 0x32, 0x86, 0x8b, 0x09, 0x00, 0x0a, + 0x02, 0x04, 0x8b, 0x09, 0x00, 0x09, 0x03, 0x04, + 0x95, 0xa1, 0x05, 0x00, 0x00, 0x02, 0x04, 0x8b, 0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, - 0x3d, 0x46, 0x50, 0x72, 0x7f, 0x90, 0x92, 0x97, + 0x3d, 0x47, 0x51, 0x74, 0x81, 0x92, 0x94, 0x99, 0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d, - 0x46, 0x50, 0x72, 0x90, 0x92, 0x97, 0x10, 0x00, - 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, - 0x2d, 0x2f, 0x3d, 0x4f, 0x50, 0x61, 0x72, 0x44, - 0x83, 0x88, 0x8f, 0x90, 0x92, 0x97, 0x00, 0x15, - 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, 0x2d, 0x2f, - 0x3d, 0x48, 0x4f, 0x50, 0x61, 0x72, 0x44, 0x83, - 0x88, 0x8f, 0x90, 0x92, 0x97, 0x09, 0x04, 0x20, - 0x22, 0x3c, 0x4f, 0x75, 0x00, 0x09, 0x03, 0x0b, - 0x15, 0x88, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5e, - 0x75, 0x00, 0x09, 0x02, 0x2d, 0x42, 0x80, 0x75, - 0x00, 0x0d, 0x02, 0x2b, 0x90, 0x80, 0x71, 0x00, - 0x09, 0x02, 0x3d, 0x61, 0x82, 0xcf, 0x00, 0x09, - 0x03, 0x15, 0x5f, 0x8c, 0x80, 0x30, 0x00, 0x00, - 0x02, 0x28, 0x46, 0x85, 0xb8, 0x00, 0x01, 0x04, - 0x11, 0x33, 0x8b, 0x8a, 0x80, 0x4a, 0x00, 0x01, - 0x02, 0x5c, 0x78, 0x00, 0x00, 0x00, 0x02, 0x5c, - 0x78, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20, + 0x47, 0x51, 0x74, 0x92, 0x94, 0x99, 0x10, 0x00, + 0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, + 0x2d, 0x2f, 0x3d, 0x50, 0x51, 0x63, 0x74, 0x45, + 0x85, 0x8a, 0x91, 0x92, 0x94, 0x99, 0x00, 0x15, + 0x0b, 0x20, 0x22, 0x2e, 0x55, 0x2b, 0x2d, 0x2f, + 0x3d, 0x49, 0x50, 0x51, 0x63, 0x74, 0x45, 0x85, + 0x8a, 0x91, 0x92, 0x94, 0x99, 0x09, 0x04, 0x20, + 0x22, 0x3c, 0x50, 0x75, 0x00, 0x09, 0x03, 0x0b, + 0x15, 0x8a, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5f, + 0x75, 0x00, 0x09, 0x02, 0x2d, 0x43, 0x80, 0x75, + 0x00, 0x0d, 0x02, 0x2b, 0x92, 0x80, 0x71, 0x00, + 0x09, 0x02, 0x3d, 0x63, 0x82, 0xcf, 0x00, 0x09, + 0x03, 0x15, 0x60, 0x8e, 0x80, 0x30, 0x00, 0x00, + 0x02, 0x28, 0x47, 0x85, 0xb8, 0x00, 0x01, 0x04, + 0x11, 0x33, 0x8d, 0x8c, 0x80, 0x4a, 0x00, 0x01, + 0x02, 0x5d, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x5d, + 0x7a, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20, 0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b, 0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00, 0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x7f, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, - 0x20, 0x7f, 0x00, 0x06, 0x20, 0x3d, 0x50, 0x72, - 0x90, 0x92, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, - 0x7f, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x7f, + 0x20, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02, + 0x20, 0x81, 0x00, 0x06, 0x20, 0x3d, 0x51, 0x74, + 0x92, 0x94, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20, + 0x81, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x81, 0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00, - 0x02, 0x20, 0x61, 0x00, 0x02, 0x0b, 0x20, 0x01, + 0x02, 0x20, 0x63, 0x00, 0x02, 0x0b, 0x20, 0x01, 0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01, - 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x61, - 0x72, 0x92, 0x97, 0x00, 0x02, 0x20, 0x2b, 0x00, + 0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x63, + 0x74, 0x94, 0x99, 0x00, 0x02, 0x20, 0x2b, 0x00, 0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00, - 0x01, 0x61, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c, - 0x35, 0x00, 0x00, 0x02, 0x1d, 0x89, 0x00, 0x00, - 0x00, 0x01, 0x89, 0x81, 0xb3, 0x00, 0x00, 0x02, - 0x46, 0x5c, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20, - 0x2b, 0x46, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, + 0x01, 0x63, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c, + 0x35, 0x00, 0x00, 0x02, 0x1d, 0x8b, 0x00, 0x00, + 0x00, 0x01, 0x8b, 0x81, 0xb3, 0x00, 0x00, 0x02, + 0x47, 0x5d, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20, + 0x2b, 0x47, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, 0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31, - 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x05, 0x0d, 0x31, + 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30, 0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31, + 0x3e, 0xa2, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30, - 0x36, 0x3e, 0xa0, 0x03, 0x05, 0x0d, 0x31, 0x30, + 0x36, 0x3e, 0xa2, 0x03, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30, 0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00, @@ -3542,7 +3577,7 @@ static const uint8_t unicode_script_ext_table[828] = { 0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30, 0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00, 0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06, - 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x02, + 0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa2, 0x00, 0x02, 0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30, 0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27, 0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e, @@ -3550,32 +3585,32 @@ static const uint8_t unicode_script_ext_table[828] = { 0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00, 0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29, - 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x46, 0x80, + 0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x47, 0x80, 0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f, - 0x42, 0x3d, 0x3c, 0x4f, 0x50, 0x5b, 0x61, 0x44, - 0x8f, 0x97, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f, - 0x42, 0x3d, 0x3c, 0x4f, 0x5b, 0x61, 0x44, 0x8f, - 0x97, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x42, - 0x3c, 0x4f, 0x5b, 0x44, 0x8f, 0x97, 0x80, 0x36, + 0x43, 0x3d, 0x3c, 0x50, 0x51, 0x5c, 0x63, 0x45, + 0x91, 0x99, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f, + 0x43, 0x3d, 0x3c, 0x50, 0x5c, 0x63, 0x45, 0x91, + 0x99, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x43, + 0x3c, 0x50, 0x5c, 0x45, 0x91, 0x99, 0x80, 0x36, 0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x90, 0x39, 0x00, 0x00, 0x03, 0x3f, - 0x46, 0x5f, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, + 0x02, 0x20, 0x92, 0x39, 0x00, 0x00, 0x03, 0x40, + 0x47, 0x60, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04, - 0x64, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x93, - 0x09, 0x00, 0x00, 0x02, 0x04, 0x93, 0x46, 0x00, + 0x66, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x95, + 0x09, 0x00, 0x00, 0x02, 0x04, 0x95, 0x46, 0x00, 0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80, 0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36, - 0x3e, 0xa0, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e, + 0x3e, 0xa2, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e, 0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf, - 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4a, 0x00, 0x02, - 0x1c, 0x4a, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x49, - 0x4a, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4a, 0x81, + 0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4b, 0x00, 0x02, + 0x1c, 0x4b, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x4a, + 0x4b, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4b, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75, - 0x00, 0x00, 0x02, 0x52, 0x71, 0x87, 0x8d, 0x00, - 0x00, 0x02, 0x2b, 0x90, 0x00, 0x00, 0x00, 0x02, - 0x2b, 0x90, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x90, - 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x90, 0x00, - 0x00, 0x00, 0x02, 0x2b, 0x90, 0xc0, 0x5c, 0x4b, + 0x00, 0x00, 0x02, 0x53, 0x73, 0x87, 0x8d, 0x00, + 0x00, 0x02, 0x2b, 0x92, 0x00, 0x00, 0x00, 0x02, + 0x2b, 0x92, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x92, + 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x92, 0x00, + 0x00, 0x00, 0x02, 0x2b, 0x92, 0xc0, 0x5c, 0x4b, 0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11, 0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30, 0xce, 0xcd, 0x2d, 0x00, @@ -3616,7 +3651,7 @@ static const uint8_t unicode_prop_Other_Math_table[200] = { 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, }; -static const uint8_t unicode_prop_Other_Alphabetic_table[417] = { +static const uint8_t unicode_prop_Other_Alphabetic_table[428] = { 0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80, @@ -3628,59 +3663,61 @@ static const uint8_t unicode_prop_Other_Alphabetic_table[417] = { 0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba, - 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x83, 0xb9, + 0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82, - 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b, - 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, 0x80, 0x89, - 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, 0x87, 0x91, - 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, 0xe2, 0x01, - 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, 0x90, 0x8a, - 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, 0x0b, 0x96, - 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x00, - 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, 0x81, 0x9d, - 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, 0xbb, 0x81, - 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, 0x40, 0xdd, - 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, 0x81, 0x8a, - 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d, - 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf, - 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, 0x9f, 0x60, - 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, 0x61, 0x07, - 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, 0x8f, 0x00, - 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, 0xac, 0x83, - 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, 0x8b, 0x07, - 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x80, - 0xab, 0x24, 0x80, 0x40, 0xec, 0x87, 0x60, 0x4f, - 0x32, 0x80, 0x48, 0x56, 0x84, 0x46, 0x85, 0x10, - 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, 0x82, 0x81, - 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, 0x81, 0x8c, - 0x80, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, 0xa3, - 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, 0x8d, - 0x81, 0xdb, 0x88, 0x08, 0x28, 0x40, 0x9f, 0x89, - 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, - 0x89, 0x81, 0x40, 0xd0, 0x8c, 0x02, 0xe9, 0x91, - 0x40, 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, - 0x00, 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, - 0x40, 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, - 0x8d, 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, - 0x83, 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38, - 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, - 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83, - 0x41, 0x5b, 0x83, 0x60, 0x50, 0x57, 0x00, 0xb6, - 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60, - 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x49, - 0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85, 0x99, 0x85, - 0x99, + 0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x8e, + 0x80, 0x8b, 0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, + 0x80, 0x89, 0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, + 0x87, 0x91, 0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, + 0xe2, 0x01, 0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, + 0x92, 0x88, 0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, + 0x0b, 0x96, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, + 0x8b, 0x00, 0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, + 0x81, 0x9d, 0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, + 0xbb, 0x81, 0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, + 0x40, 0xdd, 0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, + 0x81, 0x8a, 0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, + 0x82, 0x9d, 0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, + 0x41, 0xaf, 0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, + 0x9f, 0x60, 0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, + 0x61, 0x07, 0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, + 0x8f, 0x00, 0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, + 0xac, 0x83, 0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, + 0x8b, 0x07, 0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, + 0x0c, 0x80, 0xab, 0x24, 0x80, 0x40, 0xec, 0x87, + 0x60, 0x4f, 0x32, 0x80, 0x48, 0x56, 0x84, 0x46, + 0x85, 0x10, 0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, + 0x82, 0x81, 0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, + 0x81, 0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, + 0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, + 0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, + 0x40, 0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, + 0x81, 0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c, + 0x02, 0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c, + 0x81, 0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d, + 0x41, 0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a, + 0x00, 0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b, + 0x89, 0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d, + 0x41, 0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, + 0xf9, 0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, + 0x20, 0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08, + 0x80, 0xaf, 0x32, 0x82, 0x60, 0x50, 0x0d, 0x00, + 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, + 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, + 0xe3, 0x80, 0x48, 0xb6, 0x80, 0x47, 0xe7, 0x99, + 0x85, 0x99, 0x85, 0x99, }; -static const uint8_t unicode_prop_Other_Lowercase_table[59] = { +static const uint8_t unicode_prop_Other_Lowercase_table[69] = { 0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88, - 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59, - 0xb0, 0xbe, 0x8c, 0x80, 0xa1, 0xa4, 0x42, 0xb0, - 0x80, 0x8c, 0x80, 0x8f, 0x8c, 0x40, 0xd2, 0x8f, - 0x43, 0x4f, 0x99, 0x47, 0x91, 0x81, 0x60, 0x7a, - 0x1d, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x86, 0x81, - 0x43, 0x61, 0x83, 0x60, 0x5c, 0x1f, 0x01, 0x10, - 0xa9, 0x80, 0x88, + 0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d, + 0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1, + 0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c, + 0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91, + 0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80, + 0x40, 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, + 0x80, 0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, + 0x88, 0x60, 0xd8, 0x74, 0xbd, }; static const uint8_t unicode_prop_Other_Uppercase_table[15] = { @@ -3742,71 +3779,70 @@ static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = { 0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80, }; -static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = { - 0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44, - 0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f, - 0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80, - 0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b, - 0x84, +static const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = { + 0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80, + 0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, + 0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81, + 0x89, 0x10, 0x81, 0x8d, 0x80, }; -static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[448] = { +static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[447] = { 0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12, - 0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b, - 0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80, - 0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, - 0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, - 0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80, - 0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, - 0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, - 0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, - 0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, - 0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, - 0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, - 0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, - 0x46, 0x52, 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, - 0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, - 0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87, - 0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80, - 0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08, - 0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, - 0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, - 0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, - 0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, - 0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, - 0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, - 0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, - 0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, - 0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, - 0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, - 0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, - 0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, - 0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, - 0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, - 0x60, 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, - 0x89, 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, - 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00, - 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91, - 0xbf, 0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95, - 0x94, 0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00, - 0x80, 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40, - 0x83, 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80, - 0x88, 0x47, 0x87, 0x20, 0xa9, 0x80, 0x88, 0x60, - 0xb4, 0xe4, 0x83, 0x54, 0xb9, 0x86, 0x8d, 0x87, - 0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, - 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, - 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, - 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23, - 0x81, 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, - 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, - 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, - 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, - 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, - 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, - 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, - 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff, + 0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84, + 0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb, + 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89, + 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80, + 0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28, + 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08, + 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40, + 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7, + 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03, + 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80, + 0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b, + 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52, + 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80, + 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40, + 0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c, + 0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f, + 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00, + 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80, + 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01, + 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05, + 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40, + 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34, + 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82, + 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80, + 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5, + 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80, + 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e, + 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60, + 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x80, + 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, + 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, + 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2, + 0x00, 0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, + 0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, + 0x8c, 0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80, + 0x92, 0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, + 0x80, 0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, + 0x0a, 0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, + 0xa9, 0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x54, + 0xb9, 0x86, 0x8d, 0x87, 0xbf, 0x85, 0x42, 0x3e, + 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, + 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, + 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, + 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1, 0x48, 0x2f, + 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01, 0x00, 0x08, + 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, + 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90, + 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f, 0x99, + 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab, 0x83, + 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc, 0x05, + 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff, }; static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = { @@ -3834,7 +3870,7 @@ static const uint8_t unicode_prop_Deprecated_table[23] = { 0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80, }; -static const uint8_t unicode_prop_Diacritic_table[391] = { +static const uint8_t unicode_prop_Diacritic_table[399] = { 0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81, 0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b, 0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0, @@ -3869,20 +3905,21 @@ static const uint8_t unicode_prop_Diacritic_table[391] = { 0x00, 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81, - 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0xb0, 0x83, - 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, - 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, - 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, 0x8f, 0x80, - 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, 0x80, 0xfa, - 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, 0xf5, 0x81, - 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, 0x01, 0x0b, - 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, 0x91, 0x80, - 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, 0x01, 0x00, - 0x81, 0xd0, 0x80, 0x60, 0x4d, 0x57, 0x84, 0xba, - 0x86, 0x44, 0x57, 0x90, 0xcf, 0x81, 0x60, 0x3f, - 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, 0x81, - 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, 0x9d, - 0x83, 0x4f, 0x81, 0x86, 0x41, 0x76, 0x80, 0xbc, + 0x42, 0x3a, 0x85, 0x41, 0xd4, 0x82, 0xc5, 0x8a, + 0xb0, 0x83, 0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, + 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, + 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, + 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, + 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, + 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, + 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, + 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, + 0x01, 0x00, 0x81, 0xd0, 0x80, 0x56, 0xae, 0x8e, + 0x60, 0x36, 0x99, 0x84, 0xba, 0x86, 0x44, 0x57, + 0x90, 0xcf, 0x81, 0x60, 0x3f, 0xfd, 0x18, 0x30, + 0x81, 0x5f, 0x00, 0xad, 0x81, 0x96, 0x42, 0x1f, + 0x12, 0x2f, 0x39, 0x86, 0x9d, 0x83, 0x4e, 0x81, + 0xbd, 0x40, 0xc1, 0x86, 0x41, 0x76, 0x80, 0xbc, 0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82, }; @@ -3914,16 +3951,16 @@ static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = { 0x60, 0x2f, 0xf1, 0x81, }; -static const uint8_t unicode_prop_Ideographic_table[66] = { +static const uint8_t unicode_prop_Ideographic_table[69] = { 0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82, 0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, 0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60, 0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b, 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50, - 0x38, 0x86, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, + 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1, - 0x53, 0x4a, + 0x53, 0x4a, 0x84, 0x50, 0x5f, }; static const uint8_t unicode_prop_Join_Control_table[4] = { @@ -3979,7 +4016,7 @@ static const uint8_t unicode_prop_Regional_Indicator_table[4] = { 0x61, 0xf1, 0xe5, 0x99, }; -static const uint8_t unicode_prop_Sentence_Terminal_table[194] = { +static const uint8_t unicode_prop_Sentence_Terminal_table[196] = { 0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48, 0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa, 0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81, @@ -4001,13 +4038,13 @@ static const uint8_t unicode_prop_Sentence_Terminal_table[194] = { 0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, - 0xa3, 0x81, 0x42, 0xb3, 0x81, 0x60, 0x4b, 0x74, - 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80, - 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, 0x80, 0x5d, - 0xe7, 0x80, + 0xa3, 0x81, 0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, + 0x4b, 0x28, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, + 0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, + 0x80, 0x5d, 0xe7, 0x80, }; -static const uint8_t unicode_prop_Soft_Dotted_table[74] = { +static const uint8_t unicode_prop_Soft_Dotted_table[79] = { 0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80, 0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f, 0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2, @@ -4017,10 +4054,10 @@ static const uint8_t unicode_prop_Soft_Dotted_table[74] = { 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48, - 0x85, 0x80, + 0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80, }; -static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = { +static const uint8_t unicode_prop_Terminal_Punctuation_table[248] = { 0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80, 0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8, 0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3, @@ -4048,19 +4085,19 @@ static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = { 0x82, 0x8b, 0x81, 0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x0b, 0x81, 0x41, 0x9d, - 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0x45, 0x76, - 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, - 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, 0x81, 0x60, - 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, + 0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0xc9, 0x81, + 0x45, 0x2a, 0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, + 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, + 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83, }; -static const uint8_t unicode_prop_Unified_Ideograph_table[42] = { +static const uint8_t unicode_prop_Unified_Ideograph_table[45] = { 0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89, 0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60, - 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40, 0xdd, + 0xa6, 0xdf, 0x9f, 0x50, 0x39, 0x85, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e, - 0x53, 0x4a, + 0x53, 0x4a, 0x84, 0x50, 0x5f, }; static const uint8_t unicode_prop_Variation_Selector_table[13] = { @@ -4125,11 +4162,11 @@ static const uint8_t unicode_prop_Emoji_table[239] = { 0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01, 0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88, 0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05, - 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x84, - 0x88, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, + 0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x83, + 0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80, - 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, 0x88, 0x9c, - 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, 0x3e, + 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, 0x86, 0xad, + 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, 0x88, }; static const uint8_t unicode_prop_Emoji_Component_table[28] = { @@ -4152,7 +4189,7 @@ static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = { 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80, 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89, 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90, - 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x86, + 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88, }; static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { @@ -4170,11 +4207,11 @@ static const uint8_t unicode_prop_Emoji_Presentation_table[145] = { 0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, 0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, 0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, - 0xc5, 0x28, 0x12, 0x0a, 0x22, 0x8a, 0x0e, 0x88, + 0xc5, 0x28, 0x12, 0x0a, 0x1b, 0x8a, 0x0e, 0x88, 0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, - 0x89, 0x80, 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, - 0x88, 0x9c, 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, - 0x3e, + 0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x88, + 0x86, 0xad, 0x06, 0x87, 0x8d, 0x83, 0x88, 0x86, + 0x88, }; static const uint8_t unicode_prop_Extended_Pictographic_table[156] = { diff --git a/quickjs/libunicode.c b/deps/quickjs/libunicode.c similarity index 82% rename from quickjs/libunicode.c rename to deps/quickjs/libunicode.c index 9508b18..0712a6c 100644 --- a/quickjs/libunicode.c +++ b/deps/quickjs/libunicode.c @@ -22,13 +22,10 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" #include #include -#include "my_string.h" -#include "my_assert.h" +#include #include "cutils.h" #include "libunicode.h" @@ -46,11 +43,111 @@ enum { RUN_TYPE_UF_D1_EXT, RUN_TYPE_U_EXT, RUN_TYPE_LF_EXT, - RUN_TYPE_U_EXT2, - RUN_TYPE_L_EXT2, - RUN_TYPE_U_EXT3, + RUN_TYPE_UF_EXT2, + RUN_TYPE_LF_EXT2, + RUN_TYPE_UF_EXT3, }; +static int lre_case_conv1(uint32_t c, int conv_type) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + lre_case_conv(res, c, conv_type); + return res[0]; +} + +/* case conversion using the table entry 'idx' with value 'v' */ +static int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v) +{ + uint32_t code, data, type, a, is_lower; + is_lower = (conv_type != 0); + type = (v >> (32 - 17 - 7 - 4)) & 0xf; + data = ((v & 0xf) << 8) | case_conv_table2[idx]; + code = v >> (32 - 17); + switch(type) { + case RUN_TYPE_U: + case RUN_TYPE_L: + case RUN_TYPE_UF: + case RUN_TYPE_LF: + if (conv_type == (type & 1) || + (type >= RUN_TYPE_UF && conv_type == 2)) { + c = c - code + (case_conv_table1[data] >> (32 - 17)); + } + break; + case RUN_TYPE_UL: + a = c - code; + if ((a & 1) != (1 - is_lower)) + break; + c = (a ^ 1) + code; + break; + case RUN_TYPE_LSU: + a = c - code; + if (a == 1) { + c += 2 * is_lower - 1; + } else if (a == (1 - is_lower) * 2) { + c += (2 * is_lower - 1) * 2; + } + break; + case RUN_TYPE_U2L_399_EXT2: + if (!is_lower) { + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = 0x399; + return 2; + } else { + c = c - code + case_conv_ext[data & 0x3f]; + } + break; + case RUN_TYPE_UF_D20: + if (conv_type == 1) + break; + c = data + (conv_type == 2) * 0x20; + break; + case RUN_TYPE_UF_D1_EXT: + if (conv_type == 1) + break; + c = case_conv_ext[data] + (conv_type == 2); + break; + case RUN_TYPE_U_EXT: + case RUN_TYPE_LF_EXT: + if (is_lower != (type - RUN_TYPE_U_EXT)) + break; + c = case_conv_ext[data]; + break; + case RUN_TYPE_LF_EXT2: + if (!is_lower) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + return 2; + case RUN_TYPE_UF_EXT2: + if (conv_type == 1) + break; + res[0] = c - code + case_conv_ext[data >> 6]; + res[1] = case_conv_ext[data & 0x3f]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + } + return 2; + default: + case RUN_TYPE_UF_EXT3: + if (conv_type == 1) + break; + res[0] = case_conv_ext[data >> 8]; + res[1] = case_conv_ext[(data >> 4) & 0xf]; + res[2] = case_conv_ext[data & 0xf]; + if (conv_type == 2) { + /* convert to lower */ + res[0] = lre_case_conv1(res[0], 1); + res[1] = lre_case_conv1(res[1], 1); + res[2] = lre_case_conv1(res[2], 1); + } + return 3; + } + res[0] = c; + return 1; +} + /* conv_type: 0 = to upper 1 = to lower @@ -69,10 +166,9 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) } } } else { - uint32_t v, code, data, type, len, a, is_lower; + uint32_t v, code, len; int idx, idx_min, idx_max; - is_lower = (conv_type != 0); idx_min = 0; idx_max = countof(case_conv_table1) - 1; while (idx_min <= idx_max) { @@ -85,74 +181,7 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) } else if (c >= code + len) { idx_min = idx + 1; } else { - type = (v >> (32 - 17 - 7 - 4)) & 0xf; - data = ((v & 0xf) << 8) | case_conv_table2[idx]; - switch(type) { - case RUN_TYPE_U: - case RUN_TYPE_L: - case RUN_TYPE_UF: - case RUN_TYPE_LF: - if (conv_type == (type & 1) || - (type >= RUN_TYPE_UF && conv_type == 2)) { - c = c - code + (case_conv_table1[data] >> (32 - 17)); - } - break; - case RUN_TYPE_UL: - a = c - code; - if ((a & 1) != (1 - is_lower)) - break; - c = (a ^ 1) + code; - break; - case RUN_TYPE_LSU: - a = c - code; - if (a == 1) { - c += 2 * is_lower - 1; - } else if (a == (1 - is_lower) * 2) { - c += (2 * is_lower - 1) * 2; - } - break; - case RUN_TYPE_U2L_399_EXT2: - if (!is_lower) { - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = 0x399; - return 2; - } else { - c = c - code + case_conv_ext[data & 0x3f]; - } - break; - case RUN_TYPE_UF_D20: - if (conv_type == 1) - break; - c = data + (conv_type == 2) * 0x20; - break; - case RUN_TYPE_UF_D1_EXT: - if (conv_type == 1) - break; - c = case_conv_ext[data] + (conv_type == 2); - break; - case RUN_TYPE_U_EXT: - case RUN_TYPE_LF_EXT: - if (is_lower != (type - RUN_TYPE_U_EXT)) - break; - c = case_conv_ext[data]; - break; - case RUN_TYPE_U_EXT2: - case RUN_TYPE_L_EXT2: - if (conv_type != (type - RUN_TYPE_U_EXT2)) - break; - res[0] = c - code + case_conv_ext[data >> 6]; - res[1] = case_conv_ext[data & 0x3f]; - return 2; - default: - case RUN_TYPE_U_EXT3: - if (conv_type != 0) - break; - res[0] = case_conv_ext[data >> 8]; - res[1] = case_conv_ext[(data >> 4) & 0xf]; - res[2] = case_conv_ext[data & 0xf]; - return 3; - } - break; + return lre_case_conv_entry(res, c, conv_type, idx, v); } } } @@ -160,6 +189,77 @@ int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) return 1; } +static int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode) +{ + uint32_t res[LRE_CC_RES_LEN_MAX]; + int len; + + if (is_unicode) { + len = lre_case_conv_entry(res, c, 2, idx, v); + if (len == 1) { + c = res[0]; + } else { + /* handle the few specific multi-character cases (see + unicode_gen.c:dump_case_folding_special_cases()) */ + if (c == 0xfb06) { + c = 0xfb05; + } else if (c == 0x01fd3) { + c = 0x390; + } else if (c == 0x01fe3) { + c = 0x3b0; + } + } + } else { + if (likely(c < 128)) { + if (c >= 'a' && c <= 'z') + c = c - 'a' + 'A'; + } else { + /* legacy regexp: to upper case if single char >= 128 */ + len = lre_case_conv_entry(res, c, FALSE, idx, v); + if (len == 1 && res[0] >= 128) + c = res[0]; + } + } + return c; +} + +/* JS regexp specific rules for case folding */ +int lre_canonicalize(uint32_t c, BOOL is_unicode) +{ + if (c < 128) { + /* fast case */ + if (is_unicode) { + if (c >= 'A' && c <= 'Z') { + c = c - 'A' + 'a'; + } + } else { + if (c >= 'a' && c <= 'z') { + c = c - 'a' + 'A'; + } + } + } else { + uint32_t v, code, len; + int idx, idx_min, idx_max; + + idx_min = 0; + idx_max = countof(case_conv_table1) - 1; + while (idx_min <= idx_max) { + idx = (unsigned)(idx_max + idx_min) / 2; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + if (c < code) { + idx_max = idx - 1; + } else if (c >= code + len) { + idx_min = idx + 1; + } else { + return lre_case_folding_entry(c, idx, v, is_unicode); + } + } + } + return c; +} + static uint32_t get_le24(const uint8_t *ptr) { #if defined(__x86__) || defined(__x86_64__) @@ -1182,11 +1282,11 @@ static int unicode_case1(CharRange *cr, int case_mask) #define MR(x) (1 << RUN_TYPE_ ## x) const uint32_t tab_run_mask[3] = { MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | - MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3), + MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3), - MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2), + MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2), - MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT), + MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3), }; #undef MR uint32_t mask, v, code, type, len, i, idx; @@ -1239,7 +1339,136 @@ static int unicode_case1(CharRange *cr, int case_mask) } return 0; } - + +static int point_cmp(const void *p1, const void *p2, void *arg) +{ + uint32_t v1 = *(uint32_t *)p1; + uint32_t v2 = *(uint32_t *)p2; + return (v1 > v2) - (v1 < v2); +} + +static void cr_sort_and_remove_overlap(CharRange *cr) +{ + uint32_t start, end, start1, end1, i, j; + + /* the resulting ranges are not necessarily sorted and may overlap */ + rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL); + j = 0; + for(i = 0; i < cr->len; ) { + start = cr->points[i]; + end = cr->points[i + 1]; + i += 2; + while (i < cr->len) { + start1 = cr->points[i]; + end1 = cr->points[i + 1]; + if (start1 > end) { + /* |------| + * |-------| */ + break; + } else if (end1 <= end) { + /* |------| + * |--| */ + i += 2; + } else { + /* |------| + * |-------| */ + end = end1; + i += 2; + } + } + cr->points[j] = start; + cr->points[j + 1] = end; + j += 2; + } + cr->len = j; +} + +/* canonicalize a character set using the JS regex case folding rules + (see lre_canonicalize()) */ +int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode) +{ + CharRange cr_inter, cr_mask, cr_result, cr_sub; + uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d; + + cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_result, cr->mem_opaque, cr->realloc_func); + cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func); + + if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U)) + goto fail; + if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + if (cr_invert(&cr_mask)) + goto fail; + if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER)) + goto fail; + + /* cr_inter = cr & cr_mask */ + /* cr_sub = cr & ~cr_mask */ + + /* use the case conversion table to compute the result */ + d_start = -1; + d_end = -1; + idx = 0; + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + for(i = 0; i < cr_inter.len; i += 2) { + start = cr_inter.points[i]; + end = cr_inter.points[i + 1]; + + for(c = start; c < end; c++) { + for(;;) { + if (c >= code && c < code + len) + break; + idx++; + assert(idx < countof(case_conv_table1)); + v = case_conv_table1[idx]; + code = v >> (32 - 17); + len = (v >> (32 - 17 - 7)) & 0x7f; + } + d = lre_case_folding_entry(c, idx, v, is_unicode); + /* try to merge with the current interval */ + if (d_start == -1) { + d_start = d; + d_end = d + 1; + } else if (d_end == d) { + d_end++; + } else { + cr_add_interval(&cr_result, d_start, d_end); + d_start = d; + d_end = d + 1; + } + } + } + if (d_start != -1) { + if (cr_add_interval(&cr_result, d_start, d_end)) + goto fail; + } + + /* the resulting ranges are not necessarily sorted and may overlap */ + cr_sort_and_remove_overlap(&cr_result); + + /* or with the character not affected by the case folding */ + cr->len = 0; + if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION)) + goto fail; + + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return 0; + fail: + cr_free(&cr_inter); + cr_free(&cr_mask); + cr_free(&cr_result); + cr_free(&cr_sub); + return -1; +} + typedef enum { POP_GC, POP_PROP, diff --git a/quickjs/libunicode.h b/deps/quickjs/libunicode.h similarity index 96% rename from quickjs/libunicode.h rename to deps/quickjs/libunicode.h index e974105..8abacb0 100644 --- a/quickjs/libunicode.h +++ b/deps/quickjs/libunicode.h @@ -24,7 +24,7 @@ #ifndef LIBUNICODE_H #define LIBUNICODE_H -// #include +#include #define LRE_BOOL int /* for documentation purposes */ @@ -41,6 +41,7 @@ typedef enum { } UnicodeNormalizationEnum; int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); +int lre_canonicalize(uint32_t c, BOOL is_unicode); LRE_BOOL lre_is_cased(uint32_t c); LRE_BOOL lre_is_case_ignorable(uint32_t c); @@ -101,6 +102,8 @@ int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, int cr_invert(CharRange *cr); +int cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode); + #ifdef CONFIG_ALL_UNICODE LRE_BOOL lre_is_id_start(uint32_t c); diff --git a/deps/quickjs/list.h b/deps/quickjs/list.h new file mode 100644 index 0000000..5c18234 --- /dev/null +++ b/deps/quickjs/list.h @@ -0,0 +1,99 @@ +/* + * Linux klist like system + * + * Copyright (c) 2016-2017 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef LIST_H +#define LIST_H + +#ifndef NULL +#include +#endif + +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +#define LIST_HEAD_INIT(el) { &(el), &(el) } + +/* return the pointer of type 'type *' containing 'el' as field 'member' */ +#define list_entry(el, type, member) container_of(el, type, member) + +static inline void init_list_head(struct list_head *head) +{ + head->prev = head; + head->next = head; +} + +/* insert 'el' between 'prev' and 'next' */ +static inline void __list_add(struct list_head *el, + struct list_head *prev, struct list_head *next) +{ + prev->next = el; + el->prev = prev; + el->next = next; + next->prev = el; +} + +/* add 'el' at the head of the list 'head' (= after element head) */ +static inline void list_add(struct list_head *el, struct list_head *head) +{ + __list_add(el, head, head->next); +} + +/* add 'el' at the end of the list 'head' (= before element head) */ +static inline void list_add_tail(struct list_head *el, struct list_head *head) +{ + __list_add(el, head->prev, head); +} + +static inline void list_del(struct list_head *el) +{ + struct list_head *prev, *next; + prev = el->prev; + next = el->next; + prev->next = next; + next->prev = prev; + el->prev = NULL; /* fail safe */ + el->next = NULL; /* fail safe */ +} + +static inline int list_empty(struct list_head *el) +{ + return el->next == el; +} + +#define list_for_each(el, head) \ + for(el = (head)->next; el != (head); el = el->next) + +#define list_for_each_safe(el, el1, head) \ + for(el = (head)->next, el1 = el->next; el != (head); \ + el = el1, el1 = el->next) + +#define list_for_each_prev(el, head) \ + for(el = (head)->prev; el != (head); el = el->prev) + +#define list_for_each_prev_safe(el, el1, head) \ + for(el = (head)->prev, el1 = el->prev; el != (head); \ + el = el1, el1 = el->prev) + +#endif /* LIST_H */ diff --git a/deps/quickjs/qjs.c b/deps/quickjs/qjs.c new file mode 100644 index 0000000..77b5cfb --- /dev/null +++ b/deps/quickjs/qjs.c @@ -0,0 +1,561 @@ +/* + * QuickJS stand alone interpreter + * + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__APPLE__) +#include +#elif defined(__linux__) +#include +#endif + +#include "cutils.h" +#include "quickjs-libc.h" + +extern const uint8_t qjsc_repl[]; +extern const uint32_t qjsc_repl_size; +#ifdef CONFIG_BIGNUM +extern const uint8_t qjsc_qjscalc[]; +extern const uint32_t qjsc_qjscalc_size; +static int bignum_ext; +#endif + +static int eval_buf(JSContext *ctx, const void *buf, int buf_len, + const char *filename, int eval_flags) +{ + JSValue val; + int ret; + + if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) { + /* for the modules, we compile then run to be able to set + import.meta */ + val = JS_Eval(ctx, buf, buf_len, filename, + eval_flags | JS_EVAL_FLAG_COMPILE_ONLY); + if (!JS_IsException(val)) { + js_module_set_import_meta(ctx, val, TRUE, TRUE); + val = JS_EvalFunction(ctx, val); + } + } else { + val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); + } + if (JS_IsException(val)) { + js_std_dump_error(ctx); + ret = -1; + } else { + ret = 0; + } + JS_FreeValue(ctx, val); + return ret; +} + +static int eval_file(JSContext *ctx, const char *filename, int module) +{ + uint8_t *buf; + int ret, eval_flags; + size_t buf_len; + + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + perror(filename); + exit(1); + } + + if (module < 0) { + module = (has_suffix(filename, ".mjs") || + JS_DetectModule((const char *)buf, buf_len)); + } + if (module) + eval_flags = JS_EVAL_TYPE_MODULE; + else + eval_flags = JS_EVAL_TYPE_GLOBAL; + ret = eval_buf(ctx, buf, buf_len, filename, eval_flags); + js_free(ctx, buf); + return ret; +} + +/* also used to initialize the worker context */ +static JSContext *JS_NewCustomContext(JSRuntime *rt) +{ + JSContext *ctx; + ctx = JS_NewContext(rt); + if (!ctx) + return NULL; +#ifdef CONFIG_BIGNUM + if (bignum_ext) { + JS_AddIntrinsicBigFloat(ctx); + JS_AddIntrinsicBigDecimal(ctx); + JS_AddIntrinsicOperators(ctx); + JS_EnableBignumExt(ctx, TRUE); + } +#endif + /* system modules */ + js_init_module_std(ctx, "std"); + js_init_module_os(ctx, "os"); + return ctx; +} + +#if defined(__APPLE__) +#define MALLOC_OVERHEAD 0 +#else +#define MALLOC_OVERHEAD 8 +#endif + +struct trace_malloc_data { + uint8_t *base; +}; + +static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr, + struct trace_malloc_data *dp) +{ + return ptr - dp->base; +} + +/* default memory allocation functions with memory limitation */ +static size_t js_trace_malloc_usable_size(const void *ptr) +{ +#if defined(__APPLE__) + return malloc_size(ptr); +#elif defined(_WIN32) + return _msize((void *)ptr); +#elif defined(EMSCRIPTEN) + return 0; +#elif defined(__linux__) + return malloc_usable_size((void *)ptr); +#else + /* change this to `return 0;` if compilation fails */ + return malloc_usable_size((void *)ptr); +#endif +} + +static void +#ifdef _WIN32 +/* mingw printf is used */ +__attribute__((format(gnu_printf, 2, 3))) +#else +__attribute__((format(printf, 2, 3))) +#endif + js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...) +{ + va_list ap; + int c; + + va_start(ap, fmt); + while ((c = *fmt++) != '\0') { + if (c == '%') { + /* only handle %p and %zd */ + if (*fmt == 'p') { + uint8_t *ptr = va_arg(ap, void *); + if (ptr == NULL) { + printf("NULL"); + } else { + printf("H%+06lld.%zd", + js_trace_malloc_ptr_offset(ptr, s->opaque), + js_trace_malloc_usable_size(ptr)); + } + fmt++; + continue; + } + if (fmt[0] == 'z' && fmt[1] == 'd') { + size_t sz = va_arg(ap, size_t); + printf("%zd", sz); + fmt += 2; + continue; + } + } + putc(c, stdout); + } + va_end(ap); +} + +static void js_trace_malloc_init(struct trace_malloc_data *s) +{ + free(s->base = malloc(8)); +} + +static void *js_trace_malloc(JSMallocState *s, size_t size) +{ + void *ptr; + + /* Do not allocate zero bytes: behavior is platform dependent */ + assert(size != 0); + + if (unlikely(s->malloc_size + size > s->malloc_limit)) + return NULL; + ptr = malloc(size); + js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr); + if (ptr) { + s->malloc_count++; + s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + } + return ptr; +} + +static void js_trace_free(JSMallocState *s, void *ptr) +{ + if (!ptr) + return; + + js_trace_malloc_printf(s, "F %p\n", ptr); + s->malloc_count--; + s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD; + free(ptr); +} + +static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size) +{ + size_t old_size; + + if (!ptr) { + if (size == 0) + return NULL; + return js_trace_malloc(s, size); + } + old_size = js_trace_malloc_usable_size(ptr); + if (size == 0) { + js_trace_malloc_printf(s, "R %zd %p\n", size, ptr); + s->malloc_count--; + s->malloc_size -= old_size + MALLOC_OVERHEAD; + free(ptr); + return NULL; + } + if (s->malloc_size + size - old_size > s->malloc_limit) + return NULL; + + js_trace_malloc_printf(s, "R %zd %p", size, ptr); + + ptr = realloc(ptr, size); + js_trace_malloc_printf(s, " -> %p\n", ptr); + if (ptr) { + s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size; + } + return ptr; +} + +static const JSMallocFunctions trace_mf = { + js_trace_malloc, + js_trace_free, + js_trace_realloc, + js_trace_malloc_usable_size, +}; + +#define PROG_NAME "qjs" + +void help(void) +{ + printf("QuickJS version " CONFIG_VERSION "\n" + "usage: " PROG_NAME " [options] [file [args]]\n" + "-h --help list options\n" + "-e --eval EXPR evaluate EXPR\n" + "-i --interactive go to interactive mode\n" + "-m --module load as ES6 module (default=autodetect)\n" + " --script load as ES6 script (default=autodetect)\n" + "-I --include file include an additional file\n" + " --std make 'std' and 'os' available to the loaded script\n" +#ifdef CONFIG_BIGNUM + " --bignum enable the bignum extensions (BigFloat, BigDecimal)\n" + " --qjscalc load the QJSCalc runtime (default if invoked as qjscalc)\n" +#endif + "-T --trace trace memory allocation\n" + "-d --dump dump the memory usage stats\n" + " --memory-limit n limit the memory usage to 'n' bytes\n" + " --stack-size n limit the stack size to 'n' bytes\n" + " --unhandled-rejection dump unhandled promise rejections\n" + "-q --quit just instantiate the interpreter and quit\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + JSRuntime *rt; + JSContext *ctx; + struct trace_malloc_data trace_data = { NULL }; + int optind; + char *expr = NULL; + int interactive = 0; + int dump_memory = 0; + int trace_memory = 0; + int empty_run = 0; + int module = -1; + int load_std = 0; + int dump_unhandled_promise_rejection = 0; + size_t memory_limit = 0; + char *include_list[32]; + int i, include_count = 0; +#ifdef CONFIG_BIGNUM + int load_jscalc; +#endif + size_t stack_size = 0; + +#ifdef CONFIG_BIGNUM + /* load jscalc runtime if invoked as 'qjscalc' */ + { + const char *p, *exename; + exename = argv[0]; + p = strrchr(exename, '/'); + if (p) + exename = p + 1; + load_jscalc = !strcmp(exename, "qjscalc"); + } +#endif + + /* cannot use getopt because we want to pass the command line to + the script */ + optind = 1; + while (optind < argc && *argv[optind] == '-') { + char *arg = argv[optind] + 1; + const char *longopt = ""; + /* a single - is not an option, it also stops argument scanning */ + if (!*arg) + break; + optind++; + if (*arg == '-') { + longopt = arg + 1; + arg += strlen(arg); + /* -- stops argument scanning */ + if (!*longopt) + break; + } + for (; *arg || *longopt; longopt = "") { + char opt = *arg; + if (opt) + arg++; + if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { + help(); + continue; + } + if (opt == 'e' || !strcmp(longopt, "eval")) { + if (*arg) { + expr = arg; + break; + } + if (optind < argc) { + expr = argv[optind++]; + break; + } + fprintf(stderr, "qjs: missing expression for -e\n"); + exit(2); + } + if (opt == 'I' || !strcmp(longopt, "include")) { + if (optind >= argc) { + fprintf(stderr, "expecting filename"); + exit(1); + } + if (include_count >= countof(include_list)) { + fprintf(stderr, "too many included files"); + exit(1); + } + include_list[include_count++] = argv[optind++]; + continue; + } + if (opt == 'i' || !strcmp(longopt, "interactive")) { + interactive++; + continue; + } + if (opt == 'm' || !strcmp(longopt, "module")) { + module = 1; + continue; + } + if (!strcmp(longopt, "script")) { + module = 0; + continue; + } + if (opt == 'd' || !strcmp(longopt, "dump")) { + dump_memory++; + continue; + } + if (opt == 'T' || !strcmp(longopt, "trace")) { + trace_memory++; + continue; + } + if (!strcmp(longopt, "std")) { + load_std = 1; + continue; + } + if (!strcmp(longopt, "unhandled-rejection")) { + dump_unhandled_promise_rejection = 1; + continue; + } +#ifdef CONFIG_BIGNUM + if (!strcmp(longopt, "bignum")) { + bignum_ext = 1; + continue; + } + if (!strcmp(longopt, "qjscalc")) { + load_jscalc = 1; + continue; + } +#endif + if (opt == 'q' || !strcmp(longopt, "quit")) { + empty_run++; + continue; + } + if (!strcmp(longopt, "memory-limit")) { + if (optind >= argc) { + fprintf(stderr, "expecting memory limit"); + exit(1); + } + memory_limit = (size_t)strtod(argv[optind++], NULL); + continue; + } + if (!strcmp(longopt, "stack-size")) { + if (optind >= argc) { + fprintf(stderr, "expecting stack size"); + exit(1); + } + stack_size = (size_t)strtod(argv[optind++], NULL); + continue; + } + if (opt) { + fprintf(stderr, "qjs: unknown option '-%c'\n", opt); + } else { + fprintf(stderr, "qjs: unknown option '--%s'\n", longopt); + } + help(); + } + } + +#ifdef CONFIG_BIGNUM + if (load_jscalc) + bignum_ext = 1; +#endif + + if (trace_memory) { + js_trace_malloc_init(&trace_data); + rt = JS_NewRuntime2(&trace_mf, &trace_data); + } else { + rt = JS_NewRuntime(); + } + if (!rt) { + fprintf(stderr, "qjs: cannot allocate JS runtime\n"); + exit(2); + } + if (memory_limit != 0) + JS_SetMemoryLimit(rt, memory_limit); + if (stack_size != 0) + JS_SetMaxStackSize(rt, stack_size); + js_std_set_worker_new_context_func(JS_NewCustomContext); + js_std_init_handlers(rt); + ctx = JS_NewCustomContext(rt); + if (!ctx) { + fprintf(stderr, "qjs: cannot allocate JS context\n"); + exit(2); + } + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + + if (dump_unhandled_promise_rejection) { + JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, + NULL); + } + + if (!empty_run) { +#ifdef CONFIG_BIGNUM + if (load_jscalc) { + js_std_eval_binary(ctx, qjsc_qjscalc, qjsc_qjscalc_size, 0); + } +#endif + js_std_add_helpers(ctx, argc - optind, argv + optind); + + /* make 'std' and 'os' visible to non module code */ + if (load_std) { + const char *str = "import * as std from 'std';\n" + "import * as os from 'os';\n" + "globalThis.std = std;\n" + "globalThis.os = os;\n"; + eval_buf(ctx, str, strlen(str), "", JS_EVAL_TYPE_MODULE); + } + + for(i = 0; i < include_count; i++) { + if (eval_file(ctx, include_list[i], module)) + goto fail; + } + + if (expr) { + if (eval_buf(ctx, expr, strlen(expr), "", 0)) + goto fail; + } else + if (optind >= argc) { + /* interactive mode */ + interactive = 1; + } else { + const char *filename; + filename = argv[optind]; + if (eval_file(ctx, filename, module)) + goto fail; + } + if (interactive) { + js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); + } + js_std_loop(ctx); + } + + if (dump_memory) { + JSMemoryUsage stats; + JS_ComputeMemoryUsage(rt, &stats); + JS_DumpMemoryUsage(stdout, &stats, rt); + } + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + if (empty_run && dump_memory) { + clock_t t[5]; + double best[5]; + int i, j; + for (i = 0; i < 100; i++) { + t[0] = clock(); + rt = JS_NewRuntime(); + t[1] = clock(); + ctx = JS_NewContext(rt); + t[2] = clock(); + JS_FreeContext(ctx); + t[3] = clock(); + JS_FreeRuntime(rt); + t[4] = clock(); + for (j = 4; j > 0; j--) { + double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC; + if (i == 0 || best[j] > ms) + best[j] = ms; + } + } + printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n", + best[1] + best[2] + best[3] + best[4], + best[1], best[2], best[3], best[4]); + } + return 0; + fail: + js_std_free_handlers(rt); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return 1; +} diff --git a/deps/quickjs/qjsc.c b/deps/quickjs/qjsc.c new file mode 100644 index 0000000..f8e60b3 --- /dev/null +++ b/deps/quickjs/qjsc.c @@ -0,0 +1,761 @@ +/* + * QuickJS command line compiler + * + * Copyright (c) 2018-2021 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(_WIN32) +#include +#endif + +#include "cutils.h" +#include "quickjs-libc.h" + +typedef struct { + char *name; + char *short_name; + int flags; +} namelist_entry_t; + +typedef struct namelist_t { + namelist_entry_t *array; + int count; + int size; +} namelist_t; + +typedef struct { + const char *option_name; + const char *init_name; +} FeatureEntry; + +static namelist_t cname_list; +static namelist_t cmodule_list; +static namelist_t init_module_list; +static uint64_t feature_bitmap; +static FILE *outfile; +static BOOL byte_swap; +static BOOL dynamic_export; +static const char *c_ident_prefix = "qjsc_"; + +#define FE_ALL (-1) + +static const FeatureEntry feature_list[] = { + { "date", "Date" }, + { "eval", "Eval" }, + { "string-normalize", "StringNormalize" }, + { "regexp", "RegExp" }, + { "json", "JSON" }, + { "proxy", "Proxy" }, + { "map", "MapSet" }, + { "typedarray", "TypedArrays" }, + { "promise", "Promise" }, +#define FE_MODULE_LOADER 9 + { "module-loader", NULL }, + { "bigint", "BigInt" }, +}; + +void namelist_add(namelist_t *lp, const char *name, const char *short_name, + int flags) +{ + namelist_entry_t *e; + if (lp->count == lp->size) { + size_t newsize = lp->size + (lp->size >> 1) + 4; + namelist_entry_t *a = + realloc(lp->array, sizeof(lp->array[0]) * newsize); + /* XXX: check for realloc failure */ + lp->array = a; + lp->size = newsize; + } + e = &lp->array[lp->count++]; + e->name = strdup(name); + if (short_name) + e->short_name = strdup(short_name); + else + e->short_name = NULL; + e->flags = flags; +} + +void namelist_free(namelist_t *lp) +{ + while (lp->count > 0) { + namelist_entry_t *e = &lp->array[--lp->count]; + free(e->name); + free(e->short_name); + } + free(lp->array); + lp->array = NULL; + lp->size = 0; +} + +namelist_entry_t *namelist_find(namelist_t *lp, const char *name) +{ + int i; + for(i = 0; i < lp->count; i++) { + namelist_entry_t *e = &lp->array[i]; + if (!strcmp(e->name, name)) + return e; + } + return NULL; +} + +static void get_c_name(char *buf, size_t buf_size, const char *file) +{ + const char *p, *r; + size_t len, i; + int c; + char *q; + + p = strrchr(file, '/'); + if (!p) + p = file; + else + p++; + r = strrchr(p, '.'); + if (!r) + len = strlen(p); + else + len = r - p; + pstrcpy(buf, buf_size, c_ident_prefix); + q = buf + strlen(buf); + for(i = 0; i < len; i++) { + c = p[i]; + if (!((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z'))) { + c = '_'; + } + if ((q - buf) < buf_size - 1) + *q++ = c; + } + *q = '\0'; +} + +static void dump_hex(FILE *f, const uint8_t *buf, size_t len) +{ + size_t i, col; + col = 0; + for(i = 0; i < len; i++) { + fprintf(f, " 0x%02x,", buf[i]); + if (++col == 8) { + fprintf(f, "\n"); + col = 0; + } + } + if (col != 0) + fprintf(f, "\n"); +} + +static void output_object_code(JSContext *ctx, + FILE *fo, JSValueConst obj, const char *c_name, + BOOL load_only) +{ + uint8_t *out_buf; + size_t out_buf_len; + int flags; + flags = JS_WRITE_OBJ_BYTECODE; + if (byte_swap) + flags |= JS_WRITE_OBJ_BSWAP; + out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags); + if (!out_buf) { + js_std_dump_error(ctx); + exit(1); + } + + namelist_add(&cname_list, c_name, NULL, load_only); + + fprintf(fo, "const uint32_t %s_size = %u;\n\n", + c_name, (unsigned int)out_buf_len); + fprintf(fo, "const uint8_t %s[%u] = {\n", + c_name, (unsigned int)out_buf_len); + dump_hex(fo, out_buf, out_buf_len); + fprintf(fo, "};\n\n"); + + js_free(ctx, out_buf); +} + +static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m) +{ + /* should never be called when compiling JS code */ + abort(); +} + +static void find_unique_cname(char *cname, size_t cname_size) +{ + char cname1[1024]; + int suffix_num; + size_t len, max_len; + assert(cname_size >= 32); + /* find a C name not matching an existing module C name by + adding a numeric suffix */ + len = strlen(cname); + max_len = cname_size - 16; + if (len > max_len) + cname[max_len] = '\0'; + suffix_num = 1; + for(;;) { + snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num); + if (!namelist_find(&cname_list, cname1)) + break; + suffix_num++; + } + pstrcpy(cname, cname_size, cname1); +} + +JSModuleDef *jsc_module_loader(JSContext *ctx, + const char *module_name, void *opaque) +{ + JSModuleDef *m; + namelist_entry_t *e; + + /* check if it is a declared C or system module */ + e = namelist_find(&cmodule_list, module_name); + if (e) { + /* add in the static init module list */ + namelist_add(&init_module_list, e->name, e->short_name, 0); + /* create a dummy module */ + m = JS_NewCModule(ctx, module_name, js_module_dummy_init); + } else if (has_suffix(module_name, ".so")) { + fprintf(stderr, "Warning: binary module '%s' will be dynamically loaded\n", module_name); + /* create a dummy module */ + m = JS_NewCModule(ctx, module_name, js_module_dummy_init); + /* the resulting executable will export its symbols for the + dynamic library */ + dynamic_export = TRUE; + } else { + size_t buf_len; + uint8_t *buf; + JSValue func_val; + char cname[1024]; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + get_c_name(cname, sizeof(cname), module_name); + if (namelist_find(&cname_list, cname)) { + find_unique_cname(cname, sizeof(cname)); + } + output_object_code(ctx, outfile, func_val, cname, TRUE); + + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + } + return m; +} + +static void compile_file(JSContext *ctx, FILE *fo, + const char *filename, + const char *c_name1, + int module) +{ + uint8_t *buf; + char c_name[1024]; + int eval_flags; + JSValue obj; + size_t buf_len; + + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + fprintf(stderr, "Could not load '%s'\n", filename); + exit(1); + } + eval_flags = JS_EVAL_FLAG_COMPILE_ONLY; + if (module < 0) { + module = (has_suffix(filename, ".mjs") || + JS_DetectModule((const char *)buf, buf_len)); + } + if (module) + eval_flags |= JS_EVAL_TYPE_MODULE; + else + eval_flags |= JS_EVAL_TYPE_GLOBAL; + obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags); + if (JS_IsException(obj)) { + js_std_dump_error(ctx); + exit(1); + } + js_free(ctx, buf); + if (c_name1) { + pstrcpy(c_name, sizeof(c_name), c_name1); + } else { + get_c_name(c_name, sizeof(c_name), filename); + } + output_object_code(ctx, fo, obj, c_name, FALSE); + JS_FreeValue(ctx, obj); +} + +static const char main_c_template1[] = + "int main(int argc, char **argv)\n" + "{\n" + " JSRuntime *rt;\n" + " JSContext *ctx;\n" + " rt = JS_NewRuntime();\n" + " js_std_set_worker_new_context_func(JS_NewCustomContext);\n" + " js_std_init_handlers(rt);\n" + ; + +static const char main_c_template2[] = + " js_std_loop(ctx);\n" + " js_std_free_handlers(rt);\n" + " JS_FreeContext(ctx);\n" + " JS_FreeRuntime(rt);\n" + " return 0;\n" + "}\n"; + +#define PROG_NAME "qjsc" + +void help(void) +{ + printf("QuickJS Compiler version " CONFIG_VERSION "\n" + "usage: " PROG_NAME " [options] [files]\n" + "\n" + "options are:\n" + "-c only output bytecode to a C file\n" + "-e output main() and bytecode to a C file (default = executable output)\n" + "-o output set the output filename\n" + "-N cname set the C name of the generated data\n" + "-m compile as Javascript module (default=autodetect)\n" + "-D module_name compile a dynamically loaded module or worker\n" + "-M module_name[,cname] add initialization code for an external C module\n" + "-x byte swapped output\n" + "-p prefix set the prefix of the generated C names\n" + "-S n set the maximum stack size to 'n' bytes (default=%d)\n", + JS_DEFAULT_STACK_SIZE); +#ifdef CONFIG_LTO + { + int i; + printf("-flto use link time optimization\n"); + printf("-fbignum enable bignum extensions\n"); + printf("-fno-["); + for(i = 0; i < countof(feature_list); i++) { + if (i != 0) + printf("|"); + printf("%s", feature_list[i].option_name); + } + printf("]\n" + " disable selected language features (smaller code size)\n"); + } +#endif + exit(1); +} + +#if defined(CONFIG_CC) && !defined(_WIN32) + +int exec_cmd(char **argv) +{ + int pid, status, ret; + + pid = fork(); + if (pid == 0) { + execvp(argv[0], argv); + exit(1); + } + + for(;;) { + ret = waitpid(pid, &status, 0); + if (ret == pid && WIFEXITED(status)) + break; + } + return WEXITSTATUS(status); +} + +static int output_executable(const char *out_filename, const char *cfilename, + BOOL use_lto, BOOL verbose, const char *exename) +{ + const char *argv[64]; + const char **arg, *bn_suffix, *lto_suffix; + char libjsname[1024]; + char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p; + int ret; + + /* get the directory of the executable */ + pstrcpy(exe_dir, sizeof(exe_dir), exename); + p = strrchr(exe_dir, '/'); + if (p) { + *p = '\0'; + } else { + pstrcpy(exe_dir, sizeof(exe_dir), "."); + } + + /* if 'quickjs.h' is present at the same path as the executable, we + use it as include and lib directory */ + snprintf(buf, sizeof(buf), "%s/quickjs.h", exe_dir); + if (access(buf, R_OK) == 0) { + pstrcpy(inc_dir, sizeof(inc_dir), exe_dir); + pstrcpy(lib_dir, sizeof(lib_dir), exe_dir); + } else { + snprintf(inc_dir, sizeof(inc_dir), "%s/include/quickjs", CONFIG_PREFIX); + snprintf(lib_dir, sizeof(lib_dir), "%s/lib/quickjs", CONFIG_PREFIX); + } + + lto_suffix = ""; + bn_suffix = ""; + + arg = argv; + *arg++ = CONFIG_CC; + *arg++ = "-O2"; +#ifdef CONFIG_LTO + if (use_lto) { + *arg++ = "-flto"; + lto_suffix = ".lto"; + } +#endif + /* XXX: use the executable path to find the includes files and + libraries */ + *arg++ = "-D"; + *arg++ = "_GNU_SOURCE"; + *arg++ = "-I"; + *arg++ = inc_dir; + *arg++ = "-o"; + *arg++ = out_filename; + if (dynamic_export) + *arg++ = "-rdynamic"; + *arg++ = cfilename; + snprintf(libjsname, sizeof(libjsname), "%s/libquickjs%s%s.a", + lib_dir, bn_suffix, lto_suffix); + *arg++ = libjsname; + *arg++ = "-lm"; + *arg++ = "-ldl"; + *arg++ = "-lpthread"; + *arg = NULL; + + if (verbose) { + for(arg = argv; *arg != NULL; arg++) + printf("%s ", *arg); + printf("\n"); + } + + ret = exec_cmd((char **)argv); + unlink(cfilename); + return ret; +} +#else +static int output_executable(const char *out_filename, const char *cfilename, + BOOL use_lto, BOOL verbose, const char *exename) +{ + fprintf(stderr, "Executable output is not supported for this target\n"); + exit(1); + return 0; +} +#endif + + +typedef enum { + OUTPUT_C, + OUTPUT_C_MAIN, + OUTPUT_EXECUTABLE, +} OutputTypeEnum; + +int main(int argc, char **argv) +{ + int c, i, verbose; + const char *out_filename, *cname; + char cfilename[1024]; + FILE *fo; + JSRuntime *rt; + JSContext *ctx; + BOOL use_lto; + int module; + OutputTypeEnum output_type; + size_t stack_size; +#ifdef CONFIG_BIGNUM + BOOL bignum_ext = FALSE; +#endif + namelist_t dynamic_module_list; + + out_filename = NULL; + output_type = OUTPUT_EXECUTABLE; + cname = NULL; + feature_bitmap = FE_ALL; + module = -1; + byte_swap = FALSE; + verbose = 0; + use_lto = FALSE; + stack_size = 0; + memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); + + /* add system modules */ + namelist_add(&cmodule_list, "std", "std", 0); + namelist_add(&cmodule_list, "os", "os", 0); + + for(;;) { + c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:"); + if (c == -1) + break; + switch(c) { + case 'h': + help(); + case 'o': + out_filename = optarg; + break; + case 'c': + output_type = OUTPUT_C; + break; + case 'e': + output_type = OUTPUT_C_MAIN; + break; + case 'N': + cname = optarg; + break; + case 'f': + { + const char *p; + p = optarg; + if (!strcmp(optarg, "lto")) { + use_lto = TRUE; + } else if (strstart(p, "no-", &p)) { + use_lto = TRUE; + for(i = 0; i < countof(feature_list); i++) { + if (!strcmp(p, feature_list[i].option_name)) { + feature_bitmap &= ~((uint64_t)1 << i); + break; + } + } + if (i == countof(feature_list)) + goto bad_feature; + } else +#ifdef CONFIG_BIGNUM + if (!strcmp(optarg, "bignum")) { + bignum_ext = TRUE; + } else +#endif + { + bad_feature: + fprintf(stderr, "unsupported feature: %s\n", optarg); + exit(1); + } + } + break; + case 'm': + module = 1; + break; + case 'M': + { + char *p; + char path[1024]; + char cname[1024]; + pstrcpy(path, sizeof(path), optarg); + p = strchr(path, ','); + if (p) { + *p = '\0'; + pstrcpy(cname, sizeof(cname), p + 1); + } else { + get_c_name(cname, sizeof(cname), path); + } + namelist_add(&cmodule_list, path, cname, 0); + } + break; + case 'D': + namelist_add(&dynamic_module_list, optarg, NULL, 0); + break; + case 'x': + byte_swap = TRUE; + break; + case 'v': + verbose++; + break; + case 'p': + c_ident_prefix = optarg; + break; + case 'S': + stack_size = (size_t)strtod(optarg, NULL); + break; + default: + break; + } + } + + if (optind >= argc) + help(); + + if (!out_filename) { + if (output_type == OUTPUT_EXECUTABLE) { + out_filename = "a.out"; + } else { + out_filename = "out.c"; + } + } + + if (output_type == OUTPUT_EXECUTABLE) { +#if defined(_WIN32) || defined(__ANDROID__) + /* XXX: find a /tmp directory ? */ + snprintf(cfilename, sizeof(cfilename), "out%d.c", getpid()); +#else + snprintf(cfilename, sizeof(cfilename), "/tmp/out%d.c", getpid()); +#endif + } else { + pstrcpy(cfilename, sizeof(cfilename), out_filename); + } + + fo = fopen(cfilename, "w"); + if (!fo) { + perror(cfilename); + exit(1); + } + outfile = fo; + + rt = JS_NewRuntime(); + ctx = JS_NewContext(rt); +#ifdef CONFIG_BIGNUM + if (bignum_ext) { + JS_AddIntrinsicBigFloat(ctx); + JS_AddIntrinsicBigDecimal(ctx); + JS_AddIntrinsicOperators(ctx); + JS_EnableBignumExt(ctx, TRUE); + } +#endif + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL); + + fprintf(fo, "/* File generated automatically by the QuickJS compiler. */\n" + "\n" + ); + + if (output_type != OUTPUT_C) { + fprintf(fo, "#include \"quickjs-libc.h\"\n" + "\n" + ); + } else { + fprintf(fo, "#include \n" + "\n" + ); + } + + for(i = optind; i < argc; i++) { + const char *filename = argv[i]; + compile_file(ctx, fo, filename, cname, module); + cname = NULL; + } + + for(i = 0; i < dynamic_module_list.count; i++) { + if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) { + fprintf(stderr, "Could not load dynamic module '%s'\n", + dynamic_module_list.array[i].name); + exit(1); + } + } + + if (output_type != OUTPUT_C) { + fprintf(fo, + "static JSContext *JS_NewCustomContext(JSRuntime *rt)\n" + "{\n" + " JSContext *ctx = JS_NewContextRaw(rt);\n" + " if (!ctx)\n" + " return NULL;\n"); + /* add the basic objects */ + fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n"); + for(i = 0; i < countof(feature_list); i++) { + if ((feature_bitmap & ((uint64_t)1 << i)) && + feature_list[i].init_name) { + fprintf(fo, " JS_AddIntrinsic%s(ctx);\n", + feature_list[i].init_name); + } + } +#ifdef CONFIG_BIGNUM + if (bignum_ext) { + fprintf(fo, + " JS_AddIntrinsicBigFloat(ctx);\n" + " JS_AddIntrinsicBigDecimal(ctx);\n" + " JS_AddIntrinsicOperators(ctx);\n" + " JS_EnableBignumExt(ctx, 1);\n"); + } +#endif + /* add the precompiled modules (XXX: could modify the module + loader instead) */ + for(i = 0; i < init_module_list.count; i++) { + namelist_entry_t *e = &init_module_list.array[i]; + /* initialize the static C modules */ + + fprintf(fo, + " {\n" + " extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n" + " js_init_module_%s(ctx, \"%s\");\n" + " }\n", + e->short_name, e->short_name, e->name); + } + for(i = 0; i < cname_list.count; i++) { + namelist_entry_t *e = &cname_list.array[i]; + if (e->flags) { + fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n", + e->name, e->name); + } + } + fprintf(fo, + " return ctx;\n" + "}\n\n"); + + fputs(main_c_template1, fo); + + if (stack_size != 0) { + fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n", + (unsigned int)stack_size); + } + + /* add the module loader if necessary */ + if (feature_bitmap & (1 << FE_MODULE_LOADER)) { + fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n"); + } + + fprintf(fo, + " ctx = JS_NewCustomContext(rt);\n" + " js_std_add_helpers(ctx, argc, argv);\n"); + + for(i = 0; i < cname_list.count; i++) { + namelist_entry_t *e = &cname_list.array[i]; + if (!e->flags) { + fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n", + e->name, e->name); + } + } + fputs(main_c_template2, fo); + } + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + fclose(fo); + + if (output_type == OUTPUT_EXECUTABLE) { + return output_executable(out_filename, cfilename, use_lto, verbose, + argv[0]); + } + namelist_free(&cname_list); + namelist_free(&cmodule_list); + namelist_free(&init_module_list); + return 0; +} diff --git a/deps/quickjs/qjscalc.c b/deps/quickjs/qjscalc.c new file mode 100644 index 0000000..075da59 --- /dev/null +++ b/deps/quickjs/qjscalc.c @@ -0,0 +1,4005 @@ +/* File generated automatically by the QuickJS compiler. */ + +#include + +const uint32_t qjsc_qjscalc_size = 31967; + +const uint8_t qjsc_qjscalc[31967] = { + 0x02, 0xba, 0x02, 0x0e, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x0a, 0x46, 0x6c, 0x6f, 0x61, + 0x74, 0x10, 0x46, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x06, 0x4d, 0x6f, 0x64, 0x14, 0x50, + 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, + 0x6c, 0x0e, 0x50, 0x6f, 0x6c, 0x79, 0x4d, 0x6f, + 0x64, 0x20, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x0c, 0x53, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x0c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x02, 0x49, 0x02, 0x58, 0x02, 0x4f, 0x06, 0x67, + 0x63, 0x64, 0x08, 0x66, 0x61, 0x63, 0x74, 0x08, + 0x63, 0x6f, 0x6d, 0x62, 0x08, 0x70, 0x6d, 0x6f, + 0x64, 0x0c, 0x69, 0x6e, 0x76, 0x6d, 0x6f, 0x64, + 0x0c, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x0e, + 0x69, 0x73, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x12, + 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x69, 0x6d, + 0x65, 0x0a, 0x64, 0x65, 0x72, 0x69, 0x76, 0x0a, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x0a, 0x6e, 0x6f, + 0x72, 0x6d, 0x32, 0x06, 0x61, 0x62, 0x73, 0x08, + 0x63, 0x6f, 0x6e, 0x6a, 0x06, 0x61, 0x72, 0x67, + 0x0e, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x65, + 0x0a, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x0a, 0x66, + 0x6c, 0x6f, 0x6f, 0x72, 0x08, 0x63, 0x65, 0x69, + 0x6c, 0x08, 0x73, 0x71, 0x72, 0x74, 0x06, 0x65, + 0x78, 0x70, 0x06, 0x6c, 0x6f, 0x67, 0x08, 0x6c, + 0x6f, 0x67, 0x32, 0x0a, 0x6c, 0x6f, 0x67, 0x31, + 0x30, 0x08, 0x74, 0x6f, 0x64, 0x62, 0x0c, 0x66, + 0x72, 0x6f, 0x6d, 0x64, 0x62, 0x06, 0x73, 0x69, + 0x6e, 0x06, 0x63, 0x6f, 0x73, 0x06, 0x74, 0x61, + 0x6e, 0x08, 0x61, 0x73, 0x69, 0x6e, 0x08, 0x61, + 0x63, 0x6f, 0x73, 0x08, 0x61, 0x74, 0x61, 0x6e, + 0x0a, 0x61, 0x74, 0x61, 0x6e, 0x32, 0x08, 0x73, + 0x69, 0x6e, 0x63, 0x0a, 0x74, 0x6f, 0x64, 0x65, + 0x67, 0x0e, 0x66, 0x72, 0x6f, 0x6d, 0x64, 0x65, + 0x67, 0x08, 0x73, 0x69, 0x6e, 0x68, 0x08, 0x63, + 0x6f, 0x73, 0x68, 0x08, 0x74, 0x61, 0x6e, 0x68, + 0x0a, 0x61, 0x73, 0x69, 0x6e, 0x68, 0x0a, 0x61, + 0x63, 0x6f, 0x73, 0x68, 0x0a, 0x61, 0x74, 0x61, + 0x6e, 0x68, 0x0e, 0x73, 0x69, 0x67, 0x6d, 0x6f, + 0x69, 0x64, 0x08, 0x6c, 0x65, 0x72, 0x70, 0x06, + 0x69, 0x64, 0x6e, 0x08, 0x64, 0x69, 0x61, 0x67, + 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x0a, 0x74, + 0x72, 0x61, 0x63, 0x65, 0x10, 0x63, 0x68, 0x61, + 0x72, 0x70, 0x6f, 0x6c, 0x79, 0x12, 0x65, 0x69, + 0x67, 0x65, 0x6e, 0x76, 0x61, 0x6c, 0x73, 0x06, + 0x64, 0x65, 0x74, 0x08, 0x72, 0x61, 0x6e, 0x6b, + 0x06, 0x6b, 0x65, 0x72, 0x04, 0x63, 0x70, 0x04, + 0x64, 0x70, 0x10, 0x70, 0x6f, 0x6c, 0x72, 0x6f, + 0x6f, 0x74, 0x73, 0x10, 0x62, 0x65, 0x73, 0x74, + 0x61, 0x70, 0x70, 0x72, 0x14, 0x75, 0x73, 0x65, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x10, + 0x75, 0x73, 0x65, 0x20, 0x6d, 0x61, 0x74, 0x68, + 0x04, 0x50, 0x49, 0x0e, 0x69, 0x73, 0x50, 0x72, + 0x69, 0x6d, 0x65, 0x12, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x72, 0x69, 0x6d, 0x65, 0x0a, 0x72, 0x6f, + 0x6f, 0x74, 0x73, 0x14, 0x71, 0x6a, 0x73, 0x63, + 0x61, 0x6c, 0x63, 0x2e, 0x6a, 0x73, 0x12, 0x61, + 0x64, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x73, + 0x1a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x16, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x70, + 0x6f, 0x77, 0x18, 0x73, 0x6d, 0x61, 0x6c, 0x6c, + 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x73, 0x22, + 0x6d, 0x69, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x72, + 0x61, 0x62, 0x69, 0x6e, 0x5f, 0x74, 0x65, 0x73, + 0x74, 0x10, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x72, + 0x65, 0x63, 0x18, 0x66, 0x72, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x18, + 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x75, 0x62, 0x18, 0x66, 0x72, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x75, + 0x6c, 0x18, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x64, 0x69, 0x76, 0x18, 0x66, + 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x6f, 0x64, 0x16, 0x66, 0x72, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x71, 0x16, + 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6c, 0x74, 0x12, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x5f, 0x61, 0x64, 0x64, 0x12, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x73, 0x75, 0x62, 0x12, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x6d, 0x75, + 0x6c, 0x12, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, + 0x64, 0x69, 0x76, 0x12, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x12, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x70, 0x6f, 0x77, 0x10, + 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x65, 0x71, + 0x10, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x6c, + 0x74, 0x12, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x5f, + 0x74, 0x61, 0x62, 0x12, 0x67, 0x65, 0x74, 0x5f, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x16, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x61, 0x64, + 0x64, 0x16, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x78, 0x5f, 0x73, 0x75, 0x62, 0x16, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x6d, 0x75, + 0x6c, 0x16, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x78, 0x5f, 0x64, 0x69, 0x76, 0x14, 0x63, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x65, 0x71, + 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x61, 0x64, 0x64, + 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x73, 0x75, 0x62, + 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x6d, 0x75, 0x6c, + 0x0e, 0x6d, 0x6f, 0x64, 0x5f, 0x64, 0x69, 0x76, + 0x0c, 0x6d, 0x6f, 0x64, 0x5f, 0x65, 0x71, 0x28, + 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, + 0x61, 0x6c, 0x5f, 0x69, 0x73, 0x5f, 0x73, 0x63, + 0x61, 0x6c, 0x61, 0x72, 0x22, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x5f, 0x6e, 0x65, 0x65, 0x64, + 0x5f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x22, 0x6d, + 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, + 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x26, 0x70, 0x6f, 0x6c, 0x79, 0x5f, 0x72, 0x6f, + 0x6f, 0x74, 0x5f, 0x6c, 0x61, 0x67, 0x75, 0x65, + 0x72, 0x72, 0x65, 0x31, 0x14, 0x70, 0x6f, 0x6c, + 0x79, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x1c, + 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, + 0x61, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x1c, 0x70, + 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, + 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x1c, 0x70, 0x6f, + 0x6c, 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, + 0x5f, 0x6d, 0x75, 0x6c, 0x2a, 0x70, 0x6f, 0x6c, + 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, + 0x64, 0x69, 0x76, 0x5f, 0x73, 0x63, 0x61, 0x6c, + 0x61, 0x72, 0x1c, 0x70, 0x6f, 0x6c, 0x79, 0x6e, + 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x64, 0x69, + 0x76, 0x1c, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, + 0x6d, 0x69, 0x61, 0x6c, 0x5f, 0x6d, 0x6f, 0x64, + 0x1a, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, 0x6d, + 0x69, 0x61, 0x6c, 0x5f, 0x65, 0x71, 0x16, 0x70, + 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, 0x5f, 0x61, + 0x64, 0x64, 0x16, 0x70, 0x6f, 0x6c, 0x79, 0x6d, + 0x6f, 0x64, 0x5f, 0x73, 0x75, 0x62, 0x16, 0x70, + 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, 0x5f, 0x6d, + 0x75, 0x6c, 0x16, 0x70, 0x6f, 0x6c, 0x79, 0x6d, + 0x6f, 0x64, 0x5f, 0x64, 0x69, 0x76, 0x14, 0x70, + 0x6f, 0x6c, 0x79, 0x6d, 0x6f, 0x64, 0x5f, 0x65, + 0x71, 0x16, 0x72, 0x61, 0x74, 0x66, 0x75, 0x6e, + 0x63, 0x5f, 0x61, 0x64, 0x64, 0x16, 0x72, 0x61, + 0x74, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x73, 0x75, + 0x62, 0x16, 0x72, 0x61, 0x74, 0x66, 0x75, 0x6e, + 0x63, 0x5f, 0x6d, 0x75, 0x6c, 0x16, 0x72, 0x61, + 0x74, 0x66, 0x75, 0x6e, 0x63, 0x5f, 0x64, 0x69, + 0x76, 0x14, 0x72, 0x61, 0x74, 0x66, 0x75, 0x6e, + 0x63, 0x5f, 0x65, 0x71, 0x10, 0x67, 0x65, 0x74, + 0x5f, 0x65, 0x6d, 0x69, 0x6e, 0x3c, 0x73, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x5f, 0x69, 0x73, 0x5f, + 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x6f, + 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x79, 0x6e, 0x6f, + 0x6d, 0x69, 0x61, 0x6c, 0x14, 0x73, 0x65, 0x72, + 0x69, 0x65, 0x73, 0x5f, 0x61, 0x64, 0x64, 0x14, + 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x73, + 0x75, 0x62, 0x14, 0x73, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x14, 0x73, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x5f, 0x64, 0x69, 0x76, + 0x14, 0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x5f, + 0x70, 0x6f, 0x77, 0x12, 0x73, 0x65, 0x72, 0x69, + 0x65, 0x73, 0x5f, 0x65, 0x71, 0x12, 0x61, 0x72, + 0x72, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x12, + 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x73, 0x75, + 0x62, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, + 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x6d, + 0x75, 0x6c, 0x12, 0x61, 0x72, 0x72, 0x61, 0x79, + 0x5f, 0x6d, 0x75, 0x6c, 0x12, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x5f, 0x64, 0x69, 0x76, 0x34, 0x61, + 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x77, 0x69, 0x73, + 0x65, 0x5f, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x65, 0x10, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, + 0x65, 0x71, 0x1a, 0x61, 0x6c, 0x67, 0x65, 0x62, + 0x72, 0x61, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, + 0x2a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, + 0x69, 0x67, 0x49, 0x6e, 0x74, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x02, 0x2f, + 0x04, 0x2a, 0x2a, 0x12, 0x69, 0x73, 0x49, 0x6e, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x02, 0x2b, 0x02, + 0x2d, 0x02, 0x25, 0x04, 0x3d, 0x3d, 0x02, 0x3c, + 0x06, 0x70, 0x6f, 0x73, 0x06, 0x6e, 0x65, 0x67, + 0x08, 0x6c, 0x65, 0x66, 0x74, 0x0a, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x14, 0x74, 0x6f, 0x46, 0x72, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x16, 0x74, + 0x6f, 0x50, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x0e, 0x69, 0x73, 0x46, 0x6c, 0x6f, + 0x61, 0x74, 0x02, 0x45, 0x08, 0x4c, 0x4e, 0x31, + 0x30, 0x0a, 0x4c, 0x4f, 0x47, 0x32, 0x45, 0x0c, + 0x4c, 0x4f, 0x47, 0x31, 0x30, 0x45, 0x0e, 0x53, + 0x51, 0x52, 0x54, 0x31, 0x5f, 0x32, 0x0a, 0x53, + 0x51, 0x52, 0x54, 0x32, 0x12, 0x74, 0x6f, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x08, 0x74, + 0x72, 0x69, 0x6d, 0x06, 0x64, 0x65, 0x67, 0x0c, + 0x64, 0x69, 0x76, 0x72, 0x65, 0x6d, 0x24, 0x74, + 0x6f, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x08, 0x7a, 0x65, 0x72, 0x6f, 0x0e, 0x68, + 0x69, 0x6c, 0x62, 0x65, 0x72, 0x74, 0x18, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x73, 0x71, 0x75, + 0x61, 0x72, 0x65, 0x06, 0x64, 0x75, 0x70, 0x06, + 0x6f, 0x62, 0x6a, 0x0a, 0x70, 0x72, 0x6f, 0x70, + 0x73, 0x02, 0x69, 0x06, 0x76, 0x61, 0x6c, 0x08, + 0x70, 0x72, 0x6f, 0x70, 0x06, 0x74, 0x61, 0x62, + 0x08, 0x64, 0x65, 0x73, 0x63, 0x0e, 0x52, 0x65, + 0x66, 0x6c, 0x65, 0x63, 0x74, 0x0a, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x0e, 0x6f, 0x70, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x16, 0x6e, 0x65, 0x77, 0x5f, + 0x6f, 0x70, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x02, + 0x61, 0x02, 0x6a, 0x02, 0x62, 0x02, 0x6b, 0x0c, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x0e, 0x69, + 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x0c, 0x61, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x08, 0x70, 0x75, + 0x73, 0x68, 0x16, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x0c, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x08, 0x63, 0x61, + 0x6c, 0x6c, 0x02, 0x72, 0x0c, 0x69, 0x73, 0x5f, + 0x6e, 0x65, 0x67, 0x12, 0x66, 0x6c, 0x6f, 0x6f, + 0x72, 0x4c, 0x6f, 0x67, 0x32, 0x5e, 0x6e, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, + 0x6f, 0x77, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x02, 0x6e, 0x02, + 0x74, 0x02, 0x64, 0x02, 0x73, 0x1a, 0x69, 0x73, + 0x53, 0x61, 0x66, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x08, 0x74, 0x64, 0x69, 0x76, + 0x02, 0x78, 0x02, 0x79, 0x02, 0x71, 0x02, 0x75, + 0x02, 0x76, 0x02, 0x63, 0x0e, 0x66, 0x64, 0x69, + 0x76, 0x72, 0x65, 0x6d, 0x1c, 0x6e, 0x6f, 0x74, + 0x20, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x02, 0x6d, 0x04, 0x6e, 0x31, + 0x18, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x22, 0x6e, 0x6f, + 0x74, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x20, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x20, + 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x20, 0x64, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x20, 0x62, 0x79, 0x20, 0x7a, 0x65, 0x72, + 0x6f, 0x06, 0x6e, 0x75, 0x6d, 0x06, 0x64, 0x65, + 0x6e, 0x04, 0x61, 0x31, 0x04, 0x62, 0x31, 0x08, + 0x65, 0x64, 0x69, 0x76, 0x0a, 0x69, 0x73, 0x4e, + 0x61, 0x4e, 0x08, 0x68, 0x69, 0x6e, 0x74, 0x02, + 0x70, 0x08, 0x70, 0x72, 0x65, 0x63, 0x08, 0x6e, + 0x75, 0x6d, 0x31, 0x08, 0x6e, 0x75, 0x6d, 0x30, + 0x08, 0x64, 0x65, 0x6e, 0x31, 0x08, 0x64, 0x65, + 0x6e, 0x30, 0x30, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, + 0x74, 0x65, 0x64, 0x04, 0x72, 0x65, 0x04, 0x69, + 0x6d, 0x04, 0x2d, 0x49, 0x04, 0x2a, 0x49, 0x32, + 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x6f, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x3c, 0x3d, 0x20, + 0x30, 0x1a, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x06, + 0x72, 0x65, 0x73, 0x06, 0x6d, 0x6f, 0x64, 0x48, + 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x74, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x6f, + 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x69, 0x6e, + 0x61, 0x72, 0x79, 0x20, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x6f, 0x72, 0x20, 0x75, 0x6e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x79, 0x70, 0x65, 0x08, 0x4d, 0x6f, + 0x64, 0x28, 0x02, 0x2c, 0x02, 0x29, 0x08, 0x73, + 0x74, 0x72, 0x31, 0x02, 0x28, 0x02, 0x5e, 0x02, + 0x7a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x69, 0x74, + 0x04, 0x70, 0x31, 0x04, 0x70, 0x32, 0x04, 0x7a, + 0x30, 0x04, 0x7a, 0x31, 0x04, 0x7a, 0x32, 0x04, + 0x74, 0x30, 0x04, 0x74, 0x31, 0x04, 0x64, 0x31, + 0x04, 0x64, 0x32, 0x02, 0x65, 0x04, 0x65, 0x6c, + 0x04, 0x7a, 0x6c, 0x06, 0x65, 0x70, 0x73, 0x18, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x73, 0x26, 0x70, 0x6f, 0x6c, + 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x20, + 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x3e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x69, + 0x6e, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x66, + 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x61, + 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, + 0x06, 0x73, 0x74, 0x72, 0x10, 0x49, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x79, 0x06, 0x74, 0x6d, + 0x70, 0x04, 0x6e, 0x32, 0x48, 0x74, 0x68, 0x65, + 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x6f, 0x20, + 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x64, 0x65, + 0x67, 0x72, 0x65, 0x65, 0x20, 0x3c, 0x3d, 0x20, + 0x30, 0x10, 0x50, 0x6f, 0x6c, 0x79, 0x4d, 0x6f, + 0x64, 0x28, 0x04, 0x2f, 0x28, 0x08, 0x65, 0x6d, + 0x69, 0x6e, 0x06, 0x6d, 0x69, 0x6e, 0x04, 0x76, + 0x31, 0x04, 0x76, 0x32, 0x0e, 0x76, 0x32, 0x5f, + 0x65, 0x6d, 0x69, 0x6e, 0x04, 0x63, 0x31, 0x04, + 0x63, 0x32, 0x06, 0x73, 0x75, 0x6d, 0x04, 0x4f, + 0x28, 0x36, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, + 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, + 0x28, 0x31, 0x2f, 0x58, 0x29, 0x30, 0x6e, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x65, + 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, + 0x69, 0x6e, 0x20, 0x65, 0x78, 0x70, 0x5e, 0x6c, + 0x6f, 0x67, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, + 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, + 0x6e, 0x6f, 0x6e, 0x20, 0x7a, 0x65, 0x72, 0x6f, + 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x74, 0x20, 0x74, 0x65, 0x72, 0x6d, 0x0c, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x4f, 0x28, 0x69, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x4f, 0x28, + 0x29, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x02, 0x68, 0x02, 0x77, 0x04, 0x72, + 0x6c, 0x1e, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x20, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x1c, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, + 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x2c, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x20, + 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x08, + 0x63, 0x6f, 0x65, 0x66, 0x06, 0x73, 0x72, 0x63, + 0x06, 0x64, 0x73, 0x74, 0x30, 0x6d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x20, 0x69, 0x73, 0x20, 0x6e, + 0x6f, 0x74, 0x20, 0x69, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x02, 0x6c, 0x0e, + 0x69, 0x6d, 0x5f, 0x63, 0x6f, 0x6c, 0x73, 0x0e, + 0x6b, 0x65, 0x72, 0x5f, 0x64, 0x69, 0x6d, 0x32, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, + 0x69, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x72, + 0x61, 0x79, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x38, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x73, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x33, 0x20, 0x65, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x69, + 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, + 0x62, 0x6c, 0x65, 0x20, 0x61, 0x72, 0x72, 0x61, + 0x79, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x0a, 0x61, + 0x5f, 0x6d, 0x61, 0x74, 0x0a, 0x62, 0x5f, 0x6d, + 0x61, 0x74, 0x30, 0x69, 0x6e, 0x63, 0x6f, 0x6d, + 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x20, + 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x73, + 0x69, 0x7a, 0x65, 0x08, 0x66, 0x64, 0x69, 0x76, + 0x08, 0x63, 0x64, 0x69, 0x76, 0x0e, 0x00, 0x06, + 0x05, 0xa2, 0x01, 0x00, 0x02, 0x00, 0x06, 0x00, + 0x25, 0x97, 0x0b, 0x02, 0xa4, 0x01, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcc, 0x3f, + 0xe3, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe4, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xe5, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xe7, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xe8, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xe9, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xea, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xeb, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xec, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xed, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xee, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xef, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xf1, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xf3, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf4, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0xf5, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xf7, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, + 0x00, 0x00, 0x40, 0x3f, 0xf9, 0x00, 0x00, 0x00, + 0x40, 0x3f, 0xfa, 0x00, 0x00, 0x00, 0x40, 0x3f, + 0xfb, 0x00, 0x00, 0x00, 0x40, 0x3f, 0xfc, 0x00, + 0x00, 0x00, 0x40, 0x3f, 0xfd, 0x00, 0x00, 0x00, + 0x40, 0x3f, 0xfe, 0x00, 0x00, 0x00, 0x40, 0x3f, + 0xff, 0x00, 0x00, 0x00, 0x40, 0x3f, 0x00, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x01, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x02, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x03, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x04, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x05, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x06, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x07, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x08, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x09, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x0a, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x0b, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x0c, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x0d, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x0e, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x0f, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x10, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x11, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x12, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x13, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x14, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x15, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x16, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x17, 0x01, 0x00, 0x00, 0x40, 0x3f, 0x18, 0x01, + 0x00, 0x00, 0x40, 0x3f, 0x19, 0x01, 0x00, 0x00, + 0x40, 0x3f, 0x1a, 0x01, 0x00, 0x00, 0x40, 0x3f, + 0x1b, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x1c, 0x01, + 0x00, 0x00, 0x00, 0x3f, 0x1d, 0x01, 0x00, 0x00, + 0x00, 0x3f, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x3f, + 0x1f, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x01, + 0x00, 0x00, 0x00, 0x3f, 0x21, 0x01, 0x00, 0x00, + 0x00, 0x3f, 0x22, 0x01, 0x00, 0x00, 0x00, 0x3f, + 0x23, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x24, 0x01, + 0x00, 0x00, 0x00, 0x3f, 0x25, 0x01, 0x00, 0x00, + 0x00, 0x3f, 0x26, 0x01, 0x00, 0x00, 0x00, 0x3f, + 0x27, 0x01, 0x00, 0x00, 0x00, 0x3e, 0xe3, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xe4, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0xe6, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xe7, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xe8, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0xea, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xeb, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xec, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xed, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0xee, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xef, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0xf2, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf3, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xf4, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0xf6, 0x00, 0x00, 0x00, 0x00, 0x3e, 0xf7, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x02, 0x40, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x03, 0x40, 0xf9, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x04, 0x40, 0xfa, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x05, 0x40, 0xfb, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x06, 0x40, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x07, 0x40, 0xfd, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x08, 0x40, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x09, 0x40, 0xff, 0x00, + 0x00, 0x00, 0x00, 0xc2, 0x0a, 0x40, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x0b, 0x40, 0x01, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x0c, 0x40, 0x02, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x0d, 0x40, 0x03, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x0e, 0x40, 0x04, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x0f, 0x40, 0x05, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x10, 0x40, 0x06, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x11, 0x40, 0x07, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x12, 0x40, 0x08, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x13, 0x40, 0x09, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x14, 0x40, 0x0a, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x15, 0x40, 0x0b, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x16, 0x40, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x17, 0x40, 0x0d, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x18, 0x40, 0x0e, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x19, 0x40, 0x0f, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1a, 0x40, 0x10, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1b, 0x40, 0x11, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1c, 0x40, 0x12, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1d, 0x40, 0x13, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1e, 0x40, 0x14, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x1f, 0x40, 0x15, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x20, 0x40, 0x16, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x21, 0x40, 0x17, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x22, 0x40, 0x18, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x23, 0x40, 0x19, 0x01, + 0x00, 0x00, 0x00, 0xc2, 0x24, 0x40, 0x1a, 0x01, + 0x00, 0x00, 0x00, 0x3e, 0x1b, 0x01, 0x00, 0x00, + 0x00, 0x3e, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x3e, + 0x1d, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x1e, 0x01, + 0x00, 0x00, 0x00, 0x3e, 0x1f, 0x01, 0x00, 0x00, + 0x00, 0x3e, 0x20, 0x01, 0x00, 0x00, 0x00, 0x3e, + 0x21, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x22, 0x01, + 0x00, 0x00, 0x00, 0x3e, 0x23, 0x01, 0x00, 0x00, + 0x00, 0x3e, 0x24, 0x01, 0x00, 0x00, 0x00, 0x3e, + 0x25, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x26, 0x01, + 0x00, 0x00, 0x00, 0x3e, 0x27, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x28, 0x01, 0x00, 0x00, 0xcb, 0x04, + 0x29, 0x01, 0x00, 0x00, 0xcb, 0xc2, 0x00, 0xc8, + 0xf1, 0xcb, 0x36, 0xed, 0x00, 0x00, 0x00, 0x38, + 0xe6, 0x00, 0x00, 0x00, 0xb7, 0xb8, 0xf2, 0x3b, + 0xed, 0x00, 0x00, 0x00, 0x36, 0xee, 0x00, 0x00, + 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xb7, 0xb8, + 0x26, 0x02, 0x00, 0xf1, 0x3b, 0xee, 0x00, 0x00, + 0x00, 0x36, 0xef, 0x00, 0x00, 0x00, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x41, 0xef, 0x00, 0x00, 0x00, + 0x3b, 0xef, 0x00, 0x00, 0x00, 0x38, 0x97, 0x00, + 0x00, 0x00, 0x42, 0x66, 0x00, 0x00, 0x00, 0xc8, + 0x04, 0x2a, 0x01, 0x00, 0x00, 0x0b, 0xc2, 0x01, + 0x4d, 0x42, 0x00, 0x00, 0x00, 0x4c, 0x42, 0x00, + 0x00, 0x00, 0x24, 0x03, 0x00, 0xcb, 0x36, 0xf0, + 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x41, 0xf0, 0x00, 0x00, 0x00, 0x3b, 0xf0, 0x00, + 0x00, 0x00, 0x36, 0xf1, 0x00, 0x00, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x41, 0xf1, 0x00, 0x00, + 0x00, 0x3b, 0xf1, 0x00, 0x00, 0x00, 0x36, 0xf2, + 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x41, 0xf2, 0x00, 0x00, 0x00, 0x3b, 0xf2, 0x00, + 0x00, 0x00, 0x36, 0xf3, 0x00, 0x00, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x41, 0xf3, 0x00, 0x00, + 0x00, 0x3b, 0xf3, 0x00, 0x00, 0x00, 0x36, 0xf4, + 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x41, 0xf4, 0x00, 0x00, 0x00, 0x3b, 0xf4, 0x00, + 0x00, 0x00, 0x36, 0xf5, 0x00, 0x00, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x41, 0xf5, 0x00, 0x00, + 0x00, 0x3b, 0xf5, 0x00, 0x00, 0x00, 0x36, 0xf6, + 0x00, 0x00, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x41, 0x2b, 0x01, 0x00, 0x00, 0x3b, 0xf6, 0x00, + 0x00, 0x00, 0x36, 0xf7, 0x00, 0x00, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x41, 0x2c, 0x01, 0x00, + 0x00, 0x3b, 0xf7, 0x00, 0x00, 0x00, 0x36, 0x1b, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x1b, 0x01, 0x00, 0x00, 0x3b, 0x1b, 0x01, + 0x00, 0x00, 0x36, 0x1c, 0x01, 0x00, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x41, 0x1c, 0x01, 0x00, + 0x00, 0x3b, 0x1c, 0x01, 0x00, 0x00, 0x36, 0x1d, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x1d, 0x01, 0x00, 0x00, 0x3b, 0x1d, 0x01, + 0x00, 0x00, 0x36, 0x1e, 0x01, 0x00, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x41, 0x1e, 0x01, 0x00, + 0x00, 0x3b, 0x1e, 0x01, 0x00, 0x00, 0x36, 0x1f, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x1f, 0x01, 0x00, 0x00, 0x3b, 0x1f, 0x01, + 0x00, 0x00, 0x36, 0x20, 0x01, 0x00, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x41, 0x20, 0x01, 0x00, + 0x00, 0x3b, 0x20, 0x01, 0x00, 0x00, 0x36, 0x21, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x21, 0x01, 0x00, 0x00, 0x3b, 0x21, 0x01, + 0x00, 0x00, 0x36, 0x22, 0x01, 0x00, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x41, 0x22, 0x01, 0x00, + 0x00, 0x3b, 0x22, 0x01, 0x00, 0x00, 0x36, 0x23, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x23, 0x01, 0x00, 0x00, 0x3b, 0x23, 0x01, + 0x00, 0x00, 0x36, 0x24, 0x01, 0x00, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x41, 0x24, 0x01, 0x00, + 0x00, 0x3b, 0x24, 0x01, 0x00, 0x00, 0x36, 0x25, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x41, 0x25, 0x01, 0x00, 0x00, 0x3b, 0x25, 0x01, + 0x00, 0x00, 0x36, 0x26, 0x01, 0x00, 0x00, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0x41, 0x2d, 0x01, 0x00, + 0x00, 0x3b, 0x26, 0x01, 0x00, 0x00, 0x36, 0x27, + 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x41, 0x27, 0x01, 0x00, 0x00, 0x3b, 0x27, 0x01, + 0x00, 0x00, 0xc7, 0x28, 0xdc, 0x04, 0x01, 0x2c, + 0x00, 0xa0, 0x03, 0x01, 0x00, 0xe4, 0x03, 0x02, + 0x00, 0x05, 0x2e, 0x21, 0x00, 0x01, 0xea, 0x24, + 0x1e, 0x5d, 0x6c, 0x68, 0xaa, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x00, 0x14, 0xea, 0x03, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x68, 0x67, 0x0e, 0x43, 0x06, 0x05, + 0x00, 0x01, 0x46, 0x01, 0x20, 0x00, 0xcd, 0x01, + 0x8b, 0x1d, 0x47, 0xde, 0x01, 0x00, 0x01, 0x40, + 0xde, 0x04, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, + 0x01, 0x00, 0xe2, 0x04, 0x00, 0x02, 0x40, 0xe4, + 0x04, 0x00, 0x03, 0x40, 0xe6, 0x04, 0x00, 0x04, + 0x40, 0xe8, 0x04, 0x00, 0x05, 0x40, 0xea, 0x04, + 0x00, 0x06, 0x00, 0xec, 0x04, 0x00, 0x07, 0x00, + 0xee, 0x04, 0x00, 0x08, 0x00, 0xf0, 0x04, 0x00, + 0x09, 0x00, 0xf2, 0x04, 0x00, 0x0a, 0x00, 0xf4, + 0x04, 0x00, 0x0b, 0x00, 0xf6, 0x04, 0x00, 0x0c, + 0x00, 0xf8, 0x04, 0x00, 0x0d, 0x00, 0xfa, 0x04, + 0x00, 0x0e, 0x00, 0xfc, 0x04, 0x00, 0x0f, 0x00, + 0xfe, 0x04, 0x00, 0x10, 0x00, 0x80, 0x05, 0x00, + 0x11, 0x00, 0x82, 0x05, 0x00, 0x12, 0x00, 0x84, + 0x05, 0x00, 0x13, 0x00, 0x86, 0x05, 0x00, 0x14, + 0x00, 0x88, 0x05, 0x00, 0x15, 0x40, 0x8a, 0x05, + 0x00, 0x16, 0x40, 0x8c, 0x05, 0x00, 0x17, 0x00, + 0x8e, 0x05, 0x00, 0x18, 0x00, 0x90, 0x05, 0x00, + 0x19, 0x00, 0x92, 0x05, 0x00, 0x1a, 0x00, 0x94, + 0x05, 0x00, 0x1b, 0x00, 0x96, 0x05, 0x00, 0x1c, + 0x00, 0x98, 0x05, 0x00, 0x1d, 0x00, 0x9a, 0x05, + 0x00, 0x1e, 0x40, 0x9c, 0x05, 0x00, 0x1f, 0x00, + 0x9e, 0x05, 0x00, 0x20, 0x00, 0xa0, 0x05, 0x00, + 0x21, 0x40, 0xa2, 0x05, 0x00, 0x22, 0x40, 0xa4, + 0x05, 0x00, 0x23, 0x40, 0xa6, 0x05, 0x00, 0x24, + 0x40, 0xa8, 0x05, 0x00, 0x25, 0x40, 0xaa, 0x05, + 0x00, 0x26, 0x40, 0xac, 0x05, 0x00, 0x27, 0x00, + 0xae, 0x05, 0x00, 0x28, 0x00, 0xb0, 0x05, 0x00, + 0x29, 0x00, 0xb2, 0x05, 0x00, 0x2a, 0x00, 0xb4, + 0x05, 0x00, 0x2b, 0x00, 0xb6, 0x05, 0x00, 0x2c, + 0x00, 0xb8, 0x05, 0x00, 0x2d, 0x40, 0xba, 0x05, + 0x00, 0x2e, 0x00, 0xbc, 0x05, 0x00, 0x2f, 0x40, + 0xbe, 0x05, 0x00, 0x30, 0x00, 0xc0, 0x05, 0x00, + 0x31, 0x00, 0xc2, 0x05, 0x00, 0x32, 0x00, 0xc4, + 0x05, 0x00, 0x33, 0x00, 0xc6, 0x05, 0x00, 0x34, + 0x00, 0xc8, 0x05, 0x00, 0x35, 0x00, 0xca, 0x05, + 0x00, 0x36, 0x00, 0xcc, 0x05, 0x00, 0x37, 0x40, + 0xce, 0x05, 0x00, 0x38, 0x40, 0xd0, 0x05, 0x00, + 0x39, 0x40, 0xd2, 0x05, 0x00, 0x3a, 0x00, 0xd4, + 0x05, 0x00, 0x3b, 0x40, 0xd6, 0x05, 0x00, 0x3c, + 0x00, 0xd8, 0x05, 0x00, 0x3d, 0x00, 0xda, 0x05, + 0x00, 0x3e, 0x00, 0xdc, 0x05, 0x00, 0x3f, 0x00, + 0xde, 0x05, 0x00, 0x40, 0x00, 0xe0, 0x05, 0x00, + 0x41, 0x40, 0xe2, 0x05, 0x00, 0x42, 0x40, 0xe4, + 0x05, 0x00, 0x43, 0x00, 0xe6, 0x05, 0x00, 0x44, + 0x40, 0xe8, 0x05, 0x00, 0x45, 0x00, 0xc2, 0x00, + 0xcb, 0xc2, 0x01, 0xcc, 0xc2, 0x02, 0xcd, 0xc2, + 0x03, 0xc5, 0x04, 0xc2, 0x04, 0xc5, 0x05, 0xc2, + 0x18, 0xc5, 0x06, 0xc2, 0x19, 0xc5, 0x07, 0xc2, + 0x1a, 0xc5, 0x08, 0xc2, 0x1b, 0xc5, 0x09, 0xc2, + 0x1c, 0xc5, 0x0a, 0xc2, 0x1d, 0xc5, 0x0b, 0xc2, + 0x1e, 0xc5, 0x0c, 0xc2, 0x1f, 0xc5, 0x0d, 0xc2, + 0x20, 0xc5, 0x0e, 0xc2, 0x21, 0xc5, 0x0f, 0xc2, + 0x22, 0xc5, 0x10, 0xc2, 0x23, 0xc5, 0x11, 0xc2, + 0x24, 0xc5, 0x12, 0xc2, 0x25, 0xc5, 0x13, 0xc2, + 0x26, 0xc5, 0x14, 0xc2, 0x3a, 0xc5, 0x16, 0xc2, + 0x4b, 0xc5, 0x17, 0xc2, 0x4c, 0xc5, 0x18, 0xc2, + 0x4d, 0xc5, 0x19, 0xc2, 0x4e, 0xc5, 0x1a, 0xc2, + 0x4f, 0xc5, 0x1b, 0xc2, 0x5c, 0xc5, 0x1c, 0xc2, + 0x5d, 0xc5, 0x1d, 0xc2, 0x5e, 0xc5, 0x1e, 0xc2, + 0x5f, 0xc5, 0x1f, 0xc2, 0x60, 0xc5, 0x20, 0xc2, + 0x65, 0xc5, 0x21, 0xc2, 0x67, 0xc5, 0x22, 0xc2, + 0x68, 0xc5, 0x23, 0xc2, 0x69, 0xc5, 0x24, 0xc2, + 0x6a, 0xc5, 0x25, 0xc2, 0x74, 0xc5, 0x26, 0xc2, + 0x75, 0xc5, 0x27, 0xc2, 0x76, 0xc5, 0x28, 0xc2, + 0x77, 0xc5, 0x29, 0xc2, 0x78, 0xc5, 0x2a, 0xc2, + 0x79, 0xc5, 0x2b, 0xc2, 0x7a, 0xc5, 0x2c, 0xc2, + 0x82, 0xc5, 0x2d, 0xc2, 0x83, 0xc5, 0x2e, 0xc2, + 0x84, 0xc5, 0x2f, 0xc2, 0x85, 0xc5, 0x30, 0xc2, + 0x86, 0xc5, 0x31, 0xc2, 0x91, 0xc5, 0x32, 0xc2, + 0x92, 0xc5, 0x33, 0xc2, 0x93, 0xc5, 0x34, 0xc2, + 0x94, 0xc5, 0x35, 0xc2, 0x95, 0xc5, 0x36, 0xc2, + 0x99, 0xc5, 0x37, 0xc2, 0x9a, 0xc5, 0x38, 0xc2, + 0x9c, 0xc5, 0x39, 0xc2, 0x9d, 0xc5, 0x3a, 0xc2, + 0x9e, 0xc5, 0x3b, 0xc2, 0x9f, 0xc5, 0x3c, 0xc2, + 0xa0, 0xc5, 0x3d, 0xc2, 0xa1, 0xc5, 0x3e, 0xc2, + 0xbe, 0xc5, 0x3f, 0xc2, 0xbf, 0xc5, 0x40, 0xc2, + 0xc0, 0xc5, 0x41, 0xc2, 0xc1, 0xc5, 0x42, 0xc2, + 0xc2, 0xc5, 0x43, 0xc2, 0xc3, 0xc5, 0x44, 0xc2, + 0xc4, 0xc5, 0x45, 0xd3, 0xd3, 0x41, 0xb4, 0x00, + 0x00, 0x00, 0x43, 0xe3, 0x00, 0x00, 0x00, 0xd3, + 0xd3, 0x41, 0xb5, 0x00, 0x00, 0x00, 0x43, 0xe4, + 0x00, 0x00, 0x00, 0xd3, 0x0a, 0x43, 0x75, 0x01, + 0x00, 0x00, 0xb9, 0xba, 0xbc, 0xbe, 0xbf, 0x0b, + 0xbf, 0x0d, 0xbf, 0x11, 0xbf, 0x13, 0xbf, 0x17, + 0xbf, 0x1d, 0xbf, 0x1f, 0xbf, 0x25, 0xbf, 0x29, + 0xbf, 0x2b, 0xbf, 0x2f, 0xbf, 0x35, 0xbf, 0x3b, + 0xbf, 0x3d, 0xbf, 0x43, 0xbf, 0x47, 0xbf, 0x49, + 0xbf, 0x4f, 0xbf, 0x53, 0xbf, 0x59, 0xbf, 0x61, + 0xbf, 0x65, 0xbf, 0x67, 0xbf, 0x6b, 0xbf, 0x6d, + 0xbf, 0x71, 0xbf, 0x7f, 0xc0, 0x83, 0x00, 0x26, + 0x20, 0x00, 0xc0, 0x89, 0x00, 0x4c, 0x20, 0x00, + 0x00, 0x80, 0xc0, 0x8b, 0x00, 0x4c, 0x21, 0x00, + 0x00, 0x80, 0xc0, 0x95, 0x00, 0x4c, 0x22, 0x00, + 0x00, 0x80, 0xc0, 0x97, 0x00, 0x4c, 0x23, 0x00, + 0x00, 0x80, 0xc0, 0x9d, 0x00, 0x4c, 0x24, 0x00, + 0x00, 0x80, 0xc0, 0xa3, 0x00, 0x4c, 0x25, 0x00, + 0x00, 0x80, 0xc0, 0xa7, 0x00, 0x4c, 0x26, 0x00, + 0x00, 0x80, 0xc0, 0xad, 0x00, 0x4c, 0x27, 0x00, + 0x00, 0x80, 0xc0, 0xb3, 0x00, 0x4c, 0x28, 0x00, + 0x00, 0x80, 0xc0, 0xb5, 0x00, 0x4c, 0x29, 0x00, + 0x00, 0x80, 0xc0, 0xbf, 0x00, 0x4c, 0x2a, 0x00, + 0x00, 0x80, 0xc0, 0xc1, 0x00, 0x4c, 0x2b, 0x00, + 0x00, 0x80, 0xc0, 0xc5, 0x00, 0x4c, 0x2c, 0x00, + 0x00, 0x80, 0xc0, 0xc7, 0x00, 0x4c, 0x2d, 0x00, + 0x00, 0x80, 0xc0, 0xd3, 0x00, 0x4c, 0x2e, 0x00, + 0x00, 0x80, 0xc0, 0xdf, 0x00, 0x4c, 0x2f, 0x00, + 0x00, 0x80, 0xc0, 0xe3, 0x00, 0x4c, 0x30, 0x00, + 0x00, 0x80, 0xc0, 0xe5, 0x00, 0x4c, 0x31, 0x00, + 0x00, 0x80, 0xc0, 0xe9, 0x00, 0x4c, 0x32, 0x00, + 0x00, 0x80, 0xc0, 0xef, 0x00, 0x4c, 0x33, 0x00, + 0x00, 0x80, 0xc0, 0xf1, 0x00, 0x4c, 0x34, 0x00, + 0x00, 0x80, 0xc0, 0xfb, 0x00, 0x4c, 0x35, 0x00, + 0x00, 0x80, 0xc0, 0x01, 0x01, 0x4c, 0x36, 0x00, + 0x00, 0x80, 0xc0, 0x07, 0x01, 0x4c, 0x37, 0x00, + 0x00, 0x80, 0xc0, 0x0d, 0x01, 0x4c, 0x38, 0x00, + 0x00, 0x80, 0xc0, 0x0f, 0x01, 0x4c, 0x39, 0x00, + 0x00, 0x80, 0xc0, 0x15, 0x01, 0x4c, 0x3a, 0x00, + 0x00, 0x80, 0xc0, 0x19, 0x01, 0x4c, 0x3b, 0x00, + 0x00, 0x80, 0xc0, 0x1b, 0x01, 0x4c, 0x3c, 0x00, + 0x00, 0x80, 0xc0, 0x25, 0x01, 0x4c, 0x3d, 0x00, + 0x00, 0x80, 0xc0, 0x33, 0x01, 0x4c, 0x3e, 0x00, + 0x00, 0x80, 0xc0, 0x37, 0x01, 0x4c, 0x3f, 0x00, + 0x00, 0x80, 0xc0, 0x39, 0x01, 0x4c, 0x40, 0x00, + 0x00, 0x80, 0xc0, 0x3d, 0x01, 0x4c, 0x41, 0x00, + 0x00, 0x80, 0xc0, 0x4b, 0x01, 0x4c, 0x42, 0x00, + 0x00, 0x80, 0xc0, 0x51, 0x01, 0x4c, 0x43, 0x00, + 0x00, 0x80, 0xc0, 0x5b, 0x01, 0x4c, 0x44, 0x00, + 0x00, 0x80, 0xc0, 0x5d, 0x01, 0x4c, 0x45, 0x00, + 0x00, 0x80, 0xc0, 0x61, 0x01, 0x4c, 0x46, 0x00, + 0x00, 0x80, 0xc0, 0x67, 0x01, 0x4c, 0x47, 0x00, + 0x00, 0x80, 0xc0, 0x6f, 0x01, 0x4c, 0x48, 0x00, + 0x00, 0x80, 0xc0, 0x75, 0x01, 0x4c, 0x49, 0x00, + 0x00, 0x80, 0xc0, 0x7b, 0x01, 0x4c, 0x4a, 0x00, + 0x00, 0x80, 0xc0, 0x7f, 0x01, 0x4c, 0x4b, 0x00, + 0x00, 0x80, 0xc0, 0x85, 0x01, 0x4c, 0x4c, 0x00, + 0x00, 0x80, 0xc0, 0x8d, 0x01, 0x4c, 0x4d, 0x00, + 0x00, 0x80, 0xc0, 0x91, 0x01, 0x4c, 0x4e, 0x00, + 0x00, 0x80, 0xc0, 0x99, 0x01, 0x4c, 0x4f, 0x00, + 0x00, 0x80, 0xc0, 0xa3, 0x01, 0x4c, 0x50, 0x00, + 0x00, 0x80, 0xc0, 0xa5, 0x01, 0x4c, 0x51, 0x00, + 0x00, 0x80, 0xc0, 0xaf, 0x01, 0x4c, 0x52, 0x00, + 0x00, 0x80, 0xc0, 0xb1, 0x01, 0x4c, 0x53, 0x00, + 0x00, 0x80, 0xc0, 0xb7, 0x01, 0x4c, 0x54, 0x00, + 0x00, 0x80, 0xc0, 0xbb, 0x01, 0x4c, 0x55, 0x00, + 0x00, 0x80, 0xc0, 0xc1, 0x01, 0x4c, 0x56, 0x00, + 0x00, 0x80, 0xc0, 0xc9, 0x01, 0x4c, 0x57, 0x00, + 0x00, 0x80, 0xc0, 0xcd, 0x01, 0x4c, 0x58, 0x00, + 0x00, 0x80, 0xc0, 0xcf, 0x01, 0x4c, 0x59, 0x00, + 0x00, 0x80, 0xc0, 0xd3, 0x01, 0x4c, 0x5a, 0x00, + 0x00, 0x80, 0xc0, 0xdf, 0x01, 0x4c, 0x5b, 0x00, + 0x00, 0x80, 0xc0, 0xe7, 0x01, 0x4c, 0x5c, 0x00, + 0x00, 0x80, 0xc0, 0xeb, 0x01, 0x4c, 0x5d, 0x00, + 0x00, 0x80, 0xc0, 0xf3, 0x01, 0x4c, 0x5e, 0x00, + 0x00, 0x80, 0xce, 0x38, 0xb9, 0x00, 0x00, 0x00, + 0x42, 0x76, 0x01, 0x00, 0x00, 0x0b, 0xc2, 0x05, + 0x54, 0x77, 0x01, 0x00, 0x00, 0x04, 0xc2, 0x06, + 0x54, 0x78, 0x01, 0x00, 0x00, 0x04, 0x24, 0x01, + 0x00, 0x0e, 0xc7, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x0b, 0xc2, 0x07, 0x54, 0x79, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0x08, 0x54, 0xf0, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0x09, 0x54, 0xf1, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0x0a, 0x54, 0xf2, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0x0b, 0x54, 0xf4, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0x0c, 0x54, 0xf3, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0x0d, 0x54, 0x2b, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0x0e, 0x54, 0x2c, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0x0f, 0x54, 0xf5, 0x00, 0x00, 0x00, + 0x04, 0xf2, 0x0e, 0xc7, 0x38, 0xe3, 0x00, 0x00, + 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0xc2, + 0x10, 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x11, 0x54, 0xfa, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x12, 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x13, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x14, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x15, 0x54, 0x03, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0x16, 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, 0xf2, + 0x0e, 0x36, 0xe5, 0x00, 0x00, 0x00, 0xc2, 0x17, + 0x3b, 0xe5, 0x00, 0x00, 0x00, 0xc8, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, + 0x0b, 0xc4, 0x06, 0x4c, 0x7a, 0x01, 0x00, 0x00, + 0xc4, 0x07, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc4, + 0x08, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x09, + 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc4, 0x0a, 0x4c, + 0x7c, 0x01, 0x00, 0x00, 0xc9, 0x4c, 0x78, 0x01, + 0x00, 0x00, 0xc4, 0x0b, 0x4c, 0x7d, 0x01, 0x00, + 0x00, 0xc4, 0x0c, 0x4c, 0x7e, 0x01, 0x00, 0x00, + 0xc2, 0x27, 0x54, 0x7f, 0x01, 0x00, 0x00, 0x04, + 0xc2, 0x28, 0x54, 0x80, 0x01, 0x00, 0x00, 0x04, + 0x0b, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, 0x4c, 0x81, + 0x01, 0x00, 0x00, 0x38, 0x9a, 0x00, 0x00, 0x00, + 0x38, 0xb4, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00, + 0x4c, 0x82, 0x01, 0x00, 0x00, 0xc4, 0x06, 0x4c, + 0x7a, 0x01, 0x00, 0x00, 0xc4, 0x07, 0x4c, 0x7b, + 0x01, 0x00, 0x00, 0xc4, 0x08, 0x4c, 0x7e, 0x00, + 0x00, 0x00, 0xc4, 0x09, 0x4c, 0x77, 0x01, 0x00, + 0x00, 0xc4, 0x0a, 0x4c, 0x7c, 0x01, 0x00, 0x00, + 0xc9, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc4, 0x0b, + 0x4c, 0x7d, 0x01, 0x00, 0x00, 0xc4, 0x0c, 0x4c, + 0x7e, 0x01, 0x00, 0x00, 0x0b, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x4c, 0x81, 0x01, 0x00, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x4c, 0x82, 0x01, 0x00, + 0x00, 0xc4, 0x0d, 0x4c, 0x7a, 0x01, 0x00, 0x00, + 0xc4, 0x0e, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc4, + 0x0f, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x10, + 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc4, 0x11, 0x4c, + 0x7c, 0x01, 0x00, 0x00, 0xc4, 0x12, 0x4c, 0x78, + 0x01, 0x00, 0x00, 0xc4, 0x13, 0x4c, 0x7d, 0x01, + 0x00, 0x00, 0xc4, 0x14, 0x4c, 0x7e, 0x01, 0x00, + 0x00, 0x22, 0x04, 0x00, 0x0e, 0xc7, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x29, 0x54, 0x83, + 0x01, 0x00, 0x00, 0x04, 0xf2, 0x0e, 0xc7, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0x38, 0x9d, 0x00, 0x00, 0x00, 0x41, + 0x84, 0x01, 0x00, 0x00, 0xc2, 0x2a, 0x55, 0x04, + 0xc2, 0x2b, 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x2c, 0x54, 0x38, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x2d, 0x54, 0xfa, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x2e, 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x2f, 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x30, 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x31, 0x54, 0x03, 0x01, 0x00, 0x00, 0x04, + 0xc2, 0x32, 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, + 0xf2, 0x0e, 0xc7, 0x38, 0x9a, 0x00, 0x00, 0x00, + 0x41, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x33, + 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x34, + 0x54, 0xfa, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x35, + 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x36, + 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x37, + 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x38, + 0x54, 0x03, 0x01, 0x00, 0x00, 0x04, 0xc2, 0x39, + 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, 0xf2, 0x0e, + 0x26, 0x00, 0x00, 0xc5, 0x15, 0xc7, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x3b, 0x54, 0x85, + 0x01, 0x00, 0x00, 0x04, 0xc2, 0x3c, 0x54, 0x27, + 0x01, 0x00, 0x00, 0x04, 0xc2, 0x3d, 0x54, 0x86, + 0x01, 0x00, 0x00, 0x05, 0xc2, 0x3e, 0x54, 0x87, + 0x01, 0x00, 0x00, 0x05, 0xc2, 0x3f, 0x54, 0x88, + 0x01, 0x00, 0x00, 0x05, 0xc2, 0x40, 0x54, 0x89, + 0x01, 0x00, 0x00, 0x05, 0xc2, 0x41, 0x54, 0x8a, + 0x01, 0x00, 0x00, 0x05, 0xc2, 0x42, 0x54, 0x8b, + 0x01, 0x00, 0x00, 0x05, 0xf2, 0x0e, 0xc7, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc2, 0x43, 0x54, 0xfe, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x44, 0x54, 0xfa, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x45, 0x54, 0xfb, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x46, 0x54, 0xfc, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x47, 0x54, 0xfd, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x48, 0x54, 0x03, 0x01, 0x00, + 0x00, 0x04, 0xc2, 0x49, 0x54, 0x04, 0x01, 0x00, + 0x00, 0x04, 0xf2, 0x0e, 0x36, 0xe6, 0x00, 0x00, + 0x00, 0xc2, 0x4a, 0x3b, 0xe6, 0x00, 0x00, 0x00, + 0xc8, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x41, 0x3c, + 0x00, 0x00, 0x00, 0x0b, 0xc4, 0x17, 0x4c, 0x7a, + 0x01, 0x00, 0x00, 0xc4, 0x18, 0x4c, 0x7b, 0x01, + 0x00, 0x00, 0xc4, 0x19, 0x4c, 0x7e, 0x00, 0x00, + 0x00, 0xc4, 0x1a, 0x4c, 0x77, 0x01, 0x00, 0x00, + 0xc9, 0x4c, 0x78, 0x01, 0x00, 0x00, 0xc4, 0x1b, + 0x4c, 0x7d, 0x01, 0x00, 0x00, 0xc2, 0x50, 0x54, + 0x7f, 0x01, 0x00, 0x00, 0x04, 0xc2, 0x51, 0x54, + 0x80, 0x01, 0x00, 0x00, 0x04, 0x0b, 0x38, 0x9a, + 0x00, 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0x26, 0x04, 0x00, 0x4c, 0x81, 0x01, + 0x00, 0x00, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, + 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x26, 0x04, + 0x00, 0x4c, 0x82, 0x01, 0x00, 0x00, 0xc4, 0x17, + 0x4c, 0x7a, 0x01, 0x00, 0x00, 0xc4, 0x18, 0x4c, + 0x7b, 0x01, 0x00, 0x00, 0xc4, 0x19, 0x4c, 0x7e, + 0x00, 0x00, 0x00, 0xc4, 0x1a, 0x4c, 0x77, 0x01, + 0x00, 0x00, 0xc9, 0x4c, 0x78, 0x01, 0x00, 0x00, + 0xc4, 0x1b, 0x4c, 0x7d, 0x01, 0x00, 0x00, 0xf3, + 0x0e, 0xc7, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x0b, + 0xc2, 0x52, 0x54, 0x8c, 0x01, 0x00, 0x00, 0x04, + 0xf2, 0x0e, 0xc7, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0x41, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x53, + 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x54, + 0x54, 0x38, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x55, + 0x54, 0xfa, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x56, + 0x54, 0xfb, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x57, + 0x54, 0xfc, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x58, + 0x54, 0xfd, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x59, + 0x54, 0x03, 0x01, 0x00, 0x00, 0x04, 0xc2, 0x5a, + 0x54, 0x04, 0x01, 0x00, 0x00, 0x04, 0xf2, 0x0e, + 0x36, 0xe7, 0x00, 0x00, 0x00, 0xc2, 0x5b, 0x3b, + 0xe7, 0x00, 0x00, 0x00, 0xc8, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x0b, + 0xc4, 0x1c, 0x4c, 0x7a, 0x01, 0x00, 0x00, 0xc4, + 0x1d, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc4, 0x1e, + 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x1f, 0x4c, + 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, 0x78, 0x01, + 0x00, 0x00, 0xc4, 0x20, 0x4c, 0x7d, 0x01, 0x00, + 0x00, 0xc2, 0x61, 0x54, 0x7f, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0x62, 0x54, 0x80, 0x01, 0x00, 0x00, + 0x04, 0x0b, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, + 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x26, 0x04, + 0x00, 0x4c, 0x81, 0x01, 0x00, 0x00, 0x38, 0x9a, + 0x00, 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0x26, 0x04, 0x00, 0x4c, 0x82, 0x01, + 0x00, 0x00, 0xc4, 0x1c, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x1d, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x1e, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x1f, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xf3, 0x0e, 0xc7, 0x38, + 0xe7, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc2, 0x63, 0x54, 0xfe, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x64, 0x54, 0x38, 0x00, 0x00, + 0x00, 0x04, 0xf2, 0x0e, 0x36, 0xe8, 0x00, 0x00, + 0x00, 0xc2, 0x66, 0x3b, 0xe8, 0x00, 0x00, 0x00, + 0xc7, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x41, 0x3c, + 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x6b, 0x54, 0x8d, + 0x01, 0x00, 0x00, 0x04, 0xc2, 0x6c, 0x54, 0xfc, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x6d, 0x54, 0xfe, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x6e, 0x54, 0x38, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x6f, 0x54, 0x8e, + 0x01, 0x00, 0x00, 0x04, 0xc2, 0x70, 0x54, 0x5b, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x71, 0x54, 0xf8, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x72, 0x54, 0xf9, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x73, 0x54, 0xfa, + 0x00, 0x00, 0x00, 0x04, 0xf2, 0x0e, 0xc8, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc4, 0x26, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x27, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x28, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x2a, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc4, 0x2c, 0x4c, 0x7d, + 0x01, 0x00, 0x00, 0xc2, 0x7b, 0x54, 0x7f, 0x01, + 0x00, 0x00, 0x04, 0xc2, 0x7c, 0x54, 0x80, 0x01, + 0x00, 0x00, 0x04, 0x0b, 0x38, 0x9a, 0x00, 0x00, + 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0x38, 0xe6, 0x00, 0x00, 0x00, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0x26, 0x06, 0x00, 0x4c, 0x81, 0x01, + 0x00, 0x00, 0xc4, 0x26, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x27, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x28, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x2a, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0x0b, 0x38, 0x9a, 0x00, + 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, + 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x38, 0xe7, + 0x00, 0x00, 0x00, 0x26, 0x06, 0x00, 0x4c, 0x82, + 0x01, 0x00, 0x00, 0xc4, 0x26, 0x4c, 0x7a, 0x01, + 0x00, 0x00, 0xc4, 0x27, 0x4c, 0x7b, 0x01, 0x00, + 0x00, 0xc4, 0x28, 0x4c, 0x7e, 0x00, 0x00, 0x00, + 0xc4, 0x29, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, + 0x4c, 0x78, 0x01, 0x00, 0x00, 0x22, 0x04, 0x00, + 0x0e, 0xc7, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x0b, + 0xc2, 0x7d, 0x54, 0x8f, 0x01, 0x00, 0x00, 0x04, + 0xc2, 0x7e, 0x54, 0xf0, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x7f, 0x54, 0xf4, 0x00, 0x00, 0x00, 0x04, + 0xc2, 0x80, 0x54, 0x2d, 0x01, 0x00, 0x00, 0x04, + 0xf2, 0x0e, 0x36, 0xe9, 0x00, 0x00, 0x00, 0xc2, + 0x81, 0x3b, 0xe9, 0x00, 0x00, 0x00, 0xc8, 0x38, + 0xe9, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc4, 0x2d, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x2e, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x2f, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x30, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc4, 0x31, 0x4c, 0x7d, + 0x01, 0x00, 0x00, 0xc2, 0x87, 0x54, 0x7f, 0x01, + 0x00, 0x00, 0x04, 0xc2, 0x88, 0x54, 0x80, 0x01, + 0x00, 0x00, 0x04, 0x0b, 0x38, 0x9a, 0x00, 0x00, + 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0x38, 0xe6, 0x00, 0x00, 0x00, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x26, + 0x07, 0x00, 0x4c, 0x81, 0x01, 0x00, 0x00, 0x38, + 0x9a, 0x00, 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0x38, 0xe7, 0x00, 0x00, 0x00, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0x26, 0x07, 0x00, 0x4c, 0x82, 0x01, + 0x00, 0x00, 0xc4, 0x2d, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x2e, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x2f, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x30, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xf3, 0x0e, 0xc7, 0x38, + 0xe9, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc2, 0x89, 0x54, 0xfe, 0x00, 0x00, + 0x00, 0x04, 0xc2, 0x8a, 0x54, 0x38, 0x00, 0x00, + 0x00, 0x04, 0xf2, 0x0e, 0x36, 0xea, 0x00, 0x00, + 0x00, 0xc2, 0x8b, 0x3b, 0xea, 0x00, 0x00, 0x00, + 0xc7, 0x38, 0xea, 0x00, 0x00, 0x00, 0x41, 0x3c, + 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x8c, 0x54, 0xfe, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x8d, 0x54, 0xfc, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x8e, 0x54, 0x38, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x8f, 0x54, 0x5b, + 0x00, 0x00, 0x00, 0x04, 0xc2, 0x90, 0x54, 0xf8, + 0x00, 0x00, 0x00, 0x04, 0xf2, 0x0e, 0xc8, 0x38, + 0xea, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x0b, 0xc4, 0x32, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x33, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x34, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x35, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xc4, 0x36, 0x4c, 0x7d, + 0x01, 0x00, 0x00, 0xc2, 0x96, 0x54, 0x7f, 0x01, + 0x00, 0x00, 0x04, 0xc2, 0x97, 0x54, 0x80, 0x01, + 0x00, 0x00, 0x04, 0x0b, 0x38, 0x9a, 0x00, 0x00, + 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0x38, 0xe6, 0x00, 0x00, 0x00, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x26, + 0x07, 0x00, 0x4c, 0x81, 0x01, 0x00, 0x00, 0x38, + 0x9a, 0x00, 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0x38, 0xe7, 0x00, 0x00, 0x00, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0x26, 0x07, 0x00, 0x4c, 0x82, 0x01, + 0x00, 0x00, 0xc4, 0x32, 0x4c, 0x7a, 0x01, 0x00, + 0x00, 0xc4, 0x33, 0x4c, 0x7b, 0x01, 0x00, 0x00, + 0xc4, 0x34, 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, + 0x35, 0x4c, 0x77, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0x78, 0x01, 0x00, 0x00, 0xf3, 0x0e, 0xc7, 0x38, + 0xea, 0x00, 0x00, 0x00, 0x0b, 0xc2, 0x98, 0x54, + 0x90, 0x01, 0x00, 0x00, 0x04, 0xf2, 0x0e, 0x36, + 0xeb, 0x00, 0x00, 0x00, 0xc2, 0x9b, 0x3b, 0xeb, + 0x00, 0x00, 0x00, 0xc8, 0x38, 0xeb, 0x00, 0x00, + 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0xc4, + 0x39, 0x4c, 0x7a, 0x01, 0x00, 0x00, 0xc4, 0x3a, + 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc4, 0x3b, 0x4c, + 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x3c, 0x4c, 0x77, + 0x01, 0x00, 0x00, 0xc4, 0x3d, 0x4c, 0x78, 0x01, + 0x00, 0x00, 0xc4, 0x3e, 0x4c, 0x7d, 0x01, 0x00, + 0x00, 0xc2, 0xa2, 0x54, 0x7f, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0xa3, 0x54, 0x80, 0x01, 0x00, 0x00, + 0x04, 0x0b, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, + 0xb4, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x38, 0xe6, + 0x00, 0x00, 0x00, 0x38, 0xe7, 0x00, 0x00, 0x00, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0x26, 0x07, 0x00, + 0x4c, 0x81, 0x01, 0x00, 0x00, 0x38, 0x9a, 0x00, + 0x00, 0x00, 0x38, 0xb4, 0x00, 0x00, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, + 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x38, 0xe7, + 0x00, 0x00, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0x26, 0x07, 0x00, 0x4c, 0x82, 0x01, 0x00, 0x00, + 0xc4, 0x39, 0x4c, 0x7a, 0x01, 0x00, 0x00, 0xc4, + 0x3a, 0x4c, 0x7b, 0x01, 0x00, 0x00, 0xc4, 0x3b, + 0x4c, 0x7e, 0x00, 0x00, 0x00, 0xc4, 0x3c, 0x4c, + 0x77, 0x01, 0x00, 0x00, 0xc4, 0x3d, 0x4c, 0x78, + 0x01, 0x00, 0x00, 0xf3, 0x0e, 0xc7, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, + 0x0b, 0xc2, 0xa4, 0x54, 0xfc, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xa5, 0x54, 0xfe, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xa6, 0x54, 0x8d, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0xa7, 0x54, 0x38, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xa8, 0x54, 0x5b, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xa9, 0x54, 0xf8, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xaa, 0x54, 0xf9, 0x00, 0x00, 0x00, + 0x04, 0xc2, 0xab, 0x54, 0x03, 0x01, 0x00, 0x00, + 0x04, 0xc2, 0xac, 0x54, 0x04, 0x01, 0x00, 0x00, + 0x04, 0xf2, 0x0e, 0xc7, 0x38, 0xeb, 0x00, 0x00, + 0x00, 0x0b, 0xc2, 0xad, 0x54, 0x91, 0x01, 0x00, + 0x00, 0x04, 0xc2, 0xae, 0x54, 0xef, 0x00, 0x00, + 0x00, 0x04, 0xf2, 0x0e, 0x36, 0xec, 0x00, 0x00, + 0x00, 0xc2, 0xaf, 0x3b, 0xec, 0x00, 0x00, 0x00, + 0xc7, 0x38, 0xec, 0x00, 0x00, 0x00, 0x0b, 0xc2, + 0xb0, 0x54, 0x1b, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb1, 0x54, 0x1c, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb2, 0x54, 0x92, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb3, 0x54, 0x1d, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb4, 0x54, 0x93, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb5, 0x54, 0x1e, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb6, 0x54, 0x1f, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb7, 0x54, 0x20, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb8, 0x54, 0x21, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xb9, 0x54, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0xba, 0x54, 0x22, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xbb, 0x54, 0x23, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xbc, 0x54, 0x25, 0x01, 0x00, 0x00, 0x04, 0xc2, + 0xbd, 0x54, 0x24, 0x01, 0x00, 0x00, 0x04, 0xf2, + 0x0e, 0xc8, 0x38, 0x98, 0x00, 0x00, 0x00, 0x41, + 0x3c, 0x00, 0x00, 0x00, 0x0b, 0xc4, 0x3f, 0x4c, + 0x7a, 0x01, 0x00, 0x00, 0xc4, 0x40, 0x4c, 0x7b, + 0x01, 0x00, 0x00, 0xc4, 0x42, 0x4c, 0x7e, 0x00, + 0x00, 0x00, 0xc4, 0x43, 0x4c, 0x77, 0x01, 0x00, + 0x00, 0xc4, 0x45, 0x4c, 0x7d, 0x01, 0x00, 0x00, + 0xc2, 0xc5, 0x54, 0x7f, 0x01, 0x00, 0x00, 0x04, + 0xc2, 0xc6, 0x54, 0x80, 0x01, 0x00, 0x00, 0x04, + 0x0b, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x38, 0xe5, 0x00, 0x00, 0x00, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0x38, 0xe7, 0x00, 0x00, 0x00, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0x38, 0xe9, 0x00, 0x00, + 0x00, 0x38, 0xea, 0x00, 0x00, 0x00, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x26, 0x0a, 0x00, 0x4c, 0x82, + 0x01, 0x00, 0x00, 0xc4, 0x41, 0x4c, 0x7e, 0x00, + 0x00, 0x00, 0xc2, 0xc7, 0x54, 0x77, 0x01, 0x00, + 0x00, 0x04, 0xc9, 0x4c, 0x78, 0x01, 0x00, 0x00, + 0x0b, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x38, 0xb4, + 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x38, 0xe5, 0x00, 0x00, 0x00, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0x38, 0xe7, 0x00, 0x00, 0x00, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0x38, 0xe9, 0x00, 0x00, + 0x00, 0x38, 0xea, 0x00, 0x00, 0x00, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x26, 0x0a, 0x00, 0x4c, 0x81, + 0x01, 0x00, 0x00, 0xc2, 0xc8, 0x54, 0x7e, 0x00, + 0x00, 0x00, 0x04, 0xc2, 0xc9, 0x54, 0x77, 0x01, + 0x00, 0x00, 0x04, 0x22, 0x04, 0x00, 0x0e, 0xc7, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, + 0x00, 0x00, 0x0b, 0xc2, 0xca, 0x54, 0xfc, 0x00, + 0x00, 0x00, 0x04, 0xc2, 0xcb, 0x54, 0x94, 0x01, + 0x00, 0x00, 0x04, 0xc2, 0xcc, 0x54, 0xfe, 0x00, + 0x00, 0x00, 0x04, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0x41, 0x3c, 0x00, 0x00, 0x00, 0x41, 0xfa, 0x00, + 0x00, 0x00, 0x4c, 0xfa, 0x00, 0x00, 0x00, 0xf2, + 0x29, 0xdc, 0x04, 0x1d, 0xb7, 0x04, 0x00, 0x8d, + 0x02, 0x02, 0x3f, 0x3f, 0x00, 0x07, 0xba, 0x01, + 0x00, 0xb9, 0x04, 0x5a, 0x35, 0x00, 0x01, 0x0e, + 0x00, 0x08, 0x0e, 0x2b, 0x18, 0x00, 0x07, 0x0a, + 0x00, 0x08, 0x12, 0x2d, 0x00, 0x08, 0x14, 0x00, + 0x08, 0x2a, 0x00, 0x08, 0x2a, 0x00, 0x08, 0x34, + 0x00, 0x08, 0x16, 0x00, 0x08, 0x50, 0x2b, 0x0e, + 0x41, 0x2d, 0x00, 0x08, 0x0c, 0x2d, 0x00, 0x08, + 0x0c, 0x00, 0x08, 0x0c, 0x00, 0x08, 0x0c, 0x2b, + 0x00, 0x02, 0x08, 0x00, 0x05, 0x42, 0x00, 0x07, + 0x90, 0x01, 0x3a, 0x08, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x21, 0x26, 0x28, 0x2d, 0x2c, 0x08, 0x5d, + 0x5d, 0x26, 0x26, 0x26, 0x26, 0x26, 0x21, 0x26, + 0x27, 0x08, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x18, 0x00, 0x07, 0x10, + 0x2b, 0x0e, 0x3f, 0x00, 0x0a, 0x0c, 0x19, 0x2d, + 0x2d, 0x00, 0x08, 0x0c, 0x2d, 0x00, 0x08, 0x0c, + 0x2d, 0x2d, 0x2b, 0x00, 0x02, 0x08, 0x41, 0x2d, + 0x2d, 0x2d, 0x00, 0x08, 0x0c, 0x2d, 0x00, 0x08, + 0x0e, 0x2b, 0x00, 0x02, 0x08, 0x00, 0x05, 0x36, + 0x28, 0x00, 0x08, 0x2e, 0x2c, 0x2b, 0x2c, 0x2b, + 0x2c, 0x2b, 0x2b, 0x0e, 0x41, 0x2d, 0x2d, 0x2d, + 0x00, 0x08, 0x0c, 0x2d, 0x00, 0x08, 0x0e, 0x2b, + 0x00, 0x02, 0x08, 0x00, 0x05, 0x1c, 0x00, 0x07, + 0x3c, 0x3a, 0x08, 0x26, 0x26, 0x26, 0x26, 0x21, + 0x28, 0x2d, 0x2c, 0x08, 0x8f, 0x8f, 0x26, 0x26, + 0x26, 0x26, 0x21, 0x26, 0x0e, 0x00, 0x07, 0x0e, + 0x2b, 0x0e, 0x00, 0x0c, 0x08, 0x00, 0x08, 0x24, + 0x2d, 0x2d, 0x2d, 0x2d, 0x00, 0x08, 0x08, 0x2d, + 0x2b, 0x00, 0x02, 0x08, 0x00, 0x05, 0x2a, 0x00, + 0x07, 0x58, 0x3a, 0x08, 0x26, 0x26, 0x26, 0x26, + 0x21, 0x28, 0x2d, 0x2c, 0x08, 0x8f, 0x8f, 0x26, + 0x26, 0x26, 0x26, 0x21, 0x0e, 0x00, 0x0c, 0x10, + 0x2d, 0x2b, 0x00, 0x02, 0x22, 0x00, 0x05, 0x24, + 0x00, 0x07, 0xf0, 0x01, 0x00, 0x0c, 0x10, 0x00, + 0x08, 0x12, 0x2d, 0x00, 0x08, 0x28, 0x00, 0x08, + 0x0c, 0x00, 0x08, 0x14, 0x00, 0x08, 0x1a, 0x00, + 0x08, 0x12, 0x00, 0x08, 0x12, 0x2b, 0x00, 0x02, + 0x80, 0x01, 0x3a, 0x08, 0x26, 0x26, 0x26, 0x26, + 0x21, 0x28, 0x00, 0x08, 0x10, 0x2c, 0x08, 0xc1, + 0x26, 0x26, 0x26, 0x26, 0x22, 0x08, 0xc1, 0x26, + 0x26, 0x26, 0x26, 0x21, 0x18, 0x00, 0x07, 0x36, + 0x00, 0x08, 0x14, 0x00, 0x08, 0x28, 0x2d, 0x2b, + 0x00, 0x02, 0x08, 0x00, 0x05, 0x2a, 0x00, 0x07, + 0x48, 0x3a, 0x08, 0x26, 0x26, 0x26, 0x26, 0x21, + 0x28, 0x2d, 0x2c, 0x08, 0xda, 0xda, 0x26, 0x26, + 0x26, 0x26, 0x21, 0x0e, 0x00, 0x0c, 0x10, 0x2d, + 0x2b, 0x00, 0x02, 0x08, 0x00, 0x05, 0x2a, 0x27, + 0x41, 0x2d, 0x00, 0x08, 0x14, 0x2d, 0x00, 0x08, + 0x08, 0x2b, 0x00, 0x02, 0x3a, 0x3a, 0x08, 0x26, + 0x26, 0x26, 0x26, 0x21, 0x28, 0x2d, 0x2c, 0x08, + 0xda, 0xda, 0x26, 0x26, 0x26, 0x26, 0x21, 0x0e, + 0x00, 0x07, 0x1c, 0x2b, 0x00, 0x02, 0x2c, 0x00, + 0x05, 0x2e, 0x00, 0x07, 0xc0, 0x01, 0x3a, 0x08, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x28, 0x00, 0x08, + 0x12, 0x2c, 0x08, 0xda, 0xda, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x0e, 0x00, 0x0c, 0x12, 0x00, 0x08, + 0x20, 0x00, 0x08, 0x1e, 0x00, 0x08, 0x2c, 0x00, + 0x08, 0x1c, 0x00, 0x08, 0x20, 0x00, 0x08, 0x1c, + 0x00, 0x08, 0x22, 0x00, 0x08, 0x12, 0x2b, 0x0e, + 0x00, 0x07, 0x1a, 0x00, 0x08, 0x2a, 0x2b, 0x00, + 0x02, 0x08, 0x00, 0x05, 0x18, 0x27, 0x00, 0x07, + 0x0e, 0x00, 0x08, 0x10, 0x00, 0x08, 0x14, 0x00, + 0x08, 0x2c, 0x00, 0x08, 0x12, 0x00, 0x08, 0x12, + 0x00, 0x08, 0x22, 0x2d, 0x00, 0x08, 0x44, 0x00, + 0x08, 0x54, 0x00, 0x08, 0x52, 0x00, 0x08, 0x94, + 0x01, 0x00, 0x08, 0x18, 0x00, 0x08, 0x16, 0x2b, + 0x00, 0x02, 0xd2, 0x01, 0x3a, 0x08, 0x26, 0x26, + 0x26, 0x26, 0x28, 0x00, 0x08, 0x10, 0x2c, 0x08, + 0x99, 0x8f, 0x26, 0x2b, 0x22, 0x08, 0x99, 0x8f, + 0x2b, 0x2b, 0x18, 0x00, 0x0c, 0x10, 0x00, 0x08, + 0x18, 0x2d, 0x2b, 0x67, 0x09, 0x0e, 0x43, 0x06, + 0x05, 0xde, 0x04, 0x02, 0x05, 0x02, 0x05, 0x00, + 0x00, 0x77, 0x07, 0xaa, 0x06, 0x00, 0x01, 0x00, + 0xac, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, + 0x00, 0x00, 0xb0, 0x06, 0x00, 0x01, 0x00, 0xb2, + 0x06, 0x00, 0x02, 0x00, 0xb4, 0x06, 0x00, 0x03, + 0x00, 0xb6, 0x06, 0x00, 0x04, 0x00, 0x38, 0x9c, + 0x01, 0x00, 0x00, 0x42, 0x68, 0x00, 0x00, 0x00, + 0xd4, 0x24, 0x01, 0x00, 0xce, 0xb7, 0xcb, 0xc7, + 0xca, 0xeb, 0xa4, 0xec, 0x60, 0xca, 0xc7, 0x47, + 0xcd, 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0x67, + 0x00, 0x00, 0x00, 0xd4, 0xc9, 0x24, 0x02, 0x00, + 0xc6, 0x04, 0x09, 0x43, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x41, 0x00, 0x00, 0x00, 0xc4, 0x04, 0xa9, + 0xec, 0x1d, 0xc4, 0x04, 0x41, 0x41, 0x00, 0x00, + 0x00, 0xf7, 0xed, 0x11, 0xc4, 0x04, 0x09, 0x43, + 0x3f, 0x00, 0x00, 0x00, 0xc4, 0x04, 0x09, 0x43, + 0x3e, 0x00, 0x00, 0x00, 0xee, 0x09, 0xc4, 0x04, + 0x09, 0x43, 0x3e, 0x00, 0x00, 0x00, 0x38, 0x97, + 0x00, 0x00, 0x00, 0x42, 0x66, 0x00, 0x00, 0x00, + 0xd3, 0xc9, 0xc4, 0x04, 0x24, 0x03, 0x00, 0x0e, + 0x94, 0x00, 0xee, 0x9c, 0x29, 0xdc, 0x04, 0x23, + 0x0e, 0x04, 0x4e, 0x2b, 0x17, 0x58, 0x21, 0x35, + 0x35, 0x2b, 0x2c, 0x0e, 0x2c, 0x5d, 0x17, 0x0e, + 0x41, 0x06, 0x05, 0xe0, 0x04, 0x02, 0x09, 0x01, + 0x07, 0x00, 0x00, 0xfd, 0x01, 0x0b, 0xba, 0x06, + 0x00, 0x01, 0x00, 0xbc, 0x06, 0x00, 0x01, 0x00, + 0xbe, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x02, 0x00, 0xc2, + 0x06, 0x00, 0x03, 0x00, 0xc4, 0x06, 0x00, 0x04, + 0x00, 0xc6, 0x06, 0x00, 0x05, 0x00, 0xaa, 0x06, + 0x00, 0x06, 0x00, 0xb4, 0x06, 0x00, 0x07, 0x00, + 0xc8, 0x06, 0x00, 0x08, 0x00, 0x0d, 0x01, 0x00, + 0xd8, 0x04, 0x81, 0x01, 0x00, 0x00, 0x04, 0x82, + 0x01, 0x00, 0x00, 0x26, 0x02, 0x00, 0xc5, 0x08, + 0x26, 0x00, 0x00, 0xcb, 0xb7, 0xcc, 0xc8, 0xd4, + 0xeb, 0xa4, 0x6a, 0xb6, 0x00, 0x00, 0x00, 0xd4, + 0xc8, 0x47, 0xd1, 0x41, 0x81, 0x01, 0x00, 0x00, + 0x11, 0xed, 0x08, 0x0e, 0xc9, 0x41, 0x82, 0x01, + 0x00, 0x00, 0x6a, 0x8e, 0x00, 0x00, 0x00, 0xc9, + 0x41, 0x81, 0x01, 0x00, 0x00, 0xc9, 0x41, 0x82, + 0x01, 0x00, 0x00, 0x26, 0x02, 0x00, 0xc5, 0x07, + 0xc9, 0x04, 0x81, 0x01, 0x00, 0x00, 0x99, 0x0e, + 0xc9, 0x04, 0x82, 0x01, 0x00, 0x00, 0x99, 0x0e, + 0xb7, 0xc5, 0x05, 0xc4, 0x05, 0xb9, 0xa4, 0xec, + 0x6c, 0xc4, 0x07, 0xc4, 0x05, 0x47, 0xc6, 0x06, + 0xec, 0x54, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xc4, 0x06, 0x24, 0x01, + 0x00, 0x97, 0xec, 0x08, 0xc4, 0x06, 0x26, 0x01, + 0x00, 0xc5, 0x06, 0xb7, 0xce, 0xca, 0xc4, 0x06, + 0xeb, 0xa4, 0xec, 0x32, 0x0b, 0xc5, 0x04, 0x38, + 0x97, 0x00, 0x00, 0x00, 0x42, 0xa6, 0x01, 0x00, + 0x00, 0xc4, 0x04, 0xc9, 0x24, 0x02, 0x00, 0x0e, + 0xc4, 0x04, 0xc4, 0x08, 0xc4, 0x05, 0x47, 0x73, + 0xc4, 0x06, 0xca, 0x47, 0x49, 0xc7, 0x42, 0xa7, + 0x01, 0x00, 0x00, 0xc4, 0x04, 0x24, 0x01, 0x00, + 0x0e, 0x94, 0x03, 0xee, 0xc9, 0x94, 0x05, 0xee, + 0x9b, 0xc7, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xc9, + 0x24, 0x01, 0x00, 0x0e, 0x94, 0x01, 0xef, 0x47, + 0xff, 0xd3, 0x38, 0x9d, 0x00, 0x00, 0x00, 0x41, + 0xa8, 0x01, 0x00, 0x00, 0x73, 0x38, 0xb9, 0x00, + 0x00, 0x00, 0x41, 0xa9, 0x01, 0x00, 0x00, 0x42, + 0xaa, 0x01, 0x00, 0x00, 0x07, 0x26, 0x01, 0x00, + 0xb8, 0xc7, 0x52, 0x0e, 0x18, 0x27, 0x00, 0x00, + 0x49, 0x29, 0xdc, 0x04, 0x3a, 0x19, 0x19, 0x4e, + 0x17, 0x3a, 0x17, 0x67, 0x58, 0x2b, 0x2b, 0x30, + 0x26, 0x0d, 0x5d, 0x27, 0x30, 0x12, 0x58, 0x44, + 0x3f, 0x18, 0x18, 0x3b, 0x1c, 0x3f, 0x8f, 0x0e, + 0x43, 0x06, 0x05, 0xe2, 0x04, 0x02, 0x03, 0x02, + 0x04, 0x00, 0x00, 0xbc, 0x01, 0x05, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xd6, 0x06, 0x00, 0x00, 0x00, 0xd8, 0x06, 0x00, + 0x01, 0x00, 0xae, 0x06, 0x00, 0x02, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, + 0x00, 0xd4, 0x24, 0x01, 0x00, 0x97, 0xec, 0x12, + 0x38, 0x03, 0x01, 0x00, 0x00, 0x38, 0x04, 0x01, + 0x00, 0x00, 0xd3, 0xf1, 0xd4, 0x9b, 0x23, 0x01, + 0x00, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, 0xa5, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xec, + 0x2d, 0xd3, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xa8, + 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x38, 0xeb, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x18, 0x38, 0x1b, + 0x01, 0x00, 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, + 0x42, 0x93, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0xf1, 0xcb, 0xee, 0x03, 0xb8, 0xcb, 0xd4, + 0xb7, 0xaa, 0xec, 0x03, 0xc7, 0x28, 0x09, 0xcc, + 0xd4, 0xb7, 0xa4, 0xec, 0x06, 0x0a, 0xcc, 0xd4, + 0x8d, 0xd8, 0xd3, 0xcb, 0x38, 0xe3, 0x00, 0x00, + 0x00, 0x42, 0xad, 0x01, 0x00, 0x00, 0xd4, 0x24, + 0x01, 0x00, 0xb8, 0x9f, 0xcd, 0xc9, 0xb7, 0xa7, + 0xec, 0x14, 0xc7, 0xc7, 0x9b, 0xcb, 0xd4, 0xc9, + 0xa2, 0xb8, 0xae, 0xec, 0x05, 0xc7, 0xd3, 0x9b, + 0xcb, 0x93, 0x02, 0xee, 0xe9, 0xc8, 0xec, 0x1a, + 0xc7, 0x41, 0xfe, 0x00, 0x00, 0x00, 0xf7, 0xed, + 0x07, 0x04, 0xae, 0x01, 0x00, 0x00, 0x2f, 0xc7, + 0x42, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcb, 0xc7, 0x28, 0xdc, 0x04, 0x5d, 0x18, 0x04, + 0x58, 0x59, 0x8a, 0x35, 0x6c, 0x0d, 0x0e, 0x1c, + 0x0d, 0x0d, 0x1c, 0x0d, 0x13, 0x0d, 0x71, 0x17, + 0x26, 0x17, 0x17, 0x12, 0x30, 0x21, 0x36, 0x0e, + 0x43, 0x06, 0x05, 0xe6, 0x04, 0x02, 0x06, 0x02, + 0x05, 0x01, 0x00, 0x72, 0x08, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xe0, 0x06, 0x00, 0x01, 0x00, 0xe2, + 0x06, 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, + 0x00, 0xe4, 0x06, 0x00, 0x02, 0x00, 0xae, 0x06, + 0x00, 0x03, 0x00, 0xc2, 0x06, 0x00, 0x04, 0x00, + 0xc0, 0x06, 0x00, 0x05, 0x00, 0xe4, 0x04, 0x03, + 0x01, 0xd3, 0xb8, 0x9f, 0xcb, 0xb7, 0xcd, 0xc7, + 0xb8, 0xae, 0xb7, 0xaa, 0xec, 0x09, 0xc7, 0xb8, + 0xa2, 0xcb, 0x94, 0x02, 0xee, 0xf2, 0xdf, 0xeb, + 0xd4, 0xa4, 0xec, 0x04, 0xdf, 0xeb, 0xd8, 0xb7, + 0xc5, 0x04, 0xc4, 0x04, 0xd4, 0xa4, 0xec, 0x4a, + 0xdf, 0xc4, 0x04, 0x47, 0xc5, 0x05, 0x38, 0xe3, + 0x00, 0x00, 0x00, 0x42, 0xf3, 0x00, 0x00, 0x00, + 0xc4, 0x05, 0xc7, 0xd3, 0x24, 0x03, 0x00, 0xd0, + 0xb8, 0xaa, 0x11, 0xed, 0x07, 0x0e, 0xc8, 0xd3, + 0xb8, 0x9f, 0xaa, 0xed, 0x21, 0xb8, 0xce, 0xca, + 0xc9, 0xa4, 0xec, 0x18, 0xc8, 0xc8, 0x9b, 0xd3, + 0xb4, 0xd0, 0xb8, 0xaa, 0xec, 0x03, 0x09, 0x28, + 0xc8, 0xd3, 0xb8, 0x9f, 0xaa, 0xed, 0x07, 0x94, + 0x03, 0xee, 0xe5, 0x09, 0x28, 0x94, 0x04, 0xee, + 0xb2, 0x0a, 0x28, 0xdc, 0x04, 0x7f, 0x17, 0x04, + 0x17, 0x0d, 0x26, 0x17, 0x0d, 0x0d, 0x21, 0x12, + 0x30, 0x21, 0x5d, 0x3a, 0x0d, 0x26, 0x21, 0x17, + 0x0d, 0x1c, 0x0d, 0x17, 0x08, 0x1c, 0x0e, 0x43, + 0x06, 0x05, 0xe8, 0x04, 0x02, 0x02, 0x02, 0x04, + 0x01, 0x00, 0x2e, 0x04, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, + 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, 0x00, + 0xe8, 0x04, 0x05, 0x01, 0xd4, 0xd3, 0x9f, 0xbc, + 0xa5, 0xec, 0x16, 0xd3, 0xcc, 0xd3, 0xb8, 0x9e, + 0xcb, 0xc7, 0xd4, 0xa5, 0xec, 0x09, 0xc8, 0xc7, + 0x9b, 0xcc, 0x94, 0x00, 0xee, 0xf4, 0xc8, 0x28, + 0xd3, 0xd4, 0x9e, 0xb8, 0xa2, 0xcb, 0xdf, 0xd3, + 0xc7, 0xf2, 0xdf, 0xc7, 0xb8, 0x9e, 0xd4, 0xf2, + 0x9b, 0x28, 0xdc, 0x04, 0x9a, 0x01, 0x08, 0x04, + 0x26, 0x0d, 0x30, 0x2b, 0x08, 0x0a, 0x21, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x02, 0x00, 0x02, 0x04, + 0x00, 0x00, 0x26, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0x75, + 0x01, 0x00, 0x00, 0xec, 0x10, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0x42, 0x83, 0x01, 0x00, 0x00, 0xd3, + 0xd4, 0x25, 0x02, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0x9c, 0x28, 0xdc, 0x04, 0xac, 0x01, + 0x03, 0x03, 0x26, 0x4f, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x1d, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xe2, 0x04, 0x02, 0x01, 0x38, + 0x75, 0x01, 0x00, 0x00, 0xec, 0x07, 0xdf, 0xd3, + 0xd4, 0x23, 0x02, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0xa0, 0x28, 0xdc, 0x04, 0xb3, 0x01, + 0x03, 0x03, 0x26, 0x22, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x27, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0x98, + 0x04, 0x8d, 0x00, 0x00, 0x00, 0xac, 0x11, 0xed, + 0x1c, 0x0e, 0xd3, 0x98, 0x04, 0x47, 0x00, 0x00, + 0x00, 0xac, 0x11, 0xec, 0x10, 0x0e, 0x38, 0x9a, + 0x00, 0x00, 0x00, 0x42, 0xb3, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x28, 0xdc, 0x04, 0xbd, + 0x01, 0x02, 0x04, 0x3f, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x01, 0x02, 0x02, 0x00, 0x00, 0x11, + 0x03, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, + 0xd4, 0xb7, 0xab, 0xec, 0x0b, 0xd3, 0xd4, 0xb4, + 0xcb, 0xd4, 0xd7, 0xc7, 0xd8, 0xee, 0xf2, 0xd3, + 0x28, 0xdc, 0x04, 0xc2, 0x01, 0x06, 0x04, 0x1c, + 0x17, 0x0d, 0x0d, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x0c, + 0x01, 0xde, 0x06, 0x00, 0x01, 0x00, 0xe8, 0x04, + 0x05, 0x01, 0xd3, 0xb7, 0xa5, 0xec, 0x03, 0xb8, + 0x28, 0xdf, 0xb8, 0xd3, 0xf2, 0x28, 0xdc, 0x04, + 0xcb, 0x01, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x00, 0x02, 0x06, 0x01, 0x00, 0x39, + 0x02, 0xde, 0x06, 0x00, 0x01, 0x00, 0xc6, 0x06, + 0x00, 0x01, 0x00, 0xe8, 0x04, 0x05, 0x01, 0xd4, + 0xb7, 0xa4, 0x11, 0xed, 0x05, 0x0e, 0xd4, 0xd3, + 0xa6, 0xec, 0x03, 0xb7, 0x28, 0xd4, 0xd3, 0xd4, + 0x9f, 0xa6, 0xec, 0x05, 0xd3, 0xd4, 0x9f, 0xd8, + 0xd4, 0xb7, 0xaa, 0xec, 0x03, 0xb8, 0x28, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x42, 0xb4, 0x01, 0x00, + 0x00, 0xdf, 0xd3, 0xd4, 0x9f, 0xb8, 0x9e, 0xd3, + 0xf2, 0xdf, 0xb8, 0xd4, 0xf2, 0x25, 0x02, 0x00, + 0xdc, 0x04, 0xcf, 0x01, 0x07, 0x03, 0x3f, 0x0d, + 0x26, 0x17, 0x1c, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x06, 0x02, 0x04, 0x00, 0x00, 0x4f, + 0x08, 0xea, 0x06, 0x00, 0x01, 0x00, 0xec, 0x06, + 0x00, 0x01, 0x00, 0xee, 0x06, 0x00, 0x00, 0x00, + 0xf0, 0x06, 0x00, 0x01, 0x00, 0xf2, 0x06, 0x00, + 0x02, 0x00, 0xc0, 0x06, 0x00, 0x03, 0x00, 0xf4, + 0x06, 0x00, 0x04, 0x00, 0xe0, 0x06, 0x00, 0x05, + 0x00, 0xd3, 0xcc, 0xd4, 0xcd, 0xb8, 0xc5, 0x04, + 0xb7, 0xce, 0xc8, 0xb7, 0xab, 0xec, 0x2d, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x42, 0xbb, 0x01, 0x00, + 0x00, 0xc9, 0xc8, 0x24, 0x02, 0x00, 0xc6, 0x05, + 0xb7, 0x47, 0xcb, 0xc8, 0xcd, 0xc4, 0x05, 0xb8, + 0x47, 0xcc, 0xc4, 0x04, 0xc5, 0x05, 0xca, 0xc7, + 0xc4, 0x04, 0x9b, 0x9f, 0xc5, 0x04, 0xc4, 0x05, + 0xce, 0xee, 0xd0, 0xc9, 0xb8, 0xab, 0xec, 0x0d, + 0x38, 0xce, 0x00, 0x00, 0x00, 0x04, 0xbc, 0x01, + 0x00, 0x00, 0xf1, 0x2f, 0xca, 0xd4, 0xb4, 0x28, + 0xdc, 0x04, 0xd9, 0x01, 0x10, 0x04, 0x0d, 0x0d, + 0x12, 0x0d, 0x1c, 0x58, 0x12, 0x0d, 0x1c, 0x17, + 0x2b, 0x12, 0x0e, 0x1c, 0x3f, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x03, 0x01, 0x03, 0x04, 0x00, 0x00, + 0x3e, 0x04, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xfa, 0x06, 0x00, 0x01, + 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xd4, 0xb7, + 0xaa, 0xec, 0x03, 0xb8, 0x28, 0xd4, 0xb7, 0xa4, + 0xec, 0x14, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, + 0xf4, 0x00, 0x00, 0x00, 0xd3, 0xd5, 0x24, 0x02, + 0x00, 0xd7, 0xd4, 0x8d, 0xd8, 0xb8, 0xcb, 0xd4, + 0xb8, 0xae, 0xec, 0x07, 0xc7, 0xd3, 0x9b, 0xd5, + 0xb4, 0xcb, 0xd4, 0xb8, 0xa2, 0xdc, 0xb7, 0xaa, + 0xed, 0x09, 0xd3, 0xd3, 0x9b, 0xd5, 0xb4, 0xd7, + 0xee, 0xe6, 0xc7, 0x28, 0xdc, 0x04, 0xee, 0x01, + 0x0e, 0x04, 0x1c, 0x0d, 0x1c, 0x53, 0x13, 0x0e, + 0x1c, 0x22, 0x17, 0x0d, 0x0d, 0x21, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x02, 0x03, 0x02, 0x03, + 0x02, 0x00, 0x62, 0x05, 0xde, 0x06, 0x00, 0x01, + 0x00, 0xe0, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, + 0x00, 0x00, 0x00, 0xe2, 0x06, 0x00, 0x01, 0x00, + 0xfc, 0x06, 0x00, 0x02, 0x00, 0xe4, 0x04, 0x03, + 0x01, 0xe6, 0x04, 0x04, 0x01, 0x38, 0xe3, 0x00, + 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0x97, 0xec, 0x0d, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0xbf, 0x01, 0x00, 0x00, + 0xf1, 0x2f, 0xd3, 0xb8, 0xa5, 0xec, 0x03, 0x09, + 0x28, 0xdf, 0xeb, 0xcd, 0xb7, 0xcb, 0xc7, 0xc9, + 0xa4, 0xec, 0x1f, 0xdf, 0xc7, 0x47, 0xd0, 0xd3, + 0xaa, 0xec, 0x03, 0x0a, 0x28, 0xc8, 0xd3, 0xa6, + 0xec, 0x03, 0x09, 0x28, 0xd3, 0xc8, 0xb4, 0xb7, + 0xaa, 0xec, 0x03, 0x09, 0x28, 0x94, 0x00, 0xee, + 0xde, 0xd3, 0xc8, 0xc8, 0x9b, 0xa4, 0xec, 0x03, + 0x0a, 0x28, 0xd4, 0xf6, 0xec, 0x04, 0xbf, 0x40, + 0xd8, 0xe0, 0xd3, 0xd4, 0x23, 0x02, 0x00, 0xdc, + 0x04, 0x85, 0x02, 0x13, 0x04, 0x58, 0x3f, 0x1c, + 0x0d, 0x13, 0x26, 0x17, 0x17, 0x0d, 0x1c, 0x0d, + 0x26, 0x0d, 0x17, 0x26, 0x0d, 0x17, 0x12, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x39, 0x01, 0xde, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x97, + 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, + 0xbf, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0xb8, + 0xa4, 0xec, 0x03, 0xb8, 0xd7, 0xd3, 0x90, 0xd7, + 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x2b, 0x01, + 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xec, 0xee, + 0xd3, 0x28, 0xdc, 0x04, 0x9c, 0x02, 0x08, 0x03, + 0x58, 0x3f, 0x1c, 0x0e, 0x12, 0x53, 0x08, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x02, 0x01, 0x04, + 0x00, 0x00, 0xbb, 0x01, 0x03, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xe2, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xe3, 0x00, 0x00, + 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x97, 0xec, 0x0d, 0x38, 0xd1, 0x00, + 0x00, 0x00, 0x04, 0xbf, 0x01, 0x00, 0x00, 0xf1, + 0x2f, 0x26, 0x00, 0x00, 0xcb, 0x38, 0xfb, 0x00, + 0x00, 0x00, 0xd3, 0xf1, 0xb8, 0xa5, 0xec, 0x0e, + 0xc7, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x0e, 0xc7, 0x28, 0xd3, 0xb7, 0xa4, + 0xec, 0x0f, 0xc7, 0x42, 0xa7, 0x01, 0x00, 0x00, + 0xb6, 0x24, 0x01, 0x00, 0x0e, 0xd3, 0x8d, 0xd7, + 0xd3, 0xb9, 0xb4, 0xb7, 0xaa, 0xec, 0x12, 0xd3, + 0xb8, 0xa2, 0xd7, 0xc7, 0x42, 0xa7, 0x01, 0x00, + 0x00, 0xb9, 0x24, 0x01, 0x00, 0x0e, 0xee, 0xe9, + 0xba, 0xcc, 0xd3, 0xb8, 0xab, 0xec, 0x4f, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x42, 0x2b, 0x01, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0xec, 0x0e, 0xc7, + 0x42, 0xa7, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0x0e, 0xee, 0x32, 0xd3, 0xc8, 0xb4, 0xb7, + 0xaa, 0xed, 0x06, 0xb9, 0x95, 0x01, 0xee, 0xf5, + 0xc7, 0x42, 0xa7, 0x01, 0x00, 0x00, 0xc8, 0x24, + 0x01, 0x00, 0x0e, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x42, 0xb4, 0x01, 0x00, 0x00, 0xd3, 0xc8, 0x24, + 0x02, 0x00, 0xdb, 0xc8, 0xb4, 0xb7, 0xab, 0xed, + 0x03, 0xee, 0xde, 0xee, 0xae, 0xc7, 0x28, 0xdc, + 0x04, 0xa7, 0x02, 0x20, 0x04, 0x58, 0x3f, 0x17, + 0x3a, 0x3a, 0x08, 0x08, 0x1c, 0x3a, 0x14, 0x26, + 0x17, 0x3a, 0x0e, 0x0d, 0x1c, 0x53, 0x3a, 0x00, + 0x02, 0x08, 0x1c, 0x0d, 0x12, 0x0e, 0x3a, 0x53, + 0x17, 0x0d, 0x0d, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x06, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xb8, + 0xc7, 0x9c, 0x28, 0xdc, 0x04, 0xd2, 0x02, 0x01, + 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xcb, 0xc7, 0xc7, 0x9b, 0x28, + 0xdc, 0x04, 0xd5, 0x02, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x00, 0x0d, 0x02, 0xf2, 0x06, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcc, 0xc8, 0xcf, + 0xb7, 0xa4, 0xec, 0x04, 0xc7, 0x8d, 0xcb, 0xc7, + 0x28, 0xdc, 0x04, 0xd8, 0x02, 0x04, 0x0d, 0x08, + 0x1c, 0x12, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x28, 0xdc, + 0x04, 0xde, 0x02, 0x01, 0x0d, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, + 0x14, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, + 0xc7, 0xb7, 0xa7, 0xec, 0x03, 0xb7, 0x28, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x41, 0x2a, 0x01, 0x00, + 0x00, 0x28, 0xdc, 0x04, 0xe1, 0x02, 0x04, 0x0d, + 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x17, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0xb7, + 0xaa, 0xec, 0x03, 0xb8, 0x28, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x42, 0x03, 0x01, 0x00, 0x00, 0xc7, + 0x25, 0x01, 0x00, 0xdc, 0x04, 0xe7, 0x02, 0x04, + 0x0d, 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x18, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, + 0xb8, 0xaa, 0xec, 0x03, 0xb7, 0x28, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0xc7, 0xf1, 0x42, 0x04, 0x01, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xed, + 0x02, 0x04, 0x0d, 0x1c, 0x08, 0x08, 0x0e, 0x43, + 0x06, 0x05, 0xca, 0x03, 0x02, 0x05, 0x02, 0x04, + 0x00, 0x00, 0xd4, 0x01, 0x07, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xe2, + 0x06, 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, + 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, 0xe4, 0x01, + 0x00, 0x01, 0x00, 0xca, 0x03, 0x00, 0x01, 0x14, + 0x0c, 0x03, 0xce, 0x0c, 0x02, 0xc5, 0x04, 0xca, + 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, + 0xc0, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0xc4, + 0x04, 0xa8, 0xec, 0x03, 0xd3, 0x28, 0x38, 0xe3, + 0x00, 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x97, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0xc1, 0x01, 0x00, + 0x00, 0xf1, 0x2f, 0xd4, 0xf6, 0xec, 0x05, 0xb8, + 0xd8, 0xee, 0x6e, 0x38, 0xe3, 0x00, 0x00, 0x00, + 0x42, 0x79, 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, + 0x00, 0x97, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, + 0x00, 0x04, 0xc1, 0x01, 0x00, 0x00, 0xf1, 0x2f, + 0xd4, 0xb7, 0xaa, 0xec, 0x0d, 0x38, 0xce, 0x00, + 0x00, 0x00, 0x04, 0xc2, 0x01, 0x00, 0x00, 0xf1, + 0x2f, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0xf0, + 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x24, 0x02, 0x00, + 0xcf, 0xb8, 0xab, 0xec, 0x21, 0x38, 0xe3, 0x00, + 0x00, 0x00, 0x42, 0xb4, 0x01, 0x00, 0x00, 0xd3, + 0xc7, 0x24, 0x02, 0x00, 0xd7, 0x38, 0xe3, 0x00, + 0x00, 0x00, 0x42, 0xb4, 0x01, 0x00, 0x00, 0xd4, + 0xc7, 0x24, 0x02, 0x00, 0xd8, 0xd4, 0xb7, 0xa4, + 0xec, 0x07, 0xd3, 0x8d, 0xd7, 0xd4, 0x8d, 0xd8, + 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0xa9, 0x01, + 0x00, 0x00, 0xc4, 0x04, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xd1, 0xd3, 0x43, 0xc3, + 0x01, 0x00, 0x00, 0xc9, 0xd4, 0x43, 0xc4, 0x01, + 0x00, 0x00, 0xc9, 0x28, 0xdc, 0x04, 0xf7, 0x02, + 0x1c, 0x00, 0x07, 0x08, 0x12, 0x3f, 0x21, 0x0d, + 0x58, 0x3f, 0x17, 0x0d, 0x0d, 0x58, 0x3f, 0x1c, + 0x3f, 0x53, 0x17, 0x53, 0x00, 0x10, 0x08, 0x1c, + 0x12, 0x14, 0x6c, 0x21, 0x26, 0x0e, 0x43, 0x06, + 0x05, 0xea, 0x04, 0x02, 0x00, 0x02, 0x05, 0x00, + 0x00, 0x45, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0x42, 0x83, 0x01, 0x00, 0x00, 0xd3, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x9b, 0xd3, 0x41, 0xc4, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0x9b, 0x9e, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0x25, + 0x02, 0x00, 0xdc, 0x04, 0x9a, 0x03, 0x03, 0x03, + 0x2b, 0x2b, 0x0e, 0x43, 0x06, 0x05, 0xec, 0x04, + 0x02, 0x00, 0x02, 0x05, 0x00, 0x00, 0x45, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0xd7, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xd4, + 0xf1, 0xd8, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x42, + 0x83, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xc3, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0x9b, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0x9b, 0x9f, 0xd3, + 0x41, 0xc4, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x9b, 0x25, 0x02, 0x00, 0xdc, + 0x04, 0x9f, 0x03, 0x03, 0x03, 0x2b, 0x2b, 0x0e, + 0x43, 0x06, 0x05, 0xee, 0x04, 0x02, 0x00, 0x02, + 0x05, 0x00, 0x00, 0x37, 0x02, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0x42, 0x83, 0x01, 0x00, + 0x00, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0x9b, 0xd3, 0x41, + 0xc4, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc4, 0x01, + 0x00, 0x00, 0x9b, 0x25, 0x02, 0x00, 0xdc, 0x04, + 0xa4, 0x03, 0x03, 0x03, 0x2b, 0x2b, 0x0e, 0x43, + 0x06, 0x05, 0xf0, 0x04, 0x02, 0x00, 0x02, 0x05, + 0x00, 0x00, 0x37, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0x38, 0xe5, + 0x00, 0x00, 0x00, 0x42, 0x83, 0x01, 0x00, 0x00, + 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xc4, 0x01, 0x00, 0x00, 0x9b, 0xd3, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0x9b, 0x25, 0x02, 0x00, 0xdc, 0x04, 0xa9, + 0x03, 0x03, 0x03, 0x2b, 0x2b, 0x0e, 0x43, 0x06, + 0x05, 0xf2, 0x04, 0x02, 0x02, 0x02, 0x06, 0x00, + 0x00, 0x3c, 0x04, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0x8a, 0x07, 0x00, + 0x00, 0x00, 0x8c, 0x07, 0x00, 0x01, 0x00, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xcb, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xcc, 0xd3, + 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0xc7, 0x01, + 0x00, 0x00, 0xc7, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0xc8, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0xc7, + 0x41, 0xc4, 0x01, 0x00, 0x00, 0xc8, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0x9b, 0x24, 0x02, 0x00, 0xd4, + 0x9b, 0x9f, 0x28, 0xdc, 0x04, 0xae, 0x03, 0x03, + 0x03, 0x2b, 0x2b, 0x0e, 0x43, 0x06, 0x05, 0xf4, + 0x04, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x2f, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0xd7, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0xd8, 0xd3, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0xd4, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xaa, + 0x11, 0xec, 0x0f, 0x0e, 0xd3, 0x41, 0xc4, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xaa, 0x28, 0xdc, 0x04, 0xb3, 0x03, 0x03, 0x03, + 0x2b, 0x2c, 0x0e, 0x43, 0x06, 0x05, 0xf6, 0x04, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x2c, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0xd7, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xd4, + 0xf1, 0xd8, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0xd4, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x9b, 0xa4, 0x28, 0xdc, 0x04, + 0xb9, 0x03, 0x03, 0x03, 0x2b, 0x2b, 0x0e, 0x43, + 0x06, 0x05, 0xf8, 0x04, 0x02, 0x00, 0x02, 0x03, + 0x00, 0x00, 0x10, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0xd4, 0xf1, 0x9e, 0x28, 0xdc, 0x04, + 0xc0, 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, + 0xfa, 0x04, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, + 0x10, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0x9f, 0x28, 0xdc, 0x04, 0xc3, 0x03, + 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, 0xfc, 0x04, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x10, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd4, 0xf1, + 0x9b, 0x28, 0xdc, 0x04, 0xc6, 0x03, 0x01, 0x03, + 0x0e, 0x43, 0x06, 0x05, 0xfe, 0x04, 0x02, 0x00, + 0x02, 0x03, 0x00, 0x00, 0x10, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0xd4, 0xf1, 0x9c, 0x28, + 0xdc, 0x04, 0xc9, 0x03, 0x01, 0x03, 0x0e, 0x43, + 0x06, 0x05, 0x80, 0x05, 0x02, 0x00, 0x02, 0x03, + 0x00, 0x00, 0x10, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0xd4, 0xf1, 0xb4, 0x28, 0xdc, 0x04, + 0xcc, 0x03, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, + 0x82, 0x05, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, + 0x10, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0xa0, 0x28, 0xdc, 0x04, 0xcf, 0x03, + 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, 0x84, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x10, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd4, 0xf1, + 0xac, 0x28, 0xdc, 0x04, 0xd2, 0x03, 0x01, 0x04, + 0x0e, 0x43, 0x06, 0x05, 0x86, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x00, 0x00, 0x3c, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xd8, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0xc8, 0x01, + 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x11, 0xed, + 0x10, 0x0e, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0xc8, 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, + 0xec, 0x07, 0x38, 0x46, 0x00, 0x00, 0x00, 0x28, + 0xd3, 0xd4, 0xa4, 0x28, 0xdc, 0x04, 0xd6, 0x03, + 0x06, 0x03, 0x2b, 0x2c, 0xad, 0x1c, 0x08, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x02, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0x28, 0xdc, 0x04, 0xea, 0x03, 0x01, + 0x03, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, + 0x01, 0x03, 0x00, 0x00, 0x15, 0x01, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, + 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0x8d, 0xd3, + 0x41, 0xc4, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xdc, 0x04, 0xed, 0x03, 0x01, 0x03, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x02, 0x01, 0x02, 0x03, 0x00, + 0x00, 0x23, 0x03, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x00, 0x00, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xd3, + 0xd4, 0xf2, 0xcb, 0x38, 0x75, 0x01, 0x00, 0x00, + 0xec, 0x12, 0xc7, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xb8, 0xaa, 0xec, 0x08, 0xc7, 0x41, 0xc3, 0x01, + 0x00, 0x00, 0x28, 0xc7, 0x28, 0xdc, 0x04, 0x8c, + 0x04, 0x05, 0x03, 0x30, 0x58, 0x21, 0x08, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x01, 0x01, 0x02, + 0x00, 0x00, 0x28, 0x02, 0x92, 0x07, 0x00, 0x01, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xd3, + 0x04, 0x49, 0x00, 0x00, 0x00, 0xac, 0xec, 0x0a, + 0xc7, 0x42, 0x38, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xc7, 0x41, + 0xc3, 0x01, 0x00, 0x00, 0xf1, 0xc7, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x9c, 0x28, 0xdc, 0x04, 0x96, + 0x04, 0x03, 0x0d, 0x30, 0x31, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, + 0x16, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, + 0x38, 0xe5, 0x00, 0x00, 0x00, 0xc7, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0xc7, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, 0x9d, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x16, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0x04, 0x77, 0x01, 0x00, 0x00, + 0x9e, 0xc7, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9e, + 0x28, 0xdc, 0x04, 0xa0, 0x04, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0xc7, 0xc7, 0x9b, 0x28, 0xdc, 0x04, + 0xa3, 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x11, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xb7, 0xa4, 0xec, + 0x04, 0xc7, 0x8d, 0x28, 0xc7, 0x28, 0xdc, 0x04, + 0xa6, 0x04, 0x04, 0x0d, 0x35, 0x0d, 0x08, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x04, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0xc7, 0x28, 0xdc, 0x04, 0xac, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x19, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0xb7, 0xa7, 0xec, 0x03, 0xb7, + 0x28, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x41, 0x2a, + 0x01, 0x00, 0x00, 0x28, 0xdc, 0x04, 0xaf, 0x04, + 0x04, 0x0d, 0x35, 0x08, 0x08, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, + 0x16, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x03, 0x01, + 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xc7, + 0xf1, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xb5, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x11, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0xc7, 0xf1, 0x42, 0x04, 0x01, 0x00, + 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xb8, 0x04, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x00, 0x06, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0xb8, 0xc7, 0x9c, + 0x28, 0xdc, 0x04, 0xc0, 0x04, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0xc7, 0xc7, 0x9b, 0x28, 0xdc, 0x04, + 0xc3, 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x10, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, + 0x9f, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x00, 0x00, + 0x00, 0xc7, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xc6, + 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x28, + 0xdc, 0x04, 0xc9, 0x04, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x14, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcb, 0xc7, 0xb7, 0xa7, 0xec, 0x03, 0xb7, 0x28, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x41, 0x2a, 0x01, + 0x00, 0x00, 0x28, 0xdc, 0x04, 0xcc, 0x04, 0x04, + 0x0d, 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x10, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x42, 0x03, 0x01, 0x00, + 0x00, 0xc7, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xd2, + 0x04, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x24, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0xb7, + 0xa4, 0xec, 0x10, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0xc7, 0xf1, 0x42, 0x04, 0x01, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x04, 0x01, 0x00, 0x00, 0xc7, 0x25, 0x01, 0x00, + 0xdc, 0x04, 0xd5, 0x04, 0x03, 0x0d, 0x1c, 0x4f, + 0x0e, 0x43, 0x06, 0x05, 0x8a, 0x05, 0x01, 0x03, + 0x01, 0x05, 0x01, 0x01, 0xcb, 0x01, 0x04, 0xde, + 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, 0x00, + 0x00, 0xf4, 0x06, 0x00, 0x01, 0x00, 0x94, 0x07, + 0x00, 0x02, 0x00, 0x88, 0x05, 0x15, 0x01, 0xdf, + 0xd3, 0x47, 0xcb, 0x38, 0xb6, 0x00, 0x00, 0x00, + 0x41, 0xcb, 0x01, 0x00, 0x00, 0xcd, 0xc7, 0xec, + 0x12, 0xc7, 0x41, 0xcb, 0x01, 0x00, 0x00, 0xc9, + 0xaa, 0xec, 0x08, 0xc7, 0x41, 0x98, 0x01, 0x00, + 0x00, 0x28, 0xd3, 0x11, 0xb7, 0xac, 0xec, 0x12, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x03, 0x01, + 0x00, 0x00, 0xb8, 0x24, 0x01, 0x00, 0xcc, 0xee, + 0x77, 0x11, 0xb8, 0xac, 0xec, 0x13, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x04, 0x01, 0x00, 0x00, + 0xbf, 0x0a, 0x24, 0x01, 0x00, 0xcc, 0xee, 0x60, + 0x11, 0xba, 0xac, 0xec, 0x14, 0xb8, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x04, 0x01, 0x00, 0x00, + 0xb9, 0x24, 0x01, 0x00, 0x9c, 0xcc, 0xee, 0x48, + 0x11, 0xbb, 0xac, 0xec, 0x15, 0xb8, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x04, 0x01, 0x00, 0x00, + 0xbf, 0x0a, 0x24, 0x01, 0x00, 0x9c, 0xcc, 0xee, + 0x2f, 0x11, 0xbd, 0xac, 0xec, 0x16, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x02, 0x01, 0x00, 0x00, + 0xc1, 0x00, 0xbf, 0xed, 0xb3, 0x24, 0x01, 0x00, + 0xcc, 0xee, 0x15, 0x11, 0xbe, 0xac, 0xec, 0x10, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x02, 0x01, + 0x00, 0x00, 0xb9, 0x24, 0x01, 0x00, 0xcc, 0x0e, + 0xc9, 0xc0, 0x00, 0x04, 0xa5, 0xec, 0x12, 0xdf, + 0xd3, 0x73, 0x0b, 0xc9, 0x4c, 0xcb, 0x01, 0x00, + 0x00, 0xc8, 0x4c, 0x98, 0x01, 0x00, 0x00, 0x49, + 0xc8, 0x28, 0xdc, 0x04, 0xe3, 0x04, 0x10, 0x04, + 0x17, 0x3a, 0x44, 0x21, 0x08, 0x08, 0x71, 0x77, + 0x7b, 0x81, 0x85, 0x67, 0x08, 0x26, 0x59, 0x0b, + 0x88, 0x02, 0x06, 0xe8, 0x89, 0x04, 0x23, 0xc7, + 0x8a, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x15, 0x01, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xd3, 0x98, 0x04, 0x47, 0x00, + 0x00, 0x00, 0xac, 0x11, 0xed, 0x0a, 0x0e, 0xd3, + 0x98, 0x04, 0x8e, 0x00, 0x00, 0x00, 0xac, 0x28, + 0xdc, 0x04, 0xfc, 0x04, 0x01, 0x03, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x02, 0x07, 0x02, 0x04, 0x00, + 0x01, 0x61, 0x09, 0xf0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0x98, 0x07, 0x00, + 0x00, 0x00, 0x9a, 0x07, 0x00, 0x01, 0x00, 0x9c, + 0x07, 0x00, 0x02, 0x00, 0x9e, 0x07, 0x00, 0x03, + 0x00, 0x86, 0x07, 0x00, 0x04, 0x00, 0x88, 0x07, + 0x00, 0x05, 0x00, 0xde, 0x06, 0x00, 0x06, 0x00, + 0xd4, 0xf6, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, + 0x00, 0x04, 0xd0, 0x01, 0x00, 0x00, 0xf1, 0x2f, + 0xb8, 0xcb, 0xb7, 0xcc, 0xb7, 0xcd, 0xb8, 0xce, + 0x38, 0xe3, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x42, 0x00, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0xf1, 0xc6, 0x06, 0xc7, 0x9b, + 0xc8, 0x9e, 0xc5, 0x04, 0xc4, 0x06, 0xc9, 0x9b, + 0xca, 0x9e, 0xc6, 0x05, 0xd4, 0xa6, 0xed, 0x18, + 0xc1, 0x00, 0xbf, 0xee, 0xb3, 0xd3, 0xc4, 0x06, + 0x9f, 0x9c, 0xd7, 0xc7, 0xcc, 0xc4, 0x04, 0xcb, + 0xc9, 0xce, 0xc4, 0x05, 0xcd, 0xee, 0xc2, 0x38, + 0xe5, 0x00, 0x00, 0x00, 0xc7, 0xc9, 0x23, 0x02, + 0x00, 0xdc, 0x04, 0xff, 0x04, 0x12, 0x05, 0x17, + 0x3f, 0x0d, 0x0d, 0x0d, 0x0e, 0x71, 0x21, 0x2b, + 0x0d, 0x0d, 0x3a, 0x0d, 0x12, 0x0d, 0x12, 0x0d, + 0x0b, 0xfc, 0x01, 0x06, 0x40, 0x76, 0x3a, 0x6b, + 0x0b, 0xde, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, 0x8a, + 0x05, 0x16, 0x01, 0xdf, 0xb7, 0x23, 0x01, 0x00, + 0xdc, 0x04, 0x97, 0x05, 0x00, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, + 0x05, 0x00, 0x8a, 0x05, 0x16, 0x01, 0xdf, 0xb8, + 0x23, 0x01, 0x00, 0xdc, 0x04, 0x98, 0x05, 0x00, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x05, 0x00, 0x8a, 0x05, 0x16, + 0x01, 0xdf, 0xba, 0x23, 0x01, 0x00, 0xdc, 0x04, + 0x9a, 0x05, 0x00, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, + 0x8a, 0x05, 0x16, 0x01, 0xdf, 0xbb, 0x23, 0x01, + 0x00, 0xdc, 0x04, 0x9b, 0x05, 0x00, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x05, 0x00, 0x8a, 0x05, 0x16, 0x01, 0xdf, + 0xbd, 0x23, 0x01, 0x00, 0xdc, 0x04, 0x9d, 0x05, + 0x00, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, 0x8a, 0x05, + 0x16, 0x01, 0xdf, 0xbe, 0x23, 0x01, 0x00, 0xdc, + 0x04, 0x9e, 0x05, 0x00, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x0a, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc1, + 0x00, 0xbf, 0xee, 0xb3, 0xc7, 0x9c, 0x28, 0xdc, + 0x04, 0xa2, 0x05, 0x01, 0x0d, 0x0b, 0xfc, 0x01, + 0x06, 0x40, 0x76, 0x3a, 0x6b, 0x0b, 0xde, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, + 0x00, 0x00, 0x06, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0xc7, 0xc7, 0x9b, 0x28, 0xdc, 0x04, + 0xa5, 0x05, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x10, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x00, 0x00, + 0x00, 0xc7, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xa8, + 0x05, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x28, + 0xdc, 0x04, 0xab, 0x05, 0x01, 0x0d, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x00, 0x14, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcb, 0xc7, 0xb7, 0xa7, 0xec, 0x03, 0xb7, 0x28, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x41, 0x2a, 0x01, + 0x00, 0x00, 0x28, 0xdc, 0x04, 0xae, 0x05, 0x04, + 0x0d, 0x1c, 0x08, 0x08, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x10, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x42, 0x03, 0x01, 0x00, + 0x00, 0xc7, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xb4, + 0x05, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x24, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0xb7, + 0xa4, 0xec, 0x10, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0xc7, 0xf1, 0x42, 0x04, 0x01, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x04, 0x01, 0x00, 0x00, 0xc7, 0x25, 0x01, 0x00, + 0xdc, 0x04, 0xb7, 0x05, 0x03, 0x0d, 0x1c, 0x4f, + 0x0e, 0x43, 0x06, 0x05, 0xcc, 0x03, 0x02, 0x03, + 0x02, 0x03, 0x00, 0x00, 0x45, 0x05, 0xa2, 0x07, + 0x00, 0x01, 0x00, 0xa4, 0x07, 0x00, 0x01, 0x00, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0xe4, 0x01, 0x00, + 0x01, 0x00, 0xcc, 0x03, 0x00, 0x01, 0x14, 0x0c, + 0x03, 0xcc, 0x0c, 0x02, 0xcd, 0xc8, 0xec, 0x0d, + 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x01, + 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0xc9, 0xa8, 0xec, + 0x03, 0xd3, 0x28, 0xd4, 0xf6, 0xec, 0x03, 0xb7, + 0xd8, 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0xa9, + 0x01, 0x00, 0x00, 0xc9, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xcf, 0xd3, 0x43, 0xd1, + 0x01, 0x00, 0x00, 0xc7, 0xd4, 0x43, 0xd2, 0x01, + 0x00, 0x00, 0xc7, 0x28, 0xdc, 0x04, 0xc2, 0x05, + 0x0a, 0x23, 0x12, 0x3f, 0x1c, 0x0d, 0x17, 0x0e, + 0x67, 0x21, 0x26, 0x0e, 0x43, 0x06, 0x05, 0x8c, + 0x05, 0x02, 0x00, 0x02, 0x05, 0x00, 0x00, 0x37, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0xd7, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0xd8, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0x42, 0x8c, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xd1, + 0x01, 0x00, 0x00, 0xd4, 0x41, 0xd1, 0x01, 0x00, + 0x00, 0x9e, 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xd2, 0x01, 0x00, 0x00, 0x9e, 0x25, + 0x02, 0x00, 0xdc, 0x04, 0xd3, 0x05, 0x03, 0x03, + 0x2b, 0x2b, 0x0e, 0x43, 0x06, 0x05, 0x8e, 0x05, + 0x02, 0x00, 0x02, 0x05, 0x00, 0x00, 0x37, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0xd7, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd4, + 0xf1, 0xd8, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x42, + 0x8c, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xd1, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xd1, 0x01, 0x00, 0x00, + 0x9f, 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd2, 0x01, 0x00, 0x00, 0x9f, 0x25, 0x02, + 0x00, 0xdc, 0x04, 0xd8, 0x05, 0x03, 0x03, 0x2b, + 0x2b, 0x0e, 0x43, 0x06, 0x05, 0x90, 0x05, 0x02, + 0x00, 0x02, 0x06, 0x00, 0x00, 0x53, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xd7, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd4, 0xf1, + 0xd8, 0x38, 0xe6, 0x00, 0x00, 0x00, 0x42, 0x8c, + 0x01, 0x00, 0x00, 0xd3, 0x41, 0xd1, 0x01, 0x00, + 0x00, 0xd4, 0x41, 0xd1, 0x01, 0x00, 0x00, 0x9b, + 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xd2, 0x01, 0x00, 0x00, 0x9b, 0x9f, 0xd3, 0x41, + 0xd1, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xd2, 0x01, + 0x00, 0x00, 0x9b, 0xd3, 0x41, 0xd2, 0x01, 0x00, + 0x00, 0xd4, 0x41, 0xd1, 0x01, 0x00, 0x00, 0x9b, + 0x9e, 0x25, 0x02, 0x00, 0xdc, 0x04, 0xdd, 0x05, + 0x04, 0x03, 0x2b, 0x2b, 0xbc, 0x0e, 0x43, 0x06, + 0x05, 0x92, 0x05, 0x02, 0x00, 0x02, 0x03, 0x00, + 0x00, 0x1c, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0xd3, 0xd4, 0x42, + 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9b, + 0x28, 0xdc, 0x04, 0xe3, 0x05, 0x03, 0x03, 0x2b, + 0x2b, 0x0e, 0x43, 0x06, 0x05, 0x94, 0x05, 0x02, + 0x00, 0x02, 0x02, 0x00, 0x00, 0x2f, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xd7, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xd4, 0xf1, + 0xd8, 0xd3, 0x41, 0xd1, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd1, 0x01, 0x00, 0x00, 0xaa, 0x11, 0xec, + 0x0f, 0x0e, 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xd2, 0x01, 0x00, 0x00, 0xaa, 0x28, + 0xdc, 0x04, 0xe8, 0x05, 0x03, 0x03, 0x2b, 0x2b, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x02, 0x01, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0x28, 0xdc, 0x04, 0xf6, 0x05, + 0x01, 0x03, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, + 0x00, 0x01, 0x03, 0x00, 0x00, 0x16, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xe6, 0x00, 0x00, + 0x00, 0xd3, 0x41, 0xd1, 0x01, 0x00, 0x00, 0x8d, + 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, 0x8d, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xf9, 0x05, 0x01, 0x03, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x18, 0x02, 0xa2, 0x07, 0x00, + 0x01, 0x00, 0xa4, 0x07, 0x00, 0x01, 0x00, 0x38, + 0x75, 0x01, 0x00, 0x00, 0xec, 0x08, 0xd4, 0xb7, + 0xaa, 0xec, 0x03, 0xd3, 0x28, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0xd3, 0xd4, 0x23, 0x02, 0x00, 0xdc, + 0x04, 0x8a, 0x06, 0x04, 0x03, 0x3f, 0x08, 0x08, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x00, 0x25, 0x02, 0xf4, 0x06, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcc, + 0xc8, 0x42, 0xfa, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xcb, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xc8, + 0x41, 0xd1, 0x01, 0x00, 0x00, 0xc7, 0x9c, 0xc8, + 0x41, 0xd2, 0x01, 0x00, 0x00, 0x8d, 0xc7, 0x9c, + 0x23, 0x02, 0x00, 0xdc, 0x04, 0x93, 0x06, 0x02, + 0x0d, 0x35, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x00, 0x00, 0x83, 0x01, 0x04, + 0xf2, 0x06, 0x00, 0x00, 0x00, 0xe4, 0x06, 0x00, + 0x01, 0x00, 0xc0, 0x06, 0x00, 0x02, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xce, 0xc3, 0xcc, 0xca, + 0xd1, 0x41, 0xd1, 0x01, 0x00, 0x00, 0xb7, 0xab, + 0xec, 0x12, 0xc8, 0xc9, 0x41, 0xd1, 0x01, 0x00, + 0x00, 0x42, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x9e, 0xcc, 0xc9, 0x41, 0xd2, 0x01, 0x00, + 0x00, 0xb8, 0xaa, 0xec, 0x16, 0xc8, 0xc3, 0xab, + 0xec, 0x08, 0x04, 0x7a, 0x01, 0x00, 0x00, 0x95, + 0x01, 0x04, 0xed, 0x00, 0x00, 0x00, 0x95, 0x01, + 0xee, 0x43, 0xc9, 0x41, 0xd2, 0x01, 0x00, 0x00, + 0xb6, 0xaa, 0xec, 0x0a, 0x04, 0xd3, 0x01, 0x00, + 0x00, 0x95, 0x01, 0xee, 0x30, 0xc9, 0x41, 0xd2, + 0x01, 0x00, 0x00, 0x42, 0x38, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xcf, 0xb7, 0x47, 0x04, 0x7b, + 0x01, 0x00, 0x00, 0xab, 0xec, 0x0d, 0xc8, 0xc3, + 0xab, 0xec, 0x08, 0x04, 0x7a, 0x01, 0x00, 0x00, + 0x95, 0x01, 0xc8, 0xc7, 0x04, 0xd4, 0x01, 0x00, + 0x00, 0x9e, 0x9e, 0xcc, 0xc8, 0x28, 0xdc, 0x04, + 0x97, 0x06, 0x0f, 0x0d, 0x12, 0x35, 0x58, 0x35, + 0x1c, 0x26, 0x26, 0x3f, 0x26, 0x0d, 0x4e, 0x4e, + 0x26, 0x36, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x1e, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x41, 0xd1, + 0x01, 0x00, 0x00, 0xc7, 0x41, 0xd1, 0x01, 0x00, + 0x00, 0x9b, 0xc7, 0x41, 0xd2, 0x01, 0x00, 0x00, + 0xc7, 0x41, 0xd2, 0x01, 0x00, 0x00, 0x9b, 0x9e, + 0x28, 0xdc, 0x04, 0xa9, 0x06, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x00, 0x00, 0x16, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x02, 0x01, 0x00, 0x00, 0x38, 0xfa, 0x00, 0x00, + 0x00, 0xc7, 0xf1, 0x25, 0x01, 0x00, 0xdc, 0x04, + 0xac, 0x06, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x17, + 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, + 0xe6, 0x00, 0x00, 0x00, 0xc7, 0x41, 0xd1, 0x01, + 0x00, 0x00, 0xc7, 0x41, 0xd2, 0x01, 0x00, 0x00, + 0x8d, 0x23, 0x02, 0x00, 0xdc, 0x04, 0xaf, 0x06, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x04, 0x00, 0x00, 0x1b, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x42, 0x0f, 0x01, 0x00, 0x00, 0xc7, + 0x41, 0xd2, 0x01, 0x00, 0x00, 0xc7, 0x41, 0xd1, + 0x01, 0x00, 0x00, 0x25, 0x02, 0x00, 0xdc, 0x04, + 0xb2, 0x06, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x32, + 0x03, 0xfa, 0x03, 0x00, 0x00, 0x00, 0xd6, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcd, 0xc9, 0x41, 0xd2, 0x01, 0x00, 0x00, 0xcb, + 0xc9, 0x41, 0xd1, 0x01, 0x00, 0x00, 0x42, 0x03, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcc, 0x38, + 0xe6, 0x00, 0x00, 0x00, 0xc8, 0x38, 0x0a, 0x01, + 0x00, 0x00, 0xc7, 0xf1, 0x9b, 0xc8, 0x38, 0x09, + 0x01, 0x00, 0x00, 0xc7, 0xf1, 0x9b, 0x23, 0x02, + 0x00, 0xdc, 0x04, 0xb5, 0x06, 0x02, 0x0d, 0x71, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x00, 0x2b, 0x01, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xcb, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0x38, 0xfb, 0x00, 0x00, 0x00, 0xc7, 0xf1, 0x42, + 0x04, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x38, + 0x0f, 0x01, 0x00, 0x00, 0xc7, 0x41, 0xd2, 0x01, + 0x00, 0x00, 0xc7, 0x41, 0xd1, 0x01, 0x00, 0x00, + 0xf2, 0x23, 0x02, 0x00, 0xdc, 0x04, 0xb9, 0x06, + 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x05, 0xce, 0x03, + 0x02, 0x04, 0x02, 0x03, 0x00, 0x00, 0xa2, 0x01, + 0x06, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xfa, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, + 0xe0, 0x06, 0x00, 0x01, 0x00, 0xe4, 0x01, 0x00, + 0x01, 0x00, 0xce, 0x03, 0x00, 0x01, 0x14, 0x0c, + 0x03, 0xcd, 0x0c, 0x02, 0xce, 0xc9, 0xec, 0x0d, + 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x01, + 0x00, 0x00, 0xf1, 0x2f, 0x38, 0x97, 0x00, 0x00, + 0x00, 0x42, 0xa9, 0x01, 0x00, 0x00, 0xca, 0x41, + 0x3c, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0xcb, + 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, 0x01, + 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0xec, 0x4e, + 0xd4, 0xb7, 0xa5, 0xec, 0x0d, 0x38, 0xce, 0x00, + 0x00, 0x00, 0x04, 0xd5, 0x01, 0x00, 0x00, 0xf1, + 0x2f, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xec, + 0x07, 0xd3, 0xd4, 0xb4, 0xd7, 0xee, 0x33, 0xd3, + 0x38, 0xe5, 0x00, 0x00, 0x00, 0xa8, 0xec, 0x12, + 0xca, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, + 0xf2, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9c, + 0x28, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xd6, + 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, 0xd1, 0x00, + 0x00, 0x00, 0x04, 0xd6, 0x01, 0x00, 0x00, 0xf1, + 0x2f, 0xc7, 0xd3, 0x43, 0xd7, 0x01, 0x00, 0x00, + 0xc7, 0xd4, 0x43, 0xd8, 0x01, 0x00, 0x00, 0xc7, + 0x28, 0xdc, 0x04, 0xc0, 0x06, 0x12, 0x22, 0x12, + 0x3f, 0x67, 0x53, 0x1c, 0x3f, 0x53, 0x17, 0x3a, + 0x53, 0x08, 0x3b, 0x08, 0x3a, 0x08, 0x26, 0x26, + 0x0e, 0x43, 0x06, 0x05, 0x96, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x00, 0x00, 0x76, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xa8, 0x97, + 0xec, 0x17, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xd3, + 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, 0x9e, 0xd4, + 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xd4, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xa8, 0x97, + 0xec, 0x17, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xd3, + 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, 0x9e, 0xd3, + 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xd8, 0x01, 0x00, 0x00, 0xab, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0xd9, 0x01, 0x00, + 0x00, 0xf1, 0x2f, 0x38, 0xe7, 0x00, 0x00, 0x00, + 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xd7, 0x01, 0x00, 0x00, 0x9e, 0xd3, 0x41, 0xd8, + 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0xd7, 0x06, 0x07, 0x03, 0x35, 0x71, 0x35, 0x72, + 0x4e, 0x3f, 0x0e, 0x43, 0x06, 0x05, 0x98, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x76, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0x38, 0xe7, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe7, 0x00, 0x00, + 0x00, 0xd3, 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, + 0x9f, 0xd4, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xd4, 0x38, 0xe7, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe7, 0x00, 0x00, + 0x00, 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, + 0x9f, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xd8, 0x01, 0x00, 0x00, 0xab, 0xec, + 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xd9, + 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, 0x9f, 0xd3, + 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xdc, 0x04, 0xe2, 0x06, 0x07, 0x03, 0x35, 0x71, + 0x35, 0x72, 0x4e, 0x3f, 0x0e, 0x43, 0x06, 0x05, + 0x9a, 0x05, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, + 0x76, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe7, + 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x41, 0xd7, 0x01, + 0x00, 0x00, 0x9b, 0xd4, 0x41, 0xd8, 0x01, 0x00, + 0x00, 0x23, 0x02, 0x00, 0xd4, 0x38, 0xe7, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe7, + 0x00, 0x00, 0x00, 0xd3, 0x41, 0xd7, 0x01, 0x00, + 0x00, 0xd4, 0x9b, 0xd3, 0x41, 0xd8, 0x01, 0x00, + 0x00, 0x23, 0x02, 0x00, 0xd3, 0x41, 0xd8, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xab, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, + 0x04, 0xd9, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, + 0xe7, 0x00, 0x00, 0x00, 0xd3, 0x41, 0xd7, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, + 0x9b, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xed, 0x06, 0x07, 0x03, + 0x35, 0x71, 0x35, 0x72, 0x4e, 0x3f, 0x0e, 0x43, + 0x06, 0x05, 0x9c, 0x05, 0x02, 0x00, 0x02, 0x04, + 0x01, 0x00, 0x26, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x9a, 0x05, + 0x1e, 0x01, 0xd4, 0x38, 0xe7, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x0f, 0x38, 0xe7, 0x00, 0x00, + 0x00, 0xd4, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xf2, 0xd8, 0xdf, 0xd3, 0xd4, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xdc, 0x04, 0xf8, 0x06, 0x03, 0x03, 0x35, 0x49, + 0x0e, 0x43, 0x06, 0x05, 0x9e, 0x05, 0x02, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x1f, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xd8, 0x01, 0x00, 0x00, 0xaa, 0x11, 0xec, 0x0f, + 0x0e, 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd7, 0x01, 0x00, 0x00, 0xaa, 0x28, 0xdc, + 0x04, 0xfd, 0x06, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x02, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, + 0x28, 0xdc, 0x04, 0x89, 0x07, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x15, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xd3, 0x41, + 0xd7, 0x01, 0x00, 0x00, 0x8d, 0xd3, 0x41, 0xd8, + 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0x8c, 0x07, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x43, + 0x03, 0xc0, 0x06, 0x00, 0x00, 0x00, 0xfa, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcd, 0xc9, 0xcf, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xcc, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, + 0x01, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, 0xec, + 0x1e, 0x38, 0xe7, 0x00, 0x00, 0x00, 0x38, 0xe3, + 0x00, 0x00, 0x00, 0x42, 0xf4, 0x00, 0x00, 0x00, + 0xc7, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xc8, 0x24, + 0x02, 0x00, 0xc8, 0x23, 0x02, 0x00, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0xda, 0x01, 0x00, 0x00, + 0xf1, 0x2f, 0xdc, 0x04, 0x9b, 0x07, 0x04, 0x0d, + 0x2b, 0x53, 0x95, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x22, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x04, 0xdb, + 0x01, 0x00, 0x00, 0xc7, 0x41, 0xd7, 0x01, 0x00, + 0x00, 0x9e, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x9e, + 0xc7, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x9e, 0x04, + 0xdd, 0x01, 0x00, 0x00, 0x9e, 0x28, 0xdc, 0x04, + 0xa3, 0x07, 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x05, + 0xa0, 0x05, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, + 0x47, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, + 0x98, 0x04, 0x47, 0x00, 0x00, 0x00, 0xac, 0x11, + 0xed, 0x16, 0x0e, 0xd3, 0x98, 0x04, 0x8d, 0x00, + 0x00, 0x00, 0xac, 0x11, 0xed, 0x0a, 0x0e, 0xd3, + 0x98, 0x04, 0x8e, 0x00, 0x00, 0x00, 0xac, 0xec, + 0x03, 0x0a, 0x28, 0xd3, 0x38, 0xe5, 0x00, 0x00, + 0x00, 0xa8, 0x11, 0xed, 0x14, 0x0e, 0xd3, 0x38, + 0xe6, 0x00, 0x00, 0x00, 0xa8, 0x11, 0xed, 0x09, + 0x0e, 0xd3, 0x38, 0xe7, 0x00, 0x00, 0x00, 0xa8, + 0xec, 0x03, 0x0a, 0x28, 0x09, 0x28, 0xdc, 0x04, + 0xaa, 0x07, 0x09, 0x04, 0x3f, 0x3f, 0x35, 0x0d, + 0x3a, 0x3a, 0x30, 0x0d, 0x0e, 0x43, 0x06, 0x05, + 0xd0, 0x03, 0x01, 0x02, 0x01, 0x04, 0x01, 0x00, + 0x82, 0x01, 0x03, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xe4, 0x01, 0x00, 0x01, 0x00, 0xd0, 0x03, 0x00, + 0x01, 0x14, 0xa0, 0x05, 0x21, 0x01, 0x0c, 0x03, + 0xcb, 0x0c, 0x02, 0xcc, 0xc7, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x01, 0x00, + 0x00, 0xf1, 0x2f, 0xd3, 0xc8, 0xa8, 0xec, 0x03, + 0xd3, 0x28, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xec, 0x2a, 0xd3, 0xeb, 0xb7, 0xaa, 0xec, 0x06, + 0xb7, 0x26, 0x01, 0x00, 0xd7, 0x38, 0x97, 0x00, + 0x00, 0x00, 0x42, 0x61, 0x00, 0x00, 0x00, 0xd3, + 0xc8, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x24, 0x02, + 0x00, 0x0e, 0xd3, 0x42, 0x8d, 0x01, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xdf, 0xd3, 0xf1, 0xec, 0x1d, + 0xd3, 0x26, 0x01, 0x00, 0xd7, 0x38, 0x97, 0x00, + 0x00, 0x00, 0x42, 0x61, 0x00, 0x00, 0x00, 0xd3, + 0xc8, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x24, 0x02, + 0x00, 0x0e, 0xd3, 0x28, 0x38, 0xd1, 0x00, 0x00, + 0x00, 0x04, 0xbf, 0x01, 0x00, 0x00, 0xf1, 0x2f, + 0xdc, 0x04, 0xb7, 0x07, 0x0f, 0x22, 0x12, 0x3f, + 0x1c, 0x08, 0x58, 0x21, 0x1c, 0x6c, 0x30, 0x1c, + 0x1c, 0x6c, 0x08, 0x08, 0x0e, 0x43, 0x06, 0x05, + 0xa2, 0x05, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, + 0x44, 0x01, 0xf4, 0x06, 0x00, 0x01, 0x00, 0x38, + 0xe3, 0x00, 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0x11, 0xed, 0x32, + 0x0e, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x85, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x11, + 0xed, 0x20, 0x0e, 0xd3, 0x38, 0xe5, 0x00, 0x00, + 0x00, 0xa8, 0x11, 0xed, 0x15, 0x0e, 0xd3, 0x38, + 0xe6, 0x00, 0x00, 0x00, 0xa8, 0x11, 0xec, 0x0a, + 0x0e, 0xd3, 0x41, 0xd1, 0x01, 0x00, 0x00, 0xb7, + 0xaa, 0x97, 0x28, 0xdc, 0x04, 0xcb, 0x07, 0x04, + 0x04, 0x5d, 0x5d, 0x3a, 0x0e, 0x43, 0x06, 0x05, + 0xa4, 0x05, 0x02, 0x01, 0x02, 0x03, 0x01, 0x00, + 0x63, 0x03, 0xf4, 0x06, 0x00, 0x01, 0x00, 0xae, + 0x06, 0x00, 0x01, 0x00, 0xbc, 0x07, 0x00, 0x00, + 0x00, 0xa2, 0x05, 0x22, 0x01, 0xd4, 0xb7, 0xaa, + 0xec, 0x0d, 0xd3, 0x42, 0x38, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xcb, 0xee, 0x51, 0xd3, 0xb8, + 0xaa, 0xec, 0x05, 0xc3, 0xcb, 0xee, 0x32, 0xd3, + 0xb6, 0xaa, 0xec, 0x09, 0x04, 0x7b, 0x01, 0x00, + 0x00, 0xcb, 0xee, 0x25, 0xdf, 0xd3, 0xf1, 0xec, + 0x11, 0x04, 0xdf, 0x01, 0x00, 0x00, 0xd3, 0x9e, + 0x04, 0xdd, 0x01, 0x00, 0x00, 0x9e, 0xcb, 0xee, + 0x09, 0x38, 0x9b, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xcb, 0x04, 0x7e, 0x00, 0x00, 0x00, 0x95, 0x00, + 0x04, 0xee, 0x00, 0x00, 0x00, 0x95, 0x00, 0xd4, + 0xb8, 0xab, 0xec, 0x0b, 0xc7, 0x04, 0xe0, 0x01, + 0x00, 0x00, 0xd4, 0x9e, 0x9e, 0xcb, 0xc7, 0x28, + 0xdc, 0x04, 0xd4, 0x07, 0x11, 0x05, 0x1c, 0x35, + 0x0d, 0x1c, 0x0d, 0x26, 0x21, 0x0d, 0x1c, 0x49, + 0x0d, 0x2c, 0x27, 0x26, 0x1c, 0x37, 0x0e, 0x43, + 0x06, 0x05, 0xa6, 0x05, 0x03, 0x0e, 0x03, 0x04, + 0x00, 0x06, 0xb2, 0x02, 0x11, 0x94, 0x07, 0x00, + 0x01, 0x00, 0xc2, 0x07, 0x00, 0x01, 0x00, 0xc4, + 0x07, 0x00, 0x01, 0x00, 0xc6, 0x07, 0x00, 0x00, + 0x00, 0xc8, 0x07, 0x00, 0x01, 0x00, 0xae, 0x06, + 0x00, 0x02, 0x00, 0xca, 0x07, 0x00, 0x03, 0x00, + 0xcc, 0x07, 0x00, 0x04, 0x00, 0xce, 0x07, 0x00, + 0x05, 0x00, 0xe2, 0x06, 0x00, 0x06, 0x00, 0xd0, + 0x07, 0x00, 0x07, 0x00, 0xd2, 0x07, 0x00, 0x08, + 0x00, 0xd4, 0x07, 0x00, 0x09, 0x00, 0xd6, 0x07, + 0x00, 0x0a, 0x00, 0xd8, 0x07, 0x00, 0x0b, 0x00, + 0xda, 0x07, 0x00, 0x0c, 0x00, 0xdc, 0x07, 0x00, + 0x0d, 0x00, 0xd3, 0x42, 0x8e, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc6, 0x06, 0xb8, 0xaa, 0xec, + 0x0a, 0xd3, 0xb7, 0x47, 0x8d, 0xd3, 0xb8, 0x47, + 0x9c, 0x28, 0xd3, 0xb7, 0x47, 0xb7, 0xaa, 0xec, + 0x07, 0xc1, 0x00, 0xbf, 0xed, 0xb3, 0x28, 0xd3, + 0x42, 0xf8, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcf, 0x42, 0xf8, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xcc, 0xc1, 0x01, 0xbf, 0xed, 0xb3, 0xc5, + 0x0c, 0xc1, 0x02, 0xbf, 0xed, 0xb3, 0xc5, 0x0d, + 0xb7, 0xcd, 0xc9, 0xd5, 0xa4, 0x6a, 0xe4, 0x00, + 0x00, 0x00, 0xd3, 0x42, 0x5b, 0x00, 0x00, 0x00, + 0xd4, 0x24, 0x01, 0x00, 0xd2, 0xb7, 0xaa, 0xec, + 0x03, 0xd4, 0x28, 0x38, 0xfb, 0x00, 0x00, 0x00, + 0xd4, 0xc4, 0x0d, 0x9f, 0xf1, 0xc5, 0x0b, 0xc9, + 0xb9, 0xa7, 0xec, 0x3b, 0xc4, 0x0b, 0xc4, 0x0c, + 0xa7, 0xec, 0x34, 0x38, 0xfb, 0x00, 0x00, 0x00, + 0xc4, 0x0d, 0xf1, 0xc1, 0x03, 0xbf, 0xea, 0xb3, + 0xa4, 0xec, 0x0e, 0xc4, 0x0b, 0xc1, 0x04, 0xbf, + 0xe7, 0xb3, 0xa4, 0xec, 0x1a, 0xc4, 0x0d, 0x28, + 0xc4, 0x0b, 0x38, 0xfb, 0x00, 0x00, 0x00, 0xc4, + 0x0d, 0xf1, 0xc1, 0x05, 0xbf, 0xeb, 0xb3, 0x9b, + 0xa4, 0xec, 0x04, 0xc4, 0x0d, 0x28, 0xc4, 0x0b, + 0xc5, 0x0c, 0xd4, 0xc5, 0x0d, 0xc7, 0x42, 0x5b, + 0x00, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0xc5, + 0x04, 0xc8, 0x42, 0x5b, 0x00, 0x00, 0x00, 0xd4, + 0x24, 0x01, 0x00, 0xc5, 0x05, 0xc4, 0x06, 0xb8, + 0x9f, 0xc4, 0x04, 0x9b, 0xc6, 0x07, 0xc4, 0x07, + 0x9b, 0xc5, 0x07, 0xc4, 0x06, 0xc4, 0x06, 0xb8, + 0x9f, 0x9b, 0xca, 0x9b, 0xc4, 0x05, 0x9b, 0xc5, + 0x08, 0x38, 0x02, 0x01, 0x00, 0x00, 0xc4, 0x07, + 0xc4, 0x08, 0x9f, 0xf1, 0xc5, 0x07, 0xc4, 0x04, + 0xc4, 0x07, 0x9e, 0xc5, 0x09, 0xc4, 0x04, 0xc4, + 0x07, 0x9f, 0xc5, 0x0a, 0x38, 0xfa, 0x00, 0x00, + 0x00, 0xc4, 0x0a, 0xf1, 0x38, 0xfa, 0x00, 0x00, + 0x00, 0xc4, 0x09, 0xf1, 0xa6, 0xec, 0x05, 0xc4, + 0x0a, 0xc5, 0x09, 0xc4, 0x09, 0xb7, 0xaa, 0xec, + 0x03, 0x07, 0x28, 0xd4, 0xc4, 0x06, 0xca, 0x9b, + 0xc4, 0x09, 0x9c, 0x9f, 0xd8, 0x94, 0x02, 0xef, + 0x1a, 0xff, 0x07, 0x28, 0xdc, 0x04, 0xf0, 0x07, + 0x29, 0x00, 0x00, 0x08, 0x3a, 0x18, 0x2b, 0x09, + 0x26, 0x22, 0x35, 0x30, 0x26, 0x26, 0x35, 0x3a, + 0x17, 0x0f, 0x40, 0x3f, 0x53, 0x35, 0x0d, 0x08, + 0x62, 0x14, 0x17, 0x13, 0x3f, 0x3f, 0x30, 0x1c, + 0x49, 0x44, 0x26, 0x26, 0x62, 0x17, 0x21, 0x0d, + 0x35, 0x1c, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, + 0x0b, 0xfc, 0x01, 0x06, 0x40, 0x76, 0x3a, 0x6b, + 0x0b, 0xde, 0x0b, 0xfc, 0x01, 0x06, 0x40, 0x76, + 0x3a, 0x6b, 0x0b, 0xde, 0x0b, 0xfc, 0x01, 0x06, + 0x40, 0x76, 0x3a, 0x6b, 0x0b, 0xde, 0x0e, 0x43, + 0x06, 0x05, 0xa8, 0x05, 0x01, 0x07, 0x01, 0x05, + 0x01, 0x04, 0xab, 0x01, 0x08, 0x94, 0x07, 0x00, + 0x01, 0x00, 0xe2, 0x06, 0x00, 0x00, 0x00, 0xae, + 0x06, 0x00, 0x01, 0x00, 0xda, 0x04, 0x00, 0x02, + 0x00, 0xc2, 0x06, 0x00, 0x03, 0x00, 0xc2, 0x07, + 0x00, 0x04, 0x00, 0xde, 0x07, 0x00, 0x05, 0x00, + 0xe0, 0x07, 0x00, 0x06, 0x00, 0xa6, 0x05, 0x24, + 0x01, 0xc1, 0x00, 0xbf, 0xed, 0xb3, 0xc1, 0x01, + 0xbf, 0xee, 0xb3, 0x8d, 0xc1, 0x02, 0xbf, 0xee, + 0xb3, 0x26, 0x03, 0x00, 0xc5, 0x06, 0xd3, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xa8, 0x97, 0xec, 0x0d, + 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xf1, 0x01, + 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0x42, 0x8e, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xcf, 0xb7, 0xa5, + 0xec, 0x05, 0x26, 0x00, 0x00, 0x28, 0xc1, 0x03, + 0xbf, 0xee, 0xb3, 0x38, 0xb6, 0x00, 0x00, 0x00, + 0x41, 0xcb, 0x01, 0x00, 0x00, 0x8d, 0xa0, 0xc5, + 0x05, 0x26, 0x00, 0x00, 0xcd, 0xb7, 0xcc, 0xc8, + 0xc7, 0xa4, 0xec, 0x4f, 0xb7, 0xce, 0xca, 0xba, + 0xa4, 0xec, 0x15, 0xdf, 0xd3, 0xc4, 0x06, 0xca, + 0x47, 0xbf, 0x64, 0xf3, 0xc6, 0x04, 0xf5, 0xed, + 0x03, 0xee, 0x05, 0x94, 0x03, 0xee, 0xe8, 0xca, + 0xba, 0xaa, 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, + 0x00, 0x04, 0xf2, 0x01, 0x00, 0x00, 0xf1, 0x2f, + 0xc9, 0xc8, 0xc4, 0x04, 0x49, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd3, + 0x38, 0xee, 0x00, 0x00, 0x00, 0xc4, 0x04, 0x9f, + 0x24, 0x02, 0x00, 0xb7, 0x47, 0xd7, 0x94, 0x01, + 0xee, 0xae, 0xc9, 0x28, 0xdc, 0x04, 0xa6, 0x08, + 0x14, 0x05, 0x6d, 0x35, 0x3f, 0x35, 0x17, 0x17, + 0x62, 0x17, 0x27, 0x26, 0x3a, 0x12, 0x0d, 0x17, + 0x1c, 0x3f, 0x1c, 0x80, 0x17, 0x0b, 0xfc, 0x01, + 0x06, 0x40, 0x76, 0x3a, 0x6b, 0x0b, 0xde, 0x0b, + 0x80, 0x02, 0x06, 0x60, 0xec, 0xa8, 0x64, 0x6e, + 0x9b, 0x0b, 0x80, 0x02, 0x06, 0x50, 0xb1, 0xf1, + 0xe7, 0xbc, 0xbc, 0x0b, 0x80, 0x02, 0x06, 0x40, + 0x76, 0x3a, 0x6b, 0x0b, 0xde, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, + 0x21, 0x03, 0xc0, 0x06, 0x00, 0x00, 0x00, 0xae, + 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcd, 0xc9, 0xcf, 0xeb, 0xcc, 0xc8, 0xb8, + 0xa6, 0xec, 0x0e, 0xc7, 0xc8, 0xb8, 0x9f, 0x47, + 0xb7, 0xaa, 0xec, 0x05, 0x93, 0x01, 0xee, 0xef, + 0xc7, 0xc8, 0x43, 0x30, 0x00, 0x00, 0x00, 0xc7, + 0x28, 0xdc, 0x04, 0xc2, 0x08, 0x06, 0x0d, 0x08, + 0x12, 0x49, 0x17, 0x26, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x00, 0x2f, + 0x05, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, + 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, 0x00, + 0xc0, 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xc5, 0x04, 0xc4, 0x04, 0xd2, 0xeb, + 0xcd, 0x26, 0x00, 0x00, 0xcb, 0xb7, 0xcc, 0xc8, + 0xc9, 0xa4, 0xec, 0x14, 0xc7, 0xc8, 0x73, 0xca, + 0xc8, 0x47, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x49, 0x94, 0x01, 0xee, 0xe9, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xc7, 0x23, 0x01, 0x00, + 0xdc, 0x04, 0xca, 0x08, 0x06, 0x13, 0x12, 0x0d, + 0x17, 0x26, 0x62, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x15, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, 0xea, + 0x00, 0x00, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xb8, 0x26, 0x01, 0x00, 0xf1, 0xc7, 0x23, 0x02, + 0x00, 0xdc, 0x04, 0xd3, 0x08, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x06, 0x00, 0x03, + 0x01, 0x00, 0x67, 0x06, 0xae, 0x06, 0x00, 0x00, + 0x00, 0xe6, 0x07, 0x00, 0x01, 0x00, 0xbc, 0x07, + 0x00, 0x02, 0x00, 0xf4, 0x06, 0x00, 0x03, 0x00, + 0xc0, 0x06, 0x00, 0x04, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xa4, 0x05, 0x23, 0x01, 0x08, 0xc5, 0x05, + 0xc4, 0x05, 0xc6, 0x04, 0xeb, 0xb8, 0xaa, 0xec, + 0x0d, 0xc4, 0x04, 0xb7, 0x47, 0x42, 0x38, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xc3, 0xcc, 0xc4, + 0x04, 0xeb, 0xb8, 0x9f, 0xcb, 0xc7, 0xb7, 0xa7, + 0xec, 0x41, 0xc4, 0x04, 0xc7, 0x47, 0xd2, 0xb7, + 0xaa, 0x11, 0xed, 0x13, 0x0e, 0xca, 0x38, 0xe7, + 0x00, 0x00, 0x00, 0xa8, 0xec, 0x0b, 0xca, 0x41, + 0xd7, 0x01, 0x00, 0x00, 0xb7, 0xaa, 0xed, 0x1f, + 0xdf, 0xca, 0xc7, 0xf2, 0xd1, 0xb7, 0x47, 0x04, + 0x7b, 0x01, 0x00, 0x00, 0xab, 0xec, 0x0d, 0xc8, + 0xc3, 0xab, 0xec, 0x08, 0x04, 0x7a, 0x01, 0x00, + 0x00, 0x95, 0x01, 0xc9, 0x95, 0x01, 0x93, 0x00, + 0xee, 0xbc, 0xc8, 0x28, 0xdc, 0x04, 0xd6, 0x08, + 0x10, 0x12, 0x0d, 0x26, 0x40, 0x0d, 0x3a, 0x1c, + 0x21, 0x58, 0x0d, 0x1c, 0x35, 0x1c, 0x27, 0x12, + 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x00, 0x1b, 0x01, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xcb, 0xc7, 0xeb, 0xb8, 0xaa, + 0xec, 0x0f, 0xc7, 0xb7, 0x47, 0xb7, 0xaa, 0xec, + 0x08, 0x38, 0xf4, 0x01, 0x00, 0x00, 0x8d, 0x28, + 0xc7, 0xeb, 0xb8, 0x9f, 0x28, 0xdc, 0x04, 0xea, + 0x08, 0x04, 0x0d, 0x44, 0x21, 0x08, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x01, 0x05, 0x01, 0x03, 0x00, + 0x00, 0x21, 0x06, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xae, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xd6, 0x06, 0x00, 0x02, 0x00, 0xc0, + 0x06, 0x00, 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xc5, 0x04, 0xc4, 0x04, 0xd2, 0xeb, 0xb8, + 0x9f, 0xcc, 0xca, 0xc8, 0x47, 0xcd, 0xc8, 0xb7, + 0xa6, 0xec, 0x0d, 0x93, 0x01, 0xc9, 0xd3, 0x9b, + 0xca, 0xc8, 0x47, 0x9e, 0xcd, 0xee, 0xf0, 0xc9, + 0x28, 0xdc, 0x04, 0xf0, 0x08, 0x08, 0x12, 0x0d, + 0x1c, 0x17, 0x1c, 0x0d, 0x2b, 0x0d, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x00, 0x38, 0x05, 0xc0, 0x06, 0x00, 0x00, 0x00, + 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x02, 0x00, 0xae, 0x06, 0x00, 0x03, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc5, 0x04, 0xc4, 0x04, + 0xcf, 0xeb, 0xd0, 0xb8, 0xaa, 0xec, 0x0a, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xb7, 0x23, 0x01, 0x00, + 0x26, 0x00, 0x00, 0xcd, 0xb8, 0xce, 0xca, 0xc8, + 0xa4, 0xec, 0x10, 0xc9, 0xca, 0xb8, 0x9f, 0x73, + 0xca, 0xc7, 0xca, 0x47, 0x9b, 0x49, 0x94, 0x03, + 0xee, 0xed, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xc9, + 0x23, 0x01, 0x00, 0xdc, 0x04, 0xfa, 0x08, 0x09, + 0x12, 0x0d, 0x12, 0x17, 0x31, 0x17, 0x26, 0x3a, + 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x05, + 0x00, 0x05, 0x00, 0x00, 0x2e, 0x05, 0xc0, 0x06, + 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, + 0xd6, 0x06, 0x00, 0x02, 0x00, 0xae, 0x06, 0x00, + 0x03, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc5, + 0x04, 0xc4, 0x04, 0xcf, 0xeb, 0xcc, 0xb7, 0x26, + 0x01, 0x00, 0xcd, 0xb7, 0xce, 0xca, 0xc8, 0xa4, + 0xec, 0x12, 0xc9, 0xca, 0xb8, 0x9e, 0x73, 0xc7, + 0xca, 0x47, 0xca, 0xb8, 0x9e, 0x9c, 0x49, 0x94, + 0x03, 0xee, 0xeb, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xc9, 0x23, 0x01, 0x00, 0xdc, 0x04, 0x87, 0x09, + 0x07, 0x12, 0x0d, 0x12, 0x1c, 0x26, 0x44, 0x17, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x00, 0x25, 0x05, 0xc0, 0x06, 0x00, + 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, + 0x06, 0x00, 0x02, 0x00, 0xae, 0x06, 0x00, 0x03, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc5, 0x04, + 0xc4, 0x04, 0xcf, 0xeb, 0xcc, 0xb7, 0xcd, 0xb7, + 0xce, 0xca, 0xc8, 0xa4, 0xec, 0x13, 0xc9, 0xc7, + 0xca, 0x47, 0x42, 0xfa, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x9e, 0xcd, 0x94, 0x03, 0xee, 0xea, + 0xc9, 0x28, 0xdc, 0x04, 0x90, 0x09, 0x07, 0x12, + 0x0d, 0x12, 0x0d, 0x26, 0x49, 0x17, 0x0e, 0x43, + 0x06, 0x05, 0xaa, 0x05, 0x02, 0x05, 0x02, 0x05, + 0x00, 0x00, 0x5a, 0x07, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xea, 0x07, + 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, 0x00, + 0xae, 0x06, 0x00, 0x02, 0x00, 0xfc, 0x06, 0x00, + 0x03, 0x00, 0xec, 0x07, 0x00, 0x04, 0x00, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0xd3, + 0xeb, 0xd4, 0xeb, 0xa4, 0xec, 0x07, 0xd3, 0xcb, + 0xd4, 0xd7, 0xc7, 0xd8, 0xd4, 0xeb, 0xce, 0xd3, + 0xeb, 0xc5, 0x04, 0x26, 0x00, 0x00, 0xcc, 0xb7, + 0xcd, 0xc9, 0xca, 0xa4, 0xec, 0x10, 0xc8, 0xc9, + 0x73, 0xd3, 0xc9, 0x47, 0xd4, 0xc9, 0x47, 0x9e, + 0x49, 0x94, 0x02, 0xee, 0xed, 0xca, 0xcd, 0xc9, + 0xc4, 0x04, 0xa4, 0xec, 0x0c, 0xc8, 0xc9, 0x73, + 0xd3, 0xc9, 0x47, 0x49, 0x94, 0x02, 0xee, 0xf0, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0xc8, 0x23, 0x01, + 0x00, 0xdc, 0x04, 0x9c, 0x09, 0x0e, 0x04, 0x2b, + 0x2b, 0x26, 0x0d, 0x0d, 0x0e, 0x12, 0x17, 0x17, + 0x26, 0x4e, 0x2b, 0x3a, 0x0e, 0x43, 0x06, 0x05, + 0xac, 0x05, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, + 0x07, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xaa, 0x05, 0x26, 0x01, + 0xdf, 0xd3, 0xd4, 0x8d, 0x23, 0x02, 0x00, 0xdc, + 0x04, 0xae, 0x09, 0x01, 0x03, 0x0e, 0x43, 0x06, + 0x05, 0xae, 0x05, 0x02, 0x06, 0x02, 0x06, 0x00, + 0x00, 0x64, 0x08, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, + 0x00, 0x00, 0xc2, 0x06, 0x00, 0x01, 0x00, 0xfc, + 0x06, 0x00, 0x02, 0x00, 0xec, 0x07, 0x00, 0x03, + 0x00, 0xde, 0x06, 0x00, 0x04, 0x00, 0xd6, 0x06, + 0x00, 0x05, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0xd7, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xd4, 0xf1, 0xd8, 0xd3, 0xeb, 0xcd, 0xd4, 0xeb, + 0xce, 0xc9, 0xca, 0x9e, 0xb8, 0x9f, 0xc5, 0x04, + 0x26, 0x00, 0x00, 0xc5, 0x05, 0xb7, 0xcb, 0xc7, + 0xc4, 0x04, 0xa4, 0xec, 0x0a, 0xc4, 0x05, 0xc7, + 0xb7, 0x49, 0x94, 0x00, 0xee, 0xf2, 0xb7, 0xcb, + 0xc7, 0xc9, 0xa4, 0xec, 0x21, 0xb7, 0xcc, 0xc8, + 0xca, 0xa4, 0xec, 0x16, 0xc4, 0x05, 0xc7, 0xc8, + 0x9e, 0x73, 0x13, 0x47, 0xd3, 0xc7, 0x47, 0xd4, + 0xc8, 0x47, 0x9b, 0x9e, 0x49, 0x94, 0x01, 0xee, + 0xe7, 0x94, 0x00, 0xee, 0xdc, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0xc4, 0x05, 0x23, 0x01, 0x00, 0xdc, + 0x04, 0xb1, 0x09, 0x0e, 0x04, 0x2b, 0x2b, 0x12, + 0x12, 0x26, 0x1c, 0x2b, 0x30, 0x26, 0x26, 0x58, + 0x17, 0x17, 0x0e, 0x43, 0x06, 0x05, 0xb0, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x06, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0xb8, 0xd4, 0x9c, 0x9b, 0x28, + 0xdc, 0x04, 0xc2, 0x09, 0x01, 0x03, 0x0e, 0x43, + 0x06, 0x05, 0xb2, 0x05, 0x02, 0x00, 0x02, 0x04, + 0x00, 0x00, 0x16, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xea, + 0x00, 0x00, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xd4, + 0xf1, 0x23, 0x02, 0x00, 0xdc, 0x04, 0xc5, 0x09, + 0x02, 0x04, 0x3f, 0x0e, 0x43, 0x06, 0x05, 0xb4, + 0x05, 0x02, 0x00, 0x02, 0x04, 0x00, 0x00, 0x12, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd3, 0xd4, 0x24, + 0x02, 0x00, 0xb8, 0x47, 0x28, 0xdc, 0x04, 0xca, + 0x09, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, 0xb6, + 0x05, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x22, + 0x04, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, + 0xae, 0x06, 0x00, 0x01, 0x00, 0xd3, 0xeb, 0xcf, + 0xd4, 0xeb, 0xab, 0xec, 0x03, 0x09, 0x28, 0xb7, + 0xcc, 0xc8, 0xc7, 0xa4, 0xec, 0x10, 0xd3, 0xc8, + 0x47, 0xd4, 0xc8, 0x47, 0xab, 0xec, 0x03, 0x09, + 0x28, 0x94, 0x01, 0xee, 0xed, 0x0a, 0x28, 0xdc, + 0x04, 0xcd, 0x09, 0x08, 0x04, 0x12, 0x1c, 0x0d, + 0x26, 0x30, 0x0d, 0x17, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0x28, + 0xdc, 0x04, 0xe1, 0x09, 0x01, 0x03, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x01, 0x03, 0x01, 0x04, 0x00, + 0x00, 0x23, 0x04, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd6, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, 0x00, 0xd3, + 0xeb, 0xcd, 0x26, 0x00, 0x00, 0xcb, 0xb7, 0xcc, + 0xc8, 0xc9, 0xa4, 0xec, 0x0d, 0xc7, 0xc8, 0x73, + 0xd3, 0xc8, 0x47, 0x8d, 0x49, 0x94, 0x01, 0xee, + 0xf0, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xc7, 0x23, + 0x01, 0x00, 0xdc, 0x04, 0xe4, 0x09, 0x05, 0x04, + 0x12, 0x17, 0x26, 0x3f, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x08, 0x02, 0x05, 0x00, 0x00, 0xc8, + 0x01, 0x0a, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xfc, 0x06, 0x00, 0x00, + 0x00, 0xec, 0x07, 0x00, 0x01, 0x00, 0xae, 0x06, + 0x00, 0x02, 0x00, 0xc2, 0x06, 0x00, 0x03, 0x00, + 0xee, 0x06, 0x00, 0x04, 0x00, 0xd6, 0x06, 0x00, + 0x05, 0x00, 0xde, 0x06, 0x00, 0x06, 0x00, 0xf4, + 0x06, 0x00, 0x07, 0x00, 0xd4, 0x42, 0x8e, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, 0xa4, 0xec, + 0x0d, 0x38, 0xce, 0x00, 0x00, 0x00, 0x04, 0xc2, + 0x01, 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0xeb, 0xcb, + 0xd4, 0xeb, 0xcc, 0xc7, 0xc8, 0xa4, 0xec, 0x10, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0xb7, 0x26, 0x01, + 0x00, 0xf1, 0xd3, 0x26, 0x02, 0x00, 0x28, 0x38, + 0x98, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x41, 0x94, 0x01, 0x00, 0x00, 0x42, 0xaa, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xc5, + 0x05, 0x26, 0x00, 0x00, 0xc5, 0x04, 0x93, 0x01, + 0xc7, 0xc8, 0x9f, 0xc5, 0x06, 0xb7, 0xcd, 0xc9, + 0xc4, 0x06, 0xa4, 0xec, 0x0a, 0xc4, 0x04, 0xc9, + 0xb7, 0x49, 0x94, 0x02, 0xee, 0xf2, 0xc4, 0x06, + 0xb8, 0x9f, 0xcd, 0xc9, 0xb7, 0xa7, 0xec, 0x41, + 0xc4, 0x05, 0xc9, 0xc8, 0x9e, 0x47, 0xc6, 0x07, + 0xb7, 0xab, 0xec, 0x31, 0xc4, 0x07, 0xd4, 0xc8, + 0x47, 0x9c, 0xc5, 0x07, 0xc4, 0x05, 0xc9, 0xc8, + 0x9e, 0xb7, 0x49, 0xb7, 0xce, 0xca, 0xc8, 0xa4, + 0xec, 0x15, 0xc4, 0x05, 0xc9, 0xca, 0x9e, 0x73, + 0x13, 0x47, 0xd4, 0xca, 0x47, 0xc4, 0x07, 0x9b, + 0x9f, 0x49, 0x94, 0x03, 0xee, 0xe8, 0xc4, 0x04, + 0xc9, 0xc4, 0x07, 0x49, 0x93, 0x02, 0xee, 0xbc, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0xc4, 0x04, 0xf1, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0xc4, 0x05, 0xf1, + 0x26, 0x02, 0x00, 0x28, 0xdc, 0x04, 0xff, 0x09, + 0x17, 0x04, 0x44, 0x3f, 0x12, 0x12, 0x1c, 0x4e, + 0x85, 0x1c, 0x0d, 0x1c, 0x2b, 0x30, 0x35, 0x2b, + 0x17, 0x2b, 0x26, 0x26, 0x53, 0x17, 0x22, 0x17, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, 0x01, 0x02, + 0x04, 0x00, 0x00, 0x2e, 0x03, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xe0, + 0x06, 0x00, 0x00, 0x00, 0xd4, 0x42, 0x8e, 0x01, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, 0xa7, 0xec, + 0x19, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x42, 0x8f, + 0x01, 0x00, 0x00, 0xd3, 0xd4, 0x24, 0x02, 0x00, + 0xcb, 0xd4, 0xd7, 0xc7, 0xb8, 0x47, 0xd8, 0xee, + 0xdc, 0xd3, 0xd3, 0xd3, 0xeb, 0xb8, 0x9f, 0x47, + 0x9c, 0x28, 0xdc, 0x04, 0x9a, 0x0a, 0x06, 0x04, + 0x44, 0x53, 0x0d, 0x17, 0x0e, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x02, 0x06, 0x02, 0x04, 0x00, 0x00, + 0x7f, 0x08, 0xea, 0x06, 0x00, 0x01, 0x00, 0xec, + 0x06, 0x00, 0x01, 0x00, 0xee, 0x06, 0x00, 0x00, + 0x00, 0xf0, 0x06, 0x00, 0x01, 0x00, 0xf2, 0x06, + 0x00, 0x02, 0x00, 0xc0, 0x06, 0x00, 0x03, 0x00, + 0xf4, 0x06, 0x00, 0x04, 0x00, 0xe0, 0x06, 0x00, + 0x05, 0x00, 0xd3, 0xcc, 0xd4, 0xcd, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0xb8, 0x26, 0x01, 0x00, 0xf1, + 0xc5, 0x04, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xb7, + 0x26, 0x01, 0x00, 0xf1, 0xce, 0xc8, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, 0xa7, + 0xec, 0x2d, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x42, + 0x8f, 0x01, 0x00, 0x00, 0xc9, 0xc8, 0x24, 0x02, + 0x00, 0xc6, 0x05, 0xb7, 0x47, 0xcb, 0xc8, 0xcd, + 0xc4, 0x05, 0xb8, 0x47, 0xcc, 0xc4, 0x04, 0xc5, + 0x05, 0xca, 0xc7, 0xc4, 0x04, 0x9b, 0x9f, 0xc5, + 0x04, 0xc4, 0x05, 0xce, 0xee, 0xc8, 0xc9, 0x42, + 0x8e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, + 0xa6, 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, 0x00, + 0x04, 0xbc, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0x42, 0x8f, 0x01, 0x00, + 0x00, 0xca, 0xd4, 0x24, 0x02, 0x00, 0xb8, 0x47, + 0x28, 0xdc, 0x04, 0xa4, 0x0a, 0x10, 0x04, 0x0d, + 0x0d, 0x3f, 0x3a, 0x44, 0x58, 0x12, 0x0d, 0x1c, + 0x17, 0x2b, 0x12, 0x0e, 0x44, 0x3f, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, + 0x00, 0x05, 0x01, 0x94, 0x07, 0x00, 0x01, 0x00, + 0xa8, 0x05, 0x25, 0x01, 0xdf, 0xd3, 0x23, 0x01, + 0x00, 0xdc, 0x04, 0xb8, 0x0a, 0x01, 0x03, 0x0e, + 0x43, 0x06, 0x05, 0xd2, 0x03, 0x02, 0x04, 0x02, + 0x04, 0x00, 0x00, 0x9e, 0x01, 0x06, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xfa, 0x06, 0x00, 0x01, 0x00, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0xe0, 0x06, 0x00, + 0x01, 0x00, 0xe4, 0x01, 0x00, 0x01, 0x00, 0xd2, + 0x03, 0x00, 0x01, 0x14, 0x0c, 0x03, 0xcd, 0x0c, + 0x02, 0xce, 0xc9, 0xec, 0x0d, 0x38, 0xd1, 0x00, + 0x00, 0x00, 0x04, 0xc0, 0x01, 0x00, 0x00, 0xf1, + 0x2f, 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0xa9, + 0x01, 0x00, 0x00, 0xca, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xcb, 0xd4, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0xa8, 0xec, 0x51, 0xd4, 0x42, + 0x8e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, + 0xa5, 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, 0x00, + 0x04, 0xf7, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0xd3, + 0x38, 0xea, 0x00, 0x00, 0x00, 0xa8, 0xec, 0x12, + 0xca, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, + 0xf2, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9c, + 0x28, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xd7, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x42, 0x8f, + 0x01, 0x00, 0x00, 0xd3, 0xd4, 0x24, 0x02, 0x00, + 0xd0, 0xb8, 0x47, 0xd7, 0xee, 0x0d, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0xd6, 0x01, 0x00, 0x00, + 0xf1, 0x2f, 0xc7, 0xd3, 0x43, 0xd7, 0x01, 0x00, + 0x00, 0xc7, 0xd4, 0x43, 0xd8, 0x01, 0x00, 0x00, + 0xc7, 0x28, 0xdc, 0x04, 0xbf, 0x0a, 0x12, 0x22, + 0x12, 0x3f, 0x67, 0x30, 0x44, 0x3f, 0x30, 0x53, + 0x08, 0x2b, 0x53, 0x13, 0x0d, 0x3a, 0x08, 0x26, + 0x26, 0x0e, 0x43, 0x06, 0x05, 0xb8, 0x05, 0x02, + 0x00, 0x02, 0x03, 0x00, 0x00, 0x76, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0x38, 0xe9, 0x00, 0x00, 0x00, 0xa8, + 0x97, 0xec, 0x17, 0x38, 0xe9, 0x00, 0x00, 0x00, + 0xd3, 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, 0x9e, + 0xd4, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xd4, 0x38, 0xe9, 0x00, 0x00, 0x00, 0xa8, + 0x97, 0xec, 0x17, 0x38, 0xe9, 0x00, 0x00, 0x00, + 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, 0x9e, + 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd8, 0x01, 0x00, 0x00, 0xab, 0xec, 0x0d, + 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xd9, 0x01, + 0x00, 0x00, 0xf1, 0x2f, 0x38, 0xe9, 0x00, 0x00, + 0x00, 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd7, 0x01, 0x00, 0x00, 0x9e, 0xd3, 0x41, + 0xd8, 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, + 0x04, 0xd6, 0x0a, 0x07, 0x03, 0x35, 0x71, 0x35, + 0x72, 0x4e, 0x3f, 0x0e, 0x43, 0x06, 0x05, 0xba, + 0x05, 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x07, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xb8, 0x05, 0x2d, 0x01, 0xdf, + 0xd3, 0xd4, 0x8d, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0xe1, 0x0a, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, + 0xbc, 0x05, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, + 0x76, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0x38, 0xe9, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe9, + 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x41, 0xd7, 0x01, + 0x00, 0x00, 0x9b, 0xd4, 0x41, 0xd8, 0x01, 0x00, + 0x00, 0x23, 0x02, 0x00, 0xd4, 0x38, 0xe9, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x17, 0x38, 0xe9, + 0x00, 0x00, 0x00, 0xd3, 0x41, 0xd7, 0x01, 0x00, + 0x00, 0xd4, 0x9b, 0xd3, 0x41, 0xd8, 0x01, 0x00, + 0x00, 0x23, 0x02, 0x00, 0xd3, 0x41, 0xd8, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xab, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, + 0x04, 0xd9, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, + 0xe9, 0x00, 0x00, 0x00, 0xd3, 0x41, 0xd7, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xd7, 0x01, 0x00, 0x00, + 0x9b, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xe4, 0x0a, 0x07, 0x03, + 0x35, 0x71, 0x35, 0x72, 0x4e, 0x3f, 0x0e, 0x43, + 0x06, 0x05, 0xbe, 0x05, 0x02, 0x00, 0x02, 0x04, + 0x01, 0x00, 0x26, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xbc, 0x05, + 0x2f, 0x01, 0xd4, 0x38, 0xe9, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x0f, 0x38, 0xe9, 0x00, 0x00, + 0x00, 0xd4, 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xf2, 0xd8, 0xdf, 0xd3, 0xd4, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xdc, 0x04, 0xef, 0x0a, 0x03, 0x03, 0x35, 0x49, + 0x0e, 0x43, 0x06, 0x05, 0xc0, 0x05, 0x02, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x1f, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0x41, 0xd8, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xd8, 0x01, 0x00, 0x00, 0xaa, 0x11, 0xec, 0x0f, + 0x0e, 0xd3, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xd7, 0x01, 0x00, 0x00, 0xaa, 0x28, 0xdc, + 0x04, 0xf4, 0x0a, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x02, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, + 0x28, 0xdc, 0x04, 0x80, 0x0b, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x15, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe9, 0x00, 0x00, 0x00, 0xd3, 0x41, + 0xd7, 0x01, 0x00, 0x00, 0x8d, 0xd3, 0x41, 0xd8, + 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0x83, 0x0b, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x3b, + 0x03, 0xc0, 0x06, 0x00, 0x00, 0x00, 0xfa, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcd, 0xc9, 0xcf, 0x41, 0xd8, 0x01, 0x00, 0x00, + 0xd0, 0x38, 0xe8, 0x00, 0x00, 0x00, 0xa8, 0xec, + 0x1e, 0x38, 0xe9, 0x00, 0x00, 0x00, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0x42, 0xf4, 0x00, 0x00, 0x00, + 0xc7, 0x41, 0xd7, 0x01, 0x00, 0x00, 0xc8, 0x24, + 0x02, 0x00, 0xc8, 0x23, 0x02, 0x00, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0xda, 0x01, 0x00, 0x00, + 0xf1, 0x2f, 0xdc, 0x04, 0x92, 0x0b, 0x04, 0x0d, + 0x26, 0x30, 0x95, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x22, 0x01, + 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, 0x04, 0xf8, + 0x01, 0x00, 0x00, 0xc7, 0x41, 0xd7, 0x01, 0x00, + 0x00, 0x9e, 0x04, 0xdc, 0x01, 0x00, 0x00, 0x9e, + 0xc7, 0x41, 0xd8, 0x01, 0x00, 0x00, 0x9e, 0x04, + 0xdd, 0x01, 0x00, 0x00, 0x9e, 0x28, 0xdc, 0x04, + 0x9a, 0x0b, 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x05, + 0xd4, 0x03, 0x02, 0x06, 0x02, 0x04, 0x00, 0x00, + 0xc1, 0x01, 0x08, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xc4, 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, + 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, 0x00, 0xe2, + 0x06, 0x00, 0x02, 0x00, 0xaa, 0x06, 0x00, 0x03, + 0x00, 0xe4, 0x01, 0x00, 0x01, 0x00, 0xd4, 0x03, + 0x00, 0x01, 0x14, 0x0c, 0x03, 0xc5, 0x04, 0x0c, + 0x02, 0xc5, 0x05, 0xc4, 0x04, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x01, 0x00, + 0x00, 0xf1, 0x2f, 0xd3, 0x38, 0xe8, 0x00, 0x00, + 0x00, 0xa8, 0x97, 0x11, 0xed, 0x0a, 0x0e, 0xd4, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0xa8, 0x97, 0xec, + 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, 0xf1, + 0x01, 0x00, 0x00, 0xf1, 0x2f, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd3, + 0xd4, 0x24, 0x02, 0x00, 0xcf, 0xb8, 0x47, 0xd0, + 0x42, 0x8e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xb7, 0xa4, 0xec, 0x05, 0xc7, 0xb7, 0x47, 0x28, + 0x38, 0xe8, 0x00, 0x00, 0x00, 0x42, 0xf0, 0x00, + 0x00, 0x00, 0xd4, 0xc8, 0x24, 0x02, 0x00, 0xd1, + 0x42, 0x8e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xb7, 0xa6, 0xec, 0x25, 0x38, 0xe8, 0x00, 0x00, + 0x00, 0x42, 0x8f, 0x01, 0x00, 0x00, 0xd3, 0xc9, + 0x24, 0x02, 0x00, 0xb7, 0x47, 0xd7, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0x42, 0x8f, 0x01, 0x00, 0x00, + 0xd4, 0xc9, 0x24, 0x02, 0x00, 0xb7, 0x47, 0xd8, + 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0xa9, 0x01, + 0x00, 0x00, 0xc4, 0x05, 0x41, 0x3c, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xd2, 0xd3, 0x43, 0xc3, + 0x01, 0x00, 0x00, 0xca, 0xd4, 0x43, 0xc4, 0x01, + 0x00, 0x00, 0xca, 0x28, 0xdc, 0x04, 0xa1, 0x0b, + 0x11, 0x2d, 0x17, 0x3f, 0x3f, 0x35, 0x3f, 0x53, + 0x12, 0x3f, 0x17, 0x53, 0x3f, 0x5d, 0x5e, 0x6c, + 0x21, 0x26, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x00, 0x00, 0x16, 0x01, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xcb, 0x38, 0xea, 0x00, + 0x00, 0x00, 0xc7, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xc7, 0x41, 0xc3, 0x01, 0x00, 0x00, 0x23, 0x02, + 0x00, 0xdc, 0x04, 0xb9, 0x0b, 0x01, 0x0d, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x00, 0x00, 0x26, 0x01, 0x10, 0x00, 0x01, 0x00, + 0x08, 0xcb, 0x38, 0xea, 0x00, 0x00, 0x00, 0xc7, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0x42, 0xfc, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc7, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x42, 0xfc, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0xbc, 0x0b, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x02, 0x00, 0x04, 0x01, 0x00, 0x6b, + 0x02, 0xe6, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xa2, 0x05, 0x22, 0x01, 0x08, 0xcc, + 0xc8, 0x41, 0xc3, 0x01, 0x00, 0x00, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, 0xa5, + 0xec, 0x1f, 0xdf, 0xc8, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0xb7, 0x47, 0xf1, 0x97, 0xec, 0x12, 0xc8, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0x42, 0x38, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xcb, 0xee, 0x1c, + 0x04, 0xdf, 0x01, 0x00, 0x00, 0xc8, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0x42, 0x38, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x9e, 0x04, 0xdd, 0x01, 0x00, + 0x00, 0x9e, 0xcb, 0xc7, 0x04, 0xf9, 0x01, 0x00, + 0x00, 0xc8, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x42, + 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9e, + 0x04, 0xdd, 0x01, 0x00, 0x00, 0x9e, 0x9e, 0xcf, + 0x28, 0xdc, 0x04, 0xbf, 0x0b, 0x06, 0x0e, 0x5d, + 0x44, 0x59, 0x8a, 0x94, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, 0x22, + 0x02, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xcb, 0xc7, 0x41, 0xc3, 0x01, + 0x00, 0x00, 0x42, 0x5b, 0x00, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0xc7, 0x41, 0xc4, 0x01, 0x00, + 0x00, 0x42, 0x5b, 0x00, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x9c, 0x28, 0xdc, 0x04, 0xc9, 0x0b, + 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, + 0x03, 0x00, 0x05, 0x00, 0x00, 0x32, 0x03, 0xde, + 0x06, 0x00, 0x00, 0x00, 0xe2, 0x06, 0x00, 0x01, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcd, 0xc9, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xcb, 0xc9, 0x41, + 0xc4, 0x01, 0x00, 0x00, 0xcc, 0x38, 0xea, 0x00, + 0x00, 0x00, 0xc7, 0x42, 0xf8, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc8, 0x9b, 0xc7, 0xc8, 0x42, + 0xf8, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9b, + 0x9f, 0xc8, 0xc8, 0x9b, 0x23, 0x02, 0x00, 0xdc, + 0x04, 0xcc, 0x0b, 0x02, 0x0d, 0x49, 0x0e, 0x43, + 0x06, 0x05, 0xc2, 0x05, 0x02, 0x00, 0x02, 0x04, + 0x00, 0x00, 0x4e, 0x02, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0x38, 0xea, + 0x00, 0x00, 0x00, 0x42, 0x90, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xd7, 0x38, 0xea, 0x00, + 0x00, 0x00, 0x42, 0x90, 0x01, 0x00, 0x00, 0xd4, + 0x24, 0x01, 0x00, 0xd8, 0x38, 0xea, 0x00, 0x00, + 0x00, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0xd3, 0x41, + 0xc4, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc3, 0x01, + 0x00, 0x00, 0x9b, 0x9e, 0xd3, 0x41, 0xc4, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0x9b, 0x23, 0x02, 0x00, 0xdc, 0x04, 0xd2, 0x0b, + 0x03, 0x03, 0x4e, 0x4e, 0x0e, 0x43, 0x06, 0x05, + 0xc4, 0x05, 0x02, 0x00, 0x02, 0x04, 0x00, 0x00, + 0x4e, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xea, 0x00, 0x00, + 0x00, 0x42, 0x90, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0xd7, 0x38, 0xea, 0x00, 0x00, 0x00, + 0x42, 0x90, 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, + 0x00, 0xd8, 0x38, 0xea, 0x00, 0x00, 0x00, 0xd3, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x9b, 0xd3, 0x41, 0xc4, 0x01, + 0x00, 0x00, 0xd4, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0x9b, 0x9f, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xd7, 0x0b, 0x03, 0x03, + 0x4e, 0x4e, 0x0e, 0x43, 0x06, 0x05, 0xc6, 0x05, + 0x02, 0x00, 0x02, 0x04, 0x00, 0x00, 0x40, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, + 0x90, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xd7, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, 0x90, + 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0xd8, + 0x38, 0xea, 0x00, 0x00, 0x00, 0xd3, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0x9b, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x9b, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xdc, 0x0b, 0x03, 0x03, + 0x4e, 0x4e, 0x0e, 0x43, 0x06, 0x05, 0xc8, 0x05, + 0x02, 0x00, 0x02, 0x04, 0x00, 0x00, 0x40, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, + 0x90, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xd7, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, 0x90, + 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0xd8, + 0x38, 0xea, 0x00, 0x00, 0x00, 0xd3, 0x41, 0xc3, + 0x01, 0x00, 0x00, 0xd4, 0x41, 0xc4, 0x01, 0x00, + 0x00, 0x9b, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0xd4, 0x41, 0xc3, 0x01, 0x00, 0x00, 0x9b, 0x23, + 0x02, 0x00, 0xdc, 0x04, 0xe1, 0x0b, 0x03, 0x03, + 0x4e, 0x4e, 0x0e, 0x43, 0x06, 0x05, 0xca, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x00, 0x00, 0x3d, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, + 0x90, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xd7, 0x38, 0xea, 0x00, 0x00, 0x00, 0x42, 0x90, + 0x01, 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0xd8, + 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd4, 0x41, + 0xc3, 0x01, 0x00, 0x00, 0xaa, 0x11, 0xec, 0x0f, + 0x0e, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0xd4, + 0x41, 0xc4, 0x01, 0x00, 0x00, 0xaa, 0x28, 0xdc, + 0x04, 0xe6, 0x0b, 0x03, 0x03, 0x4e, 0x4f, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x02, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0x28, 0xdc, 0x04, 0xf5, 0x0b, 0x01, + 0x03, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x01, + 0x01, 0x03, 0x00, 0x00, 0x17, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xcb, 0x38, 0xea, 0x00, 0x00, 0x00, 0xc7, 0x41, + 0xc3, 0x01, 0x00, 0x00, 0x8d, 0xc7, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x23, 0x02, 0x00, 0xdc, 0x04, + 0xf8, 0x0b, 0x01, 0x0d, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00, 0x3e, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xaa, 0x06, + 0x00, 0x00, 0x00, 0xd3, 0x38, 0xea, 0x00, 0x00, + 0x00, 0xa8, 0xec, 0x03, 0xd3, 0x28, 0x38, 0x97, + 0x00, 0x00, 0x00, 0x42, 0xa9, 0x01, 0x00, 0x00, + 0x38, 0xea, 0x00, 0x00, 0x00, 0x41, 0x3c, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xcf, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x43, 0xc3, 0x01, + 0x00, 0x00, 0xc7, 0x38, 0xe8, 0x00, 0x00, 0x00, + 0xb8, 0xf1, 0x43, 0xc4, 0x01, 0x00, 0x00, 0xc7, + 0x28, 0xdc, 0x04, 0x8a, 0x0c, 0x07, 0x04, 0x30, + 0x08, 0x08, 0x7b, 0x3f, 0x44, 0x0e, 0x43, 0x06, + 0x05, 0xcc, 0x05, 0x01, 0x02, 0x01, 0x02, 0x00, + 0x00, 0x19, 0x03, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xae, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0xeb, 0xcc, 0xb7, 0xcb, 0xc7, + 0xc8, 0xa4, 0xec, 0x0e, 0xd3, 0xc7, 0x47, 0xb7, + 0xab, 0xec, 0x03, 0xc7, 0x28, 0x94, 0x00, 0xee, + 0xef, 0xc8, 0x28, 0xdc, 0x04, 0x9a, 0x0c, 0x06, + 0x04, 0x12, 0x26, 0x26, 0x0d, 0x17, 0x0e, 0x43, + 0x06, 0x05, 0xce, 0x05, 0x01, 0x00, 0x01, 0x02, + 0x01, 0x00, 0x0f, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xa0, 0x05, 0x21, 0x01, 0xdf, 0xd3, 0xf1, + 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0xa8, 0x28, 0xdc, 0x04, 0xa4, 0x0c, + 0x02, 0x04, 0x26, 0x0e, 0x43, 0x06, 0x05, 0xd6, + 0x03, 0x02, 0x04, 0x02, 0x05, 0x02, 0x00, 0x86, + 0x01, 0x06, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xde, + 0x06, 0x00, 0x01, 0x00, 0xf4, 0x07, 0x00, 0x00, + 0x00, 0xd6, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, + 0x00, 0x02, 0x00, 0xd6, 0x03, 0x00, 0x01, 0x14, + 0xce, 0x05, 0x38, 0x01, 0xcc, 0x05, 0x37, 0x01, + 0x0c, 0x02, 0xce, 0xd3, 0xca, 0xa8, 0xec, 0x03, + 0xd3, 0x28, 0xdf, 0xd3, 0xf1, 0xec, 0x52, 0xd4, + 0xb7, 0xa5, 0xec, 0x0c, 0xca, 0x42, 0x91, 0x01, + 0x00, 0x00, 0xb7, 0xb7, 0x25, 0x02, 0x00, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, 0xe0, + 0xd3, 0xf1, 0xcb, 0xca, 0x42, 0x91, 0x01, 0x00, + 0x00, 0xd4, 0xc7, 0x24, 0x02, 0x00, 0xcc, 0x38, + 0x9f, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x01, 0x00, + 0x00, 0xd3, 0xeb, 0xc7, 0x9f, 0xd4, 0x24, 0x02, + 0x00, 0xd8, 0xb7, 0xcd, 0xc9, 0xd4, 0xa4, 0xec, + 0x0e, 0xc8, 0xc9, 0x73, 0xd3, 0xc9, 0xc7, 0x9e, + 0x47, 0x49, 0x94, 0x02, 0xee, 0xef, 0xc8, 0x28, + 0xd3, 0x38, 0xea, 0x00, 0x00, 0x00, 0xa8, 0xec, + 0x12, 0xca, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0xd4, 0xf2, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0x9c, 0x28, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, + 0xbf, 0x01, 0x00, 0x00, 0xf1, 0x2f, 0xdc, 0x04, + 0xab, 0x0c, 0x10, 0x14, 0x1c, 0x08, 0x21, 0x1d, + 0x3b, 0x2b, 0x17, 0x3f, 0x62, 0x26, 0x44, 0x09, + 0x35, 0x53, 0x08, 0x0e, 0x43, 0x06, 0x05, 0xd0, + 0x05, 0x02, 0x0a, 0x02, 0x05, 0x02, 0x00, 0x95, + 0x02, 0x0c, 0xf8, 0x07, 0x00, 0x01, 0x00, 0xfa, + 0x07, 0x00, 0x01, 0x00, 0xea, 0x07, 0x00, 0x00, + 0x00, 0xe2, 0x06, 0x00, 0x01, 0x00, 0xf4, 0x07, + 0x00, 0x02, 0x00, 0xde, 0x06, 0x00, 0x03, 0x00, + 0xd6, 0x06, 0x00, 0x04, 0x00, 0xae, 0x06, 0x00, + 0x05, 0x00, 0xc2, 0x06, 0x00, 0x06, 0x00, 0xfc, + 0x07, 0x00, 0x07, 0x00, 0xfe, 0x07, 0x00, 0x08, + 0x00, 0x80, 0x08, 0x00, 0x09, 0x00, 0xce, 0x05, + 0x38, 0x01, 0xcc, 0x05, 0x37, 0x01, 0xd3, 0x38, + 0xeb, 0x00, 0x00, 0x00, 0xa8, 0x97, 0xec, 0x07, + 0xd3, 0xcb, 0xd4, 0xd7, 0xc7, 0xd8, 0xd3, 0x41, + 0xfa, 0x01, 0x00, 0x00, 0xd3, 0xeb, 0x9e, 0xcc, + 0xdf, 0xd4, 0xf1, 0xec, 0x15, 0x38, 0xe8, 0x00, + 0x00, 0x00, 0xd4, 0xf1, 0xd8, 0xc8, 0xb7, 0xa5, + 0xec, 0x03, 0xd3, 0x28, 0xb7, 0xc5, 0x07, 0xee, + 0x56, 0xd4, 0x38, 0xea, 0x00, 0x00, 0x00, 0xa8, + 0xec, 0x31, 0xe0, 0xd4, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0xf1, 0xe0, 0xd4, 0x41, 0xc4, 0x01, 0x00, + 0x00, 0xf1, 0x9f, 0xc5, 0x05, 0xc8, 0xc4, 0x05, + 0xa5, 0xec, 0x03, 0xd3, 0x28, 0x38, 0xeb, 0x00, + 0x00, 0x00, 0xd4, 0xc8, 0xc4, 0x05, 0x9f, 0xf2, + 0xdc, 0x41, 0xfa, 0x01, 0x00, 0x00, 0xc5, 0x07, + 0xee, 0x1d, 0xd4, 0x41, 0xfa, 0x01, 0x00, 0x00, + 0xc5, 0x07, 0x38, 0x9f, 0x00, 0x00, 0x00, 0x42, + 0xfb, 0x01, 0x00, 0x00, 0xc8, 0xc4, 0x07, 0xd4, + 0xeb, 0x9e, 0x24, 0x02, 0x00, 0xcc, 0x38, 0x9f, + 0x00, 0x00, 0x00, 0x42, 0xfb, 0x01, 0x00, 0x00, + 0xd3, 0x41, 0xfa, 0x01, 0x00, 0x00, 0xc4, 0x07, + 0x24, 0x02, 0x00, 0xcd, 0xc8, 0xc9, 0x9f, 0xce, + 0x38, 0xeb, 0x00, 0x00, 0x00, 0x42, 0x91, 0x01, + 0x00, 0x00, 0xca, 0xc9, 0x24, 0x02, 0x00, 0xc5, + 0x04, 0xc9, 0xc5, 0x05, 0xc4, 0x05, 0xc8, 0xa4, + 0xec, 0x50, 0xc4, 0x05, 0xd3, 0x41, 0xfa, 0x01, + 0x00, 0x00, 0x9f, 0xc6, 0x06, 0xb7, 0xa7, 0xec, + 0x10, 0xc4, 0x06, 0xd3, 0xeb, 0xa4, 0xec, 0x09, + 0xd3, 0xc4, 0x06, 0x47, 0xc5, 0x08, 0xee, 0x04, + 0xb7, 0xc5, 0x08, 0xc4, 0x05, 0xc4, 0x07, 0x9f, + 0xc6, 0x06, 0xb7, 0xa7, 0xec, 0x10, 0xc4, 0x06, + 0xd4, 0xeb, 0xa4, 0xec, 0x09, 0xd4, 0xc4, 0x06, + 0x47, 0xc5, 0x09, 0xee, 0x04, 0xb7, 0xc5, 0x09, + 0xc4, 0x04, 0xc4, 0x05, 0xc9, 0x9f, 0x73, 0xc4, + 0x08, 0xc4, 0x09, 0x9e, 0x49, 0x94, 0x05, 0xee, + 0xac, 0xc4, 0x04, 0x42, 0x8d, 0x01, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xdc, 0x04, 0xc4, 0x0c, 0x22, + 0x04, 0x35, 0x0d, 0x0d, 0x0e, 0x35, 0x1c, 0x2b, + 0x1c, 0x0d, 0x12, 0x3b, 0x62, 0x21, 0x0e, 0x3f, + 0x26, 0x0d, 0x2b, 0x68, 0x71, 0x17, 0x59, 0x30, + 0x3a, 0x3a, 0x2c, 0x12, 0x26, 0x3a, 0x2c, 0x12, + 0x44, 0x17, 0x0e, 0x43, 0x06, 0x05, 0xd2, 0x05, + 0x02, 0x00, 0x02, 0x03, 0x01, 0x00, 0x07, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0xd0, 0x05, 0x39, 0x01, 0xdf, 0xd3, + 0xd4, 0x8d, 0x23, 0x02, 0x00, 0xdc, 0x04, 0xf0, + 0x0c, 0x01, 0x03, 0x0e, 0x43, 0x06, 0x05, 0xd4, + 0x05, 0x02, 0x08, 0x02, 0x06, 0x00, 0x00, 0xa9, + 0x01, 0x0a, 0xf8, 0x07, 0x00, 0x01, 0x00, 0xfa, + 0x07, 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, 0x00, + 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0xc2, 0x06, + 0x00, 0x02, 0x00, 0xd6, 0x06, 0x00, 0x03, 0x00, + 0xf4, 0x07, 0x00, 0x04, 0x00, 0xfc, 0x06, 0x00, + 0x05, 0x00, 0xec, 0x07, 0x00, 0x06, 0x00, 0xc6, + 0x06, 0x00, 0x07, 0x00, 0xd3, 0x38, 0xeb, 0x00, + 0x00, 0x00, 0xa8, 0x97, 0xec, 0x0d, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0xd3, 0xd4, 0xeb, 0xf2, 0xd7, + 0xee, 0x15, 0xd4, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x0b, 0x38, 0xeb, 0x00, 0x00, + 0x00, 0xd4, 0xd3, 0xeb, 0xf2, 0xd8, 0xd3, 0x41, + 0xfa, 0x01, 0x00, 0x00, 0xd4, 0x41, 0xfa, 0x01, + 0x00, 0x00, 0x9e, 0xc5, 0x04, 0x38, 0x9f, 0x00, + 0x00, 0x00, 0x42, 0xfb, 0x01, 0x00, 0x00, 0xd3, + 0xeb, 0xd4, 0xeb, 0x24, 0x02, 0x00, 0xcb, 0xd3, + 0xeb, 0xc5, 0x05, 0xd4, 0xeb, 0xc5, 0x06, 0x38, + 0xeb, 0x00, 0x00, 0x00, 0x42, 0x91, 0x01, 0x00, + 0x00, 0xc7, 0xc4, 0x04, 0x24, 0x02, 0x00, 0xce, + 0xb7, 0xcc, 0xc8, 0xc4, 0x05, 0xa4, 0xec, 0x35, + 0x38, 0x9f, 0x00, 0x00, 0x00, 0x42, 0xfb, 0x01, + 0x00, 0x00, 0xc4, 0x06, 0xc7, 0xc8, 0x9f, 0x24, + 0x02, 0x00, 0xc5, 0x07, 0xb7, 0xcd, 0xc9, 0xc4, + 0x07, 0xa4, 0xec, 0x15, 0xca, 0xc8, 0xc9, 0x9e, + 0x73, 0x13, 0x47, 0xd3, 0xc8, 0x47, 0xd4, 0xc9, + 0x47, 0x9b, 0x9e, 0x49, 0x94, 0x02, 0xee, 0xe7, + 0x94, 0x01, 0xee, 0xc7, 0xca, 0x42, 0x8d, 0x01, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xf3, + 0x0c, 0x10, 0x04, 0x35, 0x3f, 0x35, 0x35, 0x4e, + 0x5d, 0x17, 0x17, 0x58, 0x2b, 0x67, 0x2b, 0x53, + 0x17, 0x17, 0x0e, 0x43, 0x06, 0x05, 0xd6, 0x05, + 0x02, 0x00, 0x02, 0x04, 0x01, 0x00, 0x22, 0x02, + 0xf8, 0x07, 0x00, 0x01, 0x00, 0xfa, 0x07, 0x00, + 0x01, 0x00, 0xd4, 0x05, 0x3b, 0x01, 0xd4, 0x38, + 0xeb, 0x00, 0x00, 0x00, 0xa8, 0x97, 0xec, 0x0b, + 0x38, 0xeb, 0x00, 0x00, 0x00, 0xd4, 0xd3, 0xeb, + 0xf2, 0xd8, 0xdf, 0xd3, 0xd4, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x23, 0x02, 0x00, + 0xdc, 0x04, 0x86, 0x0d, 0x03, 0x03, 0x35, 0x35, + 0x0e, 0x43, 0x06, 0x05, 0xd8, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x01, 0x00, 0x3b, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xe2, 0x04, 0x02, 0x01, 0x38, 0xe3, 0x00, 0x00, + 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, 0xd4, 0x24, + 0x01, 0x00, 0xec, 0x07, 0xdf, 0xd3, 0xd4, 0x23, + 0x02, 0x00, 0xd3, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0xa8, 0x97, 0xec, 0x0b, 0x38, 0xeb, 0x00, 0x00, + 0x00, 0xd3, 0xd4, 0xeb, 0xf2, 0xd7, 0x38, 0x03, + 0x01, 0x00, 0x00, 0x38, 0x04, 0x01, 0x00, 0x00, + 0xd3, 0xf1, 0xd4, 0x9b, 0x23, 0x01, 0x00, 0xdc, + 0x04, 0x8b, 0x0d, 0x05, 0x03, 0x53, 0x22, 0x35, + 0x35, 0x0e, 0x43, 0x06, 0x05, 0xda, 0x05, 0x02, + 0x02, 0x02, 0x03, 0x00, 0x00, 0x33, 0x04, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, + 0x00, 0x01, 0x00, 0xd3, 0x41, 0xfa, 0x01, 0x00, + 0x00, 0xd4, 0x41, 0xfa, 0x01, 0x00, 0x00, 0xab, + 0xec, 0x03, 0x09, 0x28, 0xd3, 0xeb, 0xcf, 0xd4, + 0xeb, 0xab, 0xec, 0x03, 0x09, 0x28, 0xb7, 0xcc, + 0xc8, 0xc7, 0xa4, 0xec, 0x10, 0xd3, 0xc8, 0x47, + 0xd4, 0xc8, 0x47, 0xab, 0xec, 0x03, 0x09, 0x28, + 0x94, 0x01, 0xee, 0xed, 0x0a, 0x28, 0xdc, 0x04, + 0x94, 0x0d, 0x0a, 0x04, 0x4e, 0x0d, 0x12, 0x1c, + 0x0d, 0x26, 0x30, 0x0d, 0x17, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x02, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, + 0x28, 0xdc, 0x04, 0xaa, 0x0d, 0x01, 0x03, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x03, 0x01, 0x04, + 0x00, 0x00, 0x2e, 0x04, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xaa, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, + 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, 0x02, 0x00, + 0xd3, 0xeb, 0xcc, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0x42, 0x91, 0x01, 0x00, 0x00, 0xd3, 0xeb, 0xd3, + 0x41, 0xfa, 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, + 0xcb, 0xb7, 0xcd, 0xc9, 0xc8, 0xa4, 0xec, 0x0d, + 0xc7, 0xc9, 0x73, 0xd3, 0xc9, 0x47, 0x8d, 0x49, + 0x94, 0x02, 0xee, 0xf0, 0xc7, 0x28, 0xdc, 0x04, + 0xad, 0x0d, 0x06, 0x04, 0x12, 0x71, 0x26, 0x2b, + 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x04, + 0x00, 0x04, 0x00, 0x00, 0x37, 0x04, 0xaa, 0x06, + 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, + 0xae, 0x06, 0x00, 0x02, 0x00, 0x10, 0x00, 0x01, + 0x00, 0x08, 0xce, 0xca, 0xeb, 0xcc, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0x42, 0x91, 0x01, 0x00, 0x00, + 0xca, 0xeb, 0xca, 0x41, 0xfa, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xcb, 0xb7, 0xcd, 0xc9, 0xc8, + 0xa4, 0xec, 0x14, 0xc7, 0xc9, 0x73, 0xca, 0xc9, + 0x47, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x49, 0x94, 0x02, 0xee, 0xe9, 0xc7, 0x28, + 0xdc, 0x04, 0xc2, 0x0d, 0x06, 0x0e, 0x12, 0x71, + 0x26, 0x4e, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x6e, 0x07, + 0xd6, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xae, 0x06, 0x00, 0x02, 0x00, 0xc2, + 0x06, 0x00, 0x03, 0x00, 0x82, 0x08, 0x00, 0x04, + 0x00, 0xf8, 0x07, 0x00, 0x05, 0x00, 0x10, 0x00, + 0x01, 0x00, 0x08, 0xc5, 0x06, 0xc4, 0x06, 0xc6, + 0x05, 0xeb, 0xd0, 0xb7, 0xaa, 0xec, 0x0d, 0x38, + 0xce, 0x00, 0x00, 0x00, 0x04, 0xc2, 0x01, 0x00, + 0x00, 0xf1, 0x2f, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0x42, 0x91, 0x01, 0x00, 0x00, 0xc8, 0xc4, 0x05, + 0x41, 0xfa, 0x01, 0x00, 0x00, 0x8d, 0x24, 0x02, + 0x00, 0xcf, 0xb7, 0x73, 0xb8, 0xc4, 0x05, 0xb7, + 0x47, 0x9c, 0x49, 0xb8, 0xcd, 0xc9, 0xc8, 0xa4, + 0xec, 0x2d, 0xb7, 0xc5, 0x04, 0xb8, 0xce, 0xca, + 0xc9, 0xa5, 0xec, 0x14, 0xc4, 0x04, 0xc4, 0x05, + 0xca, 0x47, 0xc7, 0xc9, 0xca, 0x9f, 0x47, 0x9b, + 0x9e, 0xc5, 0x04, 0x94, 0x03, 0xee, 0xe9, 0xc7, + 0xc9, 0x73, 0xc4, 0x04, 0x8d, 0xc7, 0xb7, 0x47, + 0x9b, 0x49, 0x94, 0x02, 0xee, 0xd0, 0xc7, 0x28, + 0xdc, 0x04, 0xcb, 0x0d, 0x0e, 0x12, 0x0d, 0x17, + 0x17, 0x3f, 0x76, 0x30, 0x26, 0x12, 0x26, 0x4e, + 0x17, 0x3a, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x5a, 0x06, + 0xae, 0x06, 0x00, 0x00, 0x00, 0xc2, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, 0x00, 0xd6, + 0x06, 0x00, 0x03, 0x00, 0xf8, 0x07, 0x00, 0x04, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xc5, 0x05, + 0xc4, 0x05, 0xc6, 0x04, 0xeb, 0xcd, 0xb7, 0xcb, + 0xc7, 0xc9, 0xa4, 0xec, 0x0d, 0xc4, 0x04, 0xc7, + 0x47, 0xb7, 0xaa, 0xec, 0x05, 0x94, 0x00, 0xee, + 0xf0, 0xc7, 0xb7, 0xaa, 0xec, 0x04, 0xc4, 0x04, + 0x28, 0xc7, 0xcc, 0xc8, 0xc9, 0xa4, 0xec, 0x10, + 0xc4, 0x04, 0xc8, 0xc7, 0x9f, 0x73, 0xc4, 0x04, + 0xc8, 0x47, 0x49, 0x94, 0x01, 0xee, 0xed, 0xc4, + 0x04, 0xc9, 0xc7, 0x9f, 0x43, 0x30, 0x00, 0x00, + 0x00, 0xc4, 0x04, 0x41, 0x45, 0x00, 0x00, 0x00, + 0x42, 0xfa, 0x01, 0x00, 0x00, 0xc7, 0x9e, 0x43, + 0xfa, 0x01, 0x00, 0x00, 0xc4, 0x04, 0x28, 0xdc, + 0x04, 0xdc, 0x0d, 0x0c, 0x12, 0x0d, 0x17, 0x0d, + 0x44, 0x17, 0x1c, 0x12, 0x26, 0x4e, 0x35, 0x62, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x09, 0x00, + 0x06, 0x01, 0x00, 0x75, 0x09, 0xae, 0x06, 0x00, + 0x00, 0x00, 0xc2, 0x06, 0x00, 0x01, 0x00, 0xe6, + 0x07, 0x00, 0x02, 0x00, 0xbc, 0x07, 0x00, 0x03, + 0x00, 0xf4, 0x06, 0x00, 0x04, 0x00, 0xc0, 0x06, + 0x00, 0x05, 0x00, 0xf4, 0x07, 0x00, 0x06, 0x00, + 0xde, 0x06, 0x00, 0x07, 0x00, 0x10, 0x00, 0x01, + 0x00, 0xa4, 0x05, 0x23, 0x01, 0x08, 0xc5, 0x08, + 0xc4, 0x08, 0xc5, 0x05, 0xc3, 0xcd, 0xc4, 0x08, + 0x41, 0xfa, 0x01, 0x00, 0x00, 0xc5, 0x06, 0xc4, + 0x08, 0xeb, 0xc5, 0x07, 0xb7, 0xcc, 0xc8, 0xc4, + 0x07, 0xa4, 0xec, 0x33, 0xc8, 0xc4, 0x06, 0x9e, + 0xcb, 0xc4, 0x05, 0xc8, 0x47, 0xc6, 0x04, 0xb7, + 0xab, 0xec, 0x20, 0xdf, 0xc4, 0x04, 0xc7, 0xf2, + 0xd2, 0xb7, 0x47, 0x04, 0x7b, 0x01, 0x00, 0x00, + 0xab, 0xec, 0x0d, 0xc9, 0xc3, 0xab, 0xec, 0x08, + 0x04, 0x7a, 0x01, 0x00, 0x00, 0x95, 0x02, 0xca, + 0x95, 0x02, 0x94, 0x01, 0xee, 0xc9, 0xc9, 0xc3, + 0xab, 0xec, 0x08, 0x04, 0x7a, 0x01, 0x00, 0x00, + 0x95, 0x02, 0xc9, 0x04, 0x02, 0x02, 0x00, 0x00, + 0xdf, 0xb8, 0xc4, 0x07, 0xc4, 0x06, 0x9e, 0xf2, + 0x9e, 0x04, 0xdd, 0x01, 0x00, 0x00, 0x9e, 0x9e, + 0xd1, 0x28, 0xdc, 0x04, 0xea, 0x0d, 0x12, 0x12, + 0x17, 0x0d, 0x30, 0x1c, 0x2b, 0x1c, 0x21, 0x17, + 0x21, 0x35, 0x1c, 0x27, 0x13, 0x17, 0x1c, 0x26, + 0x76, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x05, + 0x01, 0x03, 0x00, 0x00, 0x3c, 0x06, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, 0x00, 0x00, + 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x02, 0x00, 0xc0, 0x06, 0x00, 0x03, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc5, 0x04, 0xc4, 0x04, + 0xd2, 0xeb, 0xd0, 0xb7, 0xaa, 0xec, 0x03, 0xb7, + 0x28, 0xca, 0xc8, 0x8f, 0xd0, 0x47, 0xcd, 0xc8, + 0xb7, 0xa6, 0xec, 0x0d, 0x93, 0x01, 0xc9, 0xd3, + 0x9b, 0xca, 0xc8, 0x47, 0x9e, 0xcd, 0xee, 0xf0, + 0xca, 0x41, 0xfa, 0x01, 0x00, 0x00, 0xb7, 0xab, + 0xec, 0x0c, 0xc9, 0xd3, 0xca, 0x41, 0xfa, 0x01, + 0x00, 0x00, 0xa0, 0x9b, 0xcd, 0xc9, 0x28, 0xdc, + 0x04, 0x80, 0x0e, 0x0c, 0x12, 0x0d, 0x12, 0x17, + 0x0d, 0x21, 0x1c, 0x0d, 0x2b, 0x0d, 0x35, 0x3a, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x07, 0x00, + 0x05, 0x00, 0x00, 0x6d, 0x07, 0xc0, 0x06, 0x00, + 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, 0xf4, + 0x07, 0x00, 0x02, 0x00, 0xd6, 0x06, 0x00, 0x03, + 0x00, 0xae, 0x06, 0x00, 0x04, 0x00, 0xc2, 0x06, + 0x00, 0x05, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc5, 0x06, 0xc4, 0x06, 0xcf, 0xeb, 0xcc, 0xc7, + 0x41, 0xfa, 0x01, 0x00, 0x00, 0xcd, 0xc8, 0xb7, + 0xaa, 0xec, 0x15, 0xc9, 0xb7, 0xaa, 0xec, 0x10, + 0x38, 0xeb, 0x00, 0x00, 0x00, 0x42, 0x91, 0x01, + 0x00, 0x00, 0xb7, 0xb7, 0x25, 0x02, 0x00, 0x38, + 0xeb, 0x00, 0x00, 0x00, 0x42, 0x91, 0x01, 0x00, + 0x00, 0xc8, 0xc9, 0xb8, 0x9f, 0x24, 0x02, 0x00, + 0xce, 0xb7, 0xc5, 0x04, 0xc4, 0x04, 0xc8, 0xa4, + 0xec, 0x22, 0xc9, 0xc4, 0x04, 0x9e, 0xc6, 0x05, + 0xb7, 0xaa, 0xec, 0x08, 0xca, 0xc4, 0x04, 0xb7, + 0x49, 0xee, 0x0d, 0xca, 0xc4, 0x04, 0x73, 0xc4, + 0x05, 0xc7, 0xc4, 0x04, 0x47, 0x9b, 0x49, 0x94, + 0x04, 0xee, 0xda, 0xca, 0x42, 0x8d, 0x01, 0x00, + 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0x8e, 0x0e, + 0x0b, 0x12, 0x3f, 0x35, 0x4f, 0x5d, 0x30, 0x21, + 0x17, 0x27, 0x3f, 0x17, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x00, 0x07, 0x00, 0x05, 0x00, 0x00, 0x60, + 0x07, 0xc0, 0x06, 0x00, 0x00, 0x00, 0xde, 0x06, + 0x00, 0x01, 0x00, 0xf4, 0x07, 0x00, 0x02, 0x00, + 0xae, 0x06, 0x00, 0x03, 0x00, 0xc2, 0x06, 0x00, + 0x04, 0x00, 0xd6, 0x06, 0x00, 0x05, 0x00, 0x10, + 0x00, 0x01, 0x00, 0x08, 0xc5, 0x06, 0xc4, 0x06, + 0xcf, 0xeb, 0xcc, 0xc7, 0x41, 0xfa, 0x01, 0x00, + 0x00, 0xcd, 0x38, 0xeb, 0x00, 0x00, 0x00, 0x42, + 0x91, 0x01, 0x00, 0x00, 0xc8, 0xc9, 0xb8, 0x9e, + 0x24, 0x02, 0x00, 0xc5, 0x05, 0xb7, 0xce, 0xca, + 0xc8, 0xa4, 0xec, 0x2e, 0xc9, 0xca, 0x9e, 0xc6, + 0x04, 0xb6, 0xaa, 0xec, 0x14, 0xc7, 0xca, 0x47, + 0xb7, 0xab, 0xec, 0x1a, 0x38, 0xce, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x02, 0x00, 0x00, 0xf1, 0x2f, + 0xc4, 0x05, 0xca, 0x73, 0xc7, 0xca, 0x47, 0xc4, + 0x04, 0xb8, 0x9e, 0x9c, 0x49, 0x94, 0x03, 0xee, + 0xcf, 0xc4, 0x05, 0x42, 0x8d, 0x01, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xdc, 0x04, 0x9e, 0x0e, 0x0b, + 0x12, 0x3f, 0x62, 0x26, 0x1c, 0x17, 0x26, 0x3a, + 0x08, 0x45, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x00, 0x06, 0x00, 0x05, 0x01, 0x00, 0x8b, 0x01, + 0x06, 0xf4, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, + 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x02, 0x00, + 0xde, 0x06, 0x00, 0x03, 0x00, 0xc0, 0x06, 0x00, + 0x04, 0x00, 0x10, 0x00, 0x01, 0x00, 0xde, 0x01, + 0x00, 0x03, 0x08, 0xc5, 0x05, 0xc4, 0x05, 0xc6, + 0x04, 0x41, 0xfa, 0x01, 0x00, 0x00, 0xb7, 0xa4, + 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, 0x00, 0x04, + 0x04, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xc4, 0x04, + 0x41, 0xfa, 0x01, 0x00, 0x00, 0xc4, 0x04, 0xeb, + 0x9e, 0xce, 0xc4, 0x04, 0x41, 0xfa, 0x01, 0x00, + 0x00, 0xb7, 0xa6, 0x11, 0xed, 0x08, 0x0e, 0xc4, + 0x04, 0xb7, 0x47, 0xb7, 0xaa, 0xec, 0x05, 0xb8, + 0xcb, 0xee, 0x18, 0xdf, 0x42, 0x03, 0x01, 0x00, + 0x00, 0xc4, 0x04, 0xb7, 0x47, 0x24, 0x01, 0x00, + 0xcb, 0xc4, 0x04, 0xc4, 0x04, 0xb7, 0x47, 0x9f, + 0xc5, 0x04, 0x38, 0xeb, 0x00, 0x00, 0x00, 0x42, + 0x91, 0x01, 0x00, 0x00, 0xca, 0xb7, 0x24, 0x02, + 0x00, 0xcd, 0xb7, 0xcc, 0xc8, 0xca, 0xa4, 0xec, + 0x12, 0xc9, 0xc8, 0x73, 0xc7, 0x38, 0xf1, 0x00, + 0x00, 0x00, 0xc8, 0xf1, 0x9c, 0x49, 0x94, 0x01, + 0xee, 0xeb, 0xc9, 0x42, 0x5b, 0x00, 0x00, 0x00, + 0xc4, 0x04, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xac, + 0x0e, 0x0e, 0x12, 0x0d, 0x3a, 0x3f, 0x3f, 0x6c, + 0x0d, 0x0d, 0x49, 0x31, 0x53, 0x26, 0x44, 0x17, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x00, 0x03, 0x00, + 0x05, 0x01, 0x00, 0x38, 0x03, 0xc0, 0x06, 0x00, + 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, 0x00, 0x10, + 0x00, 0x01, 0x00, 0xde, 0x01, 0x00, 0x03, 0x08, + 0xcd, 0xc9, 0xcf, 0x41, 0xfa, 0x01, 0x00, 0x00, + 0xb7, 0xab, 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, + 0x00, 0x04, 0x05, 0x02, 0x00, 0x00, 0xf1, 0x2f, + 0x38, 0xf9, 0x00, 0x00, 0x00, 0x38, 0xf8, 0x00, + 0x00, 0x00, 0xc7, 0xf1, 0xc7, 0x9c, 0xf1, 0xd0, + 0xdf, 0x42, 0x04, 0x01, 0x00, 0x00, 0xc7, 0xb7, + 0x47, 0x24, 0x01, 0x00, 0x9e, 0xd0, 0x28, 0xdc, + 0x04, 0xbd, 0x0e, 0x06, 0x0d, 0x08, 0x35, 0x3f, + 0x54, 0x49, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, + 0x03, 0x02, 0x04, 0x00, 0x00, 0x43, 0x05, 0xde, + 0x06, 0x00, 0x01, 0x00, 0xf4, 0x07, 0x00, 0x01, + 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, + 0x00, 0x01, 0x00, 0xaa, 0x06, 0x00, 0x02, 0x00, + 0x26, 0x00, 0x00, 0xcb, 0xb7, 0xcc, 0xc8, 0xd3, + 0xa4, 0xec, 0x09, 0xc7, 0xc8, 0xb7, 0x49, 0x94, + 0x01, 0xee, 0xf4, 0x38, 0x97, 0x00, 0x00, 0x00, + 0x42, 0xa9, 0x01, 0x00, 0x00, 0x38, 0xeb, 0x00, + 0x00, 0x00, 0x41, 0x3c, 0x00, 0x00, 0x00, 0x24, + 0x01, 0x00, 0xd1, 0xd4, 0x43, 0xfa, 0x01, 0x00, + 0x00, 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0x61, + 0x00, 0x00, 0x00, 0xc7, 0xc9, 0x24, 0x02, 0x00, + 0x0e, 0xc7, 0x28, 0xdc, 0x04, 0xca, 0x0e, 0x07, + 0x05, 0x17, 0x26, 0x2c, 0x7b, 0x21, 0x53, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x02, 0x01, 0x04, + 0x01, 0x01, 0x6b, 0x03, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0x8c, 0x08, 0x00, 0x00, 0x00, 0xde, 0x06, + 0x00, 0x01, 0x00, 0xce, 0x05, 0x38, 0x01, 0xc2, + 0x00, 0xcb, 0xdf, 0xd3, 0xf1, 0xec, 0x19, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xdb, 0x42, + 0x8e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xd0, + 0xb7, 0xa4, 0xec, 0x40, 0xc7, 0xf0, 0x2f, 0xd3, + 0x38, 0xea, 0x00, 0x00, 0x00, 0xa8, 0xec, 0x31, + 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, 0x42, 0x8e, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xb7, 0xab, + 0xec, 0x04, 0xc7, 0xf0, 0x2f, 0xd3, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x42, 0x8e, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xd0, 0xb7, 0xa4, 0xec, 0x04, + 0xc7, 0xf0, 0x2f, 0xc8, 0x8d, 0xcc, 0xee, 0x04, + 0xc7, 0xf0, 0x2f, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0x42, 0x91, 0x01, 0x00, 0x00, 0xb7, 0xc8, 0x25, + 0x02, 0x00, 0xdc, 0x04, 0xd6, 0x0e, 0x11, 0x00, + 0x03, 0x0a, 0x1c, 0x2b, 0x30, 0x17, 0x0d, 0x35, + 0x5d, 0x12, 0x4e, 0x17, 0x12, 0x12, 0x0d, 0x12, + 0x0e, 0x43, 0x06, 0x05, 0x8c, 0x08, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0x07, 0x02, 0x00, 0x00, + 0x23, 0x01, 0x00, 0xdc, 0x04, 0xd7, 0x0e, 0x01, + 0x03, 0x0e, 0x43, 0x06, 0x05, 0xd8, 0x03, 0x02, + 0x04, 0x02, 0x03, 0x00, 0x00, 0x2e, 0x06, 0x90, + 0x08, 0x00, 0x01, 0x00, 0x92, 0x08, 0x00, 0x01, + 0x00, 0xae, 0x06, 0x00, 0x00, 0x00, 0xc2, 0x06, + 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x02, 0x00, + 0x94, 0x08, 0x00, 0x03, 0x00, 0xd4, 0xf6, 0xec, + 0x03, 0xd3, 0xd8, 0x26, 0x00, 0x00, 0xcd, 0xb7, + 0xcb, 0xc7, 0xd3, 0xa4, 0xec, 0x1c, 0x26, 0x00, + 0x00, 0xce, 0xb7, 0xcc, 0xc8, 0xd4, 0xa4, 0xec, + 0x09, 0xca, 0xc8, 0xb7, 0x49, 0x94, 0x01, 0xee, + 0xf4, 0xc9, 0xc7, 0xca, 0x49, 0x94, 0x00, 0xee, + 0xe1, 0xc9, 0x28, 0xdc, 0x04, 0xef, 0x0e, 0x0a, + 0x04, 0x17, 0x0d, 0x17, 0x26, 0x17, 0x26, 0x2b, + 0x17, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, + 0x02, 0x01, 0x03, 0x00, 0x00, 0x1c, 0x03, 0xde, + 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, + 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0x38, 0xec, + 0x00, 0x00, 0x00, 0xd3, 0xd3, 0xf2, 0xcb, 0xb7, + 0xcc, 0xc8, 0xd3, 0xa4, 0xec, 0x0b, 0xc7, 0xc8, + 0x47, 0xc8, 0xb8, 0x49, 0x94, 0x01, 0xee, 0xf2, + 0xc7, 0x28, 0xdc, 0x04, 0xfe, 0x0e, 0x04, 0x04, + 0x30, 0x26, 0x35, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x22, 0x04, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x00, 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0xde, + 0x06, 0x00, 0x02, 0x00, 0xd3, 0xeb, 0xcd, 0x38, + 0xec, 0x00, 0x00, 0x00, 0xc9, 0xc9, 0xf2, 0xcb, + 0xb7, 0xcc, 0xc8, 0xc9, 0xa4, 0xec, 0x0e, 0xc7, + 0xc8, 0x47, 0xc8, 0x73, 0xd3, 0xc8, 0x47, 0x49, + 0x94, 0x01, 0xee, 0xef, 0xc7, 0x28, 0xdc, 0x04, + 0x85, 0x0f, 0x05, 0x04, 0x12, 0x30, 0x26, 0x44, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x03, 0x01, + 0x05, 0x00, 0x00, 0x2d, 0x04, 0xde, 0x06, 0x00, + 0x01, 0x00, 0xae, 0x06, 0x00, 0x00, 0x00, 0xc2, + 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x02, + 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xcd, 0xb7, 0xcb, 0xc7, 0xd3, 0xa4, 0xec, 0x1d, + 0xb7, 0xcc, 0xc8, 0xd3, 0xa4, 0xec, 0x12, 0xc9, + 0xc7, 0x47, 0xc8, 0x73, 0xb8, 0xb8, 0xc7, 0x9e, + 0xc8, 0x9e, 0x9c, 0x49, 0x94, 0x01, 0xee, 0xeb, + 0x94, 0x00, 0xee, 0xe0, 0xc9, 0x28, 0xdc, 0x04, + 0x8d, 0x0f, 0x07, 0x04, 0x2b, 0x26, 0x26, 0x44, + 0x17, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, + 0x05, 0x01, 0x04, 0x00, 0x00, 0x87, 0x01, 0x06, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0x90, 0x08, 0x00, + 0x00, 0x00, 0x92, 0x08, 0x00, 0x01, 0x00, 0xd6, + 0x06, 0x00, 0x02, 0x00, 0xae, 0x06, 0x00, 0x03, + 0x00, 0xc2, 0x06, 0x00, 0x04, 0x00, 0x38, 0x98, + 0x00, 0x00, 0x00, 0x42, 0xa5, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x97, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0x0b, 0x02, 0x00, + 0x00, 0xf1, 0x2f, 0xd3, 0xeb, 0xcb, 0x38, 0x98, + 0x00, 0x00, 0x00, 0x42, 0xa5, 0x01, 0x00, 0x00, + 0xd3, 0xb7, 0x47, 0x24, 0x01, 0x00, 0x97, 0xec, + 0x20, 0xb8, 0xcc, 0x38, 0xec, 0x00, 0x00, 0x00, + 0xc8, 0xc7, 0xf2, 0xcd, 0xb7, 0xce, 0xca, 0xc7, + 0xa4, 0xec, 0x41, 0xc9, 0xb7, 0x47, 0xca, 0x73, + 0xd3, 0xca, 0x47, 0x49, 0x94, 0x03, 0xee, 0xef, + 0xd3, 0xb7, 0x47, 0xeb, 0xcc, 0x38, 0xec, 0x00, + 0x00, 0x00, 0xc8, 0xc7, 0xf2, 0xcd, 0xb7, 0xce, + 0xca, 0xc7, 0xa4, 0xec, 0x1f, 0xb7, 0xc5, 0x04, + 0xc4, 0x04, 0xc8, 0xa4, 0xec, 0x12, 0xc9, 0xc4, + 0x04, 0x47, 0xca, 0x73, 0xd3, 0xca, 0x47, 0xc4, + 0x04, 0x47, 0x49, 0x94, 0x04, 0xee, 0xea, 0x94, + 0x03, 0xee, 0xde, 0xc9, 0x28, 0xdc, 0x04, 0x97, + 0x0f, 0x11, 0x04, 0x58, 0x3f, 0x12, 0x62, 0x0d, + 0x30, 0x26, 0x30, 0x18, 0x1c, 0x30, 0x26, 0x30, + 0x44, 0x17, 0x18, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, 0x4b, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, + 0x00, 0x00, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0x97, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, + 0x04, 0x0c, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xd3, + 0xeb, 0xcb, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xd3, 0xb7, 0x47, 0x24, + 0x01, 0x00, 0x97, 0x11, 0xed, 0x08, 0x0e, 0xc7, + 0xd3, 0xb7, 0x47, 0xeb, 0xab, 0xec, 0x0d, 0x38, + 0xd1, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x02, 0x00, + 0x00, 0xf1, 0x2f, 0xc7, 0x28, 0xdc, 0x04, 0xad, + 0x0f, 0x06, 0x04, 0x58, 0x3f, 0x12, 0x94, 0x3f, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x03, 0x01, + 0x03, 0x00, 0x00, 0x2a, 0x04, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, 0xd6, + 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, 0x02, + 0x00, 0x38, 0xec, 0x00, 0x00, 0x00, 0x42, 0x93, + 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcb, + 0xd3, 0xb7, 0x47, 0xb7, 0x47, 0xcc, 0xb8, 0xcd, + 0xc9, 0xc7, 0xa4, 0xec, 0x0d, 0xc8, 0xd3, 0xc9, + 0x47, 0xc9, 0x47, 0x9e, 0xcc, 0x94, 0x02, 0xee, + 0xf0, 0xc8, 0x28, 0xdc, 0x04, 0xb6, 0x0f, 0x06, + 0x04, 0x4e, 0x21, 0x26, 0x2b, 0x17, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x01, 0x06, 0x01, 0x04, 0x00, + 0x00, 0x80, 0x01, 0x07, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, 0x94, 0x07, + 0x00, 0x01, 0x00, 0xf4, 0x06, 0x00, 0x02, 0x00, + 0xae, 0x06, 0x00, 0x03, 0x00, 0xc2, 0x06, 0x00, + 0x04, 0x00, 0x9c, 0x08, 0x00, 0x05, 0x00, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x42, 0x93, 0x01, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcb, 0x26, 0x00, + 0x00, 0xcc, 0xb7, 0xce, 0xca, 0xc7, 0xb8, 0x9e, + 0xa4, 0xec, 0x09, 0xc8, 0xca, 0xb7, 0x49, 0x94, + 0x03, 0xee, 0xf2, 0xc8, 0xc7, 0xb8, 0x49, 0x38, + 0xec, 0x00, 0x00, 0x00, 0x42, 0x1b, 0x01, 0x00, + 0x00, 0xc7, 0x24, 0x01, 0x00, 0xcd, 0xb7, 0xce, + 0xca, 0xc7, 0xa4, 0xec, 0x3a, 0xc9, 0xd3, 0x9b, + 0xcd, 0x38, 0x1e, 0x01, 0x00, 0x00, 0xc9, 0xf1, + 0x8d, 0xca, 0xb8, 0x9e, 0x9c, 0xc5, 0x05, 0xc8, + 0xc7, 0xca, 0x9f, 0xb8, 0x9f, 0xc4, 0x05, 0x49, + 0xb7, 0xc5, 0x04, 0xc4, 0x04, 0xc7, 0xa4, 0xec, + 0x12, 0xc9, 0xc4, 0x04, 0x47, 0xc4, 0x04, 0x73, + 0x13, 0x47, 0xc4, 0x05, 0x9e, 0x49, 0x94, 0x04, + 0xee, 0xea, 0x94, 0x03, 0xee, 0xc3, 0x38, 0xe8, + 0x00, 0x00, 0x00, 0xc8, 0x23, 0x01, 0x00, 0xdc, + 0x04, 0xbf, 0x0f, 0x0e, 0x04, 0x4e, 0x17, 0x30, + 0x2b, 0x17, 0x4e, 0x26, 0x17, 0x49, 0x30, 0x30, + 0x58, 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, + 0x00, 0x01, 0x05, 0x00, 0x00, 0x1b, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0x38, 0xe8, 0x00, 0x00, + 0x00, 0x42, 0x2d, 0x01, 0x00, 0x00, 0x38, 0xec, + 0x00, 0x00, 0x00, 0x42, 0x1f, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x25, 0x01, 0x00, 0xdc, + 0x04, 0xd0, 0x0f, 0x01, 0x03, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x01, 0x08, 0x01, 0x05, 0x00, 0x00, + 0xdd, 0x01, 0x09, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xde, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, + 0x01, 0x00, 0xc2, 0x06, 0x00, 0x02, 0x00, 0xc6, + 0x06, 0x00, 0x03, 0x00, 0xe4, 0x06, 0x00, 0x04, + 0x00, 0x9e, 0x08, 0x00, 0x05, 0x00, 0xf2, 0x06, + 0x00, 0x06, 0x00, 0xf4, 0x06, 0x00, 0x07, 0x00, + 0x38, 0xec, 0x00, 0x00, 0x00, 0x42, 0x93, 0x01, + 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcb, 0xb8, + 0xc5, 0x04, 0xd3, 0x42, 0x94, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc5, 0x05, 0xb7, 0xcc, 0xc8, + 0xc7, 0xa4, 0x6a, 0x9d, 0x00, 0x00, 0x00, 0xc8, + 0xcd, 0xc9, 0xc7, 0xa4, 0xec, 0x0f, 0xc4, 0x05, + 0xc9, 0x47, 0xc8, 0x47, 0xb7, 0xab, 0xed, 0x05, + 0x94, 0x02, 0xee, 0xee, 0xc9, 0xc7, 0xaa, 0xec, + 0x03, 0xb7, 0x28, 0xc9, 0xc8, 0xab, 0xec, 0x2e, + 0xb7, 0xce, 0xca, 0xc7, 0xa4, 0xec, 0x22, 0xc4, + 0x05, 0xc9, 0x47, 0xca, 0x47, 0xc5, 0x06, 0xc4, + 0x05, 0xc9, 0x47, 0xca, 0x73, 0xc4, 0x05, 0xc8, + 0x47, 0xca, 0x47, 0x49, 0xc4, 0x05, 0xc8, 0x47, + 0xca, 0xc4, 0x06, 0x49, 0x94, 0x03, 0xee, 0xdb, + 0xc4, 0x04, 0x8d, 0xc5, 0x04, 0xc4, 0x05, 0xc8, + 0x47, 0xc8, 0x47, 0x42, 0xfe, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xc5, 0x07, 0xc8, 0xb8, 0x9e, + 0xcd, 0xc9, 0xc7, 0xa4, 0xec, 0x2e, 0xc4, 0x07, + 0xc4, 0x05, 0xc9, 0x47, 0xc8, 0x47, 0x9b, 0xc5, + 0x06, 0xb7, 0xce, 0xca, 0xc7, 0xa4, 0xec, 0x18, + 0xc4, 0x05, 0xc9, 0x47, 0xca, 0x73, 0x13, 0x47, + 0xc4, 0x05, 0xc8, 0x47, 0xca, 0x47, 0xc4, 0x06, + 0x9b, 0x9f, 0x49, 0x94, 0x03, 0xee, 0xe5, 0x94, + 0x02, 0xee, 0xcf, 0x94, 0x01, 0xef, 0x61, 0xff, + 0xc4, 0x04, 0xc5, 0x07, 0xb7, 0xcc, 0xc8, 0xc7, + 0xa4, 0xec, 0x10, 0xc4, 0x07, 0xc4, 0x05, 0xc8, + 0x47, 0xc8, 0x47, 0x9b, 0xc5, 0x07, 0x94, 0x01, + 0xee, 0xed, 0xc4, 0x07, 0x28, 0xdc, 0x04, 0xd3, + 0x0f, 0x1d, 0x05, 0x4e, 0x12, 0x3a, 0x35, 0x26, + 0x2b, 0x0d, 0x17, 0x1c, 0x0d, 0x1c, 0x26, 0x2b, + 0x44, 0x2b, 0x17, 0x1d, 0x53, 0x30, 0x3a, 0x26, + 0x62, 0x17, 0x17, 0x1c, 0x17, 0x26, 0x4e, 0x0e, + 0x42, 0x07, 0x05, 0x00, 0x01, 0x0a, 0x01, 0x05, + 0x00, 0x00, 0x9f, 0x02, 0x0b, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xde, 0x06, 0x00, 0x00, 0x00, 0xa0, + 0x08, 0x00, 0x01, 0x00, 0x9e, 0x08, 0x00, 0x02, + 0x00, 0xae, 0x06, 0x00, 0x03, 0x00, 0xc2, 0x06, + 0x00, 0x04, 0x00, 0xc6, 0x06, 0x00, 0x05, 0x00, + 0xec, 0x07, 0x00, 0x06, 0x00, 0xd6, 0x06, 0x00, + 0x07, 0x00, 0xf4, 0x06, 0x00, 0x08, 0x00, 0xf2, + 0x06, 0x00, 0x09, 0x00, 0x38, 0xec, 0x00, 0x00, + 0x00, 0x42, 0x93, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0xcb, 0xd3, 0x42, 0x94, 0x01, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xcd, 0x38, 0xec, 0x00, + 0x00, 0x00, 0x42, 0x1b, 0x01, 0x00, 0x00, 0xc7, + 0x24, 0x01, 0x00, 0xcc, 0xb7, 0xce, 0xca, 0xc7, + 0xa4, 0x6a, 0xef, 0x00, 0x00, 0x00, 0xca, 0xc5, + 0x04, 0xc4, 0x04, 0xc7, 0xa4, 0xec, 0x0f, 0xc9, + 0xc4, 0x04, 0x47, 0xca, 0x47, 0xb7, 0xab, 0xed, + 0x05, 0x94, 0x04, 0xee, 0xed, 0xc4, 0x04, 0xc7, + 0xaa, 0xec, 0x0d, 0x38, 0xce, 0x00, 0x00, 0x00, + 0x04, 0x11, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xc4, + 0x04, 0xca, 0xab, 0xec, 0x27, 0xc9, 0xc4, 0x04, + 0x47, 0xc5, 0x09, 0xc9, 0xc4, 0x04, 0x73, 0xc9, + 0xca, 0x47, 0x49, 0xc9, 0xca, 0xc4, 0x09, 0x49, + 0xc8, 0xc4, 0x04, 0x47, 0xc5, 0x09, 0xc8, 0xc4, + 0x04, 0x73, 0xc8, 0xca, 0x47, 0x49, 0xc8, 0xca, + 0xc4, 0x09, 0x49, 0xc9, 0xca, 0x47, 0xca, 0x47, + 0x42, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xc5, 0x08, 0xb7, 0xc5, 0x05, 0xc4, 0x05, 0xc7, + 0xa4, 0xec, 0x1d, 0xc9, 0xca, 0x47, 0xc4, 0x05, + 0x73, 0x13, 0x47, 0xc4, 0x08, 0x9b, 0x49, 0xc8, + 0xca, 0x47, 0xc4, 0x05, 0x73, 0x13, 0x47, 0xc4, + 0x08, 0x9b, 0x49, 0x94, 0x05, 0xee, 0xdf, 0xb7, + 0xc5, 0x04, 0xc4, 0x04, 0xc7, 0xa4, 0xec, 0x55, + 0xc4, 0x04, 0xca, 0xab, 0xec, 0x4b, 0xc9, 0xc4, + 0x04, 0x47, 0xca, 0x47, 0xc5, 0x08, 0xca, 0xc5, + 0x05, 0xc4, 0x05, 0xc7, 0xa4, 0xec, 0x19, 0xc9, + 0xc4, 0x04, 0x47, 0xc4, 0x05, 0x73, 0x13, 0x47, + 0xc9, 0xca, 0x47, 0xc4, 0x05, 0x47, 0xc4, 0x08, + 0x9b, 0x9f, 0x49, 0x94, 0x05, 0xee, 0xe3, 0xb7, + 0xc5, 0x05, 0xc4, 0x05, 0xc7, 0xa4, 0xec, 0x19, + 0xc8, 0xc4, 0x04, 0x47, 0xc4, 0x05, 0x73, 0x13, + 0x47, 0xc8, 0xca, 0x47, 0xc4, 0x05, 0x47, 0xc4, + 0x08, 0x9b, 0x9f, 0x49, 0x94, 0x05, 0xee, 0xe3, + 0x94, 0x04, 0xee, 0xa7, 0x94, 0x03, 0xef, 0x0f, + 0xff, 0xc8, 0x28, 0xdc, 0x04, 0xf5, 0x0f, 0x22, + 0x04, 0x4e, 0x35, 0x4e, 0x35, 0x30, 0x2b, 0x0d, + 0x17, 0x21, 0x3f, 0x22, 0x21, 0x2b, 0x1c, 0x21, + 0x2b, 0x1e, 0x4e, 0x30, 0x3f, 0x3f, 0x18, 0x30, + 0x21, 0x2b, 0x30, 0x67, 0x17, 0x30, 0x67, 0x18, + 0x17, 0x1c, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, + 0x08, 0x01, 0x05, 0x00, 0x00, 0x92, 0x02, 0x09, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0x9e, 0x08, 0x00, + 0x00, 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0xc2, + 0x06, 0x00, 0x02, 0x00, 0xc6, 0x06, 0x00, 0x03, + 0x00, 0x92, 0x08, 0x00, 0x04, 0x00, 0x90, 0x08, + 0x00, 0x05, 0x00, 0xa4, 0x08, 0x00, 0x06, 0x00, + 0xf4, 0x06, 0x00, 0x07, 0x00, 0x38, 0x98, 0x00, + 0x00, 0x00, 0x42, 0xa5, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0x97, 0x11, 0xed, 0x13, 0x0e, + 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, 0xa5, 0x01, + 0x00, 0x00, 0xd3, 0xb7, 0x47, 0x24, 0x01, 0x00, + 0x97, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, + 0x04, 0x0b, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xd3, + 0xeb, 0xc5, 0x05, 0xd3, 0xb7, 0x47, 0xeb, 0xc5, + 0x04, 0xd3, 0x42, 0x94, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xcb, 0xb7, 0xc5, 0x06, 0xb7, 0xcc, + 0xc8, 0xc4, 0x04, 0xa4, 0x6a, 0xbf, 0x00, 0x00, + 0x00, 0xc4, 0x06, 0xcd, 0xc9, 0xc4, 0x05, 0xa4, + 0xec, 0x0e, 0xc7, 0xc9, 0x47, 0xc8, 0x47, 0xb7, + 0xab, 0xed, 0x05, 0x94, 0x02, 0xee, 0xee, 0xc9, + 0xc4, 0x05, 0xaa, 0x6b, 0x9b, 0x00, 0x00, 0x00, + 0xc9, 0xc4, 0x06, 0xab, 0xec, 0x34, 0xb7, 0xce, + 0xca, 0xc4, 0x04, 0xa4, 0xec, 0x2c, 0x36, 0xb9, + 0x01, 0x00, 0x00, 0xc7, 0xc9, 0x47, 0xca, 0x47, + 0x3b, 0xb9, 0x01, 0x00, 0x00, 0xc7, 0xc9, 0x47, + 0xca, 0x73, 0xc7, 0xc4, 0x06, 0x47, 0xca, 0x47, + 0x49, 0xc7, 0xc4, 0x06, 0x47, 0xca, 0x73, 0x38, + 0xb9, 0x01, 0x00, 0x00, 0x49, 0x94, 0x03, 0xee, + 0xd0, 0xc7, 0xc4, 0x06, 0x47, 0xc8, 0x47, 0x42, + 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xc5, + 0x07, 0xb7, 0xce, 0xca, 0xc4, 0x04, 0xa4, 0xec, + 0x11, 0xc7, 0xc4, 0x06, 0x47, 0xca, 0x73, 0x13, + 0x47, 0xc4, 0x07, 0x9b, 0x49, 0x94, 0x03, 0xee, + 0xeb, 0xc4, 0x06, 0xb8, 0x9e, 0xcd, 0xc9, 0xc4, + 0x05, 0xa4, 0xec, 0x2a, 0xc7, 0xc9, 0x47, 0xc8, + 0x47, 0xc5, 0x07, 0xc8, 0xce, 0xca, 0xc4, 0x04, + 0xa4, 0xec, 0x17, 0xc7, 0xc9, 0x47, 0xca, 0x73, + 0x13, 0x47, 0xc7, 0xc4, 0x06, 0x47, 0xca, 0x47, + 0xc4, 0x07, 0x9b, 0x9f, 0x49, 0x94, 0x03, 0xee, + 0xe5, 0x94, 0x02, 0xee, 0xd2, 0x94, 0x06, 0x94, + 0x01, 0xef, 0x3e, 0xff, 0xc4, 0x06, 0x28, 0xdc, + 0x04, 0x9f, 0x10, 0x21, 0x05, 0x62, 0x62, 0x3f, + 0x17, 0x21, 0x35, 0x12, 0x3a, 0x30, 0x26, 0x0d, + 0x17, 0x17, 0x1c, 0x22, 0x2b, 0x4e, 0x3f, 0x3f, + 0x19, 0x53, 0x2b, 0x3f, 0x18, 0x3a, 0x26, 0x2b, + 0x5d, 0x17, 0x17, 0x0d, 0x1c, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x01, 0x0c, 0x01, 0x05, 0x00, 0x00, + 0x90, 0x03, 0x0d, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0x9e, 0x08, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, + 0x01, 0x00, 0xc2, 0x06, 0x00, 0x02, 0x00, 0xc6, + 0x06, 0x00, 0x03, 0x00, 0x92, 0x08, 0x00, 0x04, + 0x00, 0x90, 0x08, 0x00, 0x05, 0x00, 0xa4, 0x08, + 0x00, 0x06, 0x00, 0xfa, 0x06, 0x00, 0x07, 0x00, + 0xd6, 0x06, 0x00, 0x08, 0x00, 0xa6, 0x08, 0x00, + 0x09, 0x00, 0xa8, 0x08, 0x00, 0x0a, 0x00, 0xf4, + 0x06, 0x00, 0x0b, 0x00, 0x38, 0x98, 0x00, 0x00, + 0x00, 0x42, 0xa5, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x97, 0x11, 0xed, 0x13, 0x0e, 0x38, + 0x98, 0x00, 0x00, 0x00, 0x42, 0xa5, 0x01, 0x00, + 0x00, 0xd3, 0xb7, 0x47, 0x24, 0x01, 0x00, 0x97, + 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, + 0x0b, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xd3, 0xeb, + 0xc5, 0x05, 0xd3, 0xb7, 0x47, 0xeb, 0xc5, 0x04, + 0xd3, 0x42, 0x94, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0xcb, 0x26, 0x00, 0x00, 0xc5, 0x09, 0xb7, + 0xc5, 0x06, 0xb7, 0xcc, 0xc8, 0xc4, 0x04, 0xa4, + 0x6a, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x09, 0xc8, + 0x09, 0x49, 0xc4, 0x06, 0xcd, 0xc9, 0xc4, 0x05, + 0xa4, 0xec, 0x0e, 0xc7, 0xc9, 0x47, 0xc8, 0x47, + 0xb7, 0xab, 0xed, 0x05, 0x94, 0x02, 0xee, 0xee, + 0xc9, 0xc4, 0x05, 0xaa, 0x6b, 0xa3, 0x00, 0x00, + 0x00, 0xc4, 0x09, 0xc8, 0x0a, 0x49, 0xc9, 0xc4, + 0x06, 0xab, 0xec, 0x34, 0xb7, 0xce, 0xca, 0xc4, + 0x04, 0xa4, 0xec, 0x2c, 0x36, 0xb9, 0x01, 0x00, + 0x00, 0xc7, 0xc9, 0x47, 0xca, 0x47, 0x3b, 0xb9, + 0x01, 0x00, 0x00, 0xc7, 0xc9, 0x47, 0xca, 0x73, + 0xc7, 0xc4, 0x06, 0x47, 0xca, 0x47, 0x49, 0xc7, + 0xc4, 0x06, 0x47, 0xca, 0x73, 0x38, 0xb9, 0x01, + 0x00, 0x00, 0x49, 0x94, 0x03, 0xee, 0xd0, 0xc7, + 0xc4, 0x06, 0x47, 0xc8, 0x47, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0xc5, 0x0b, 0xb7, + 0xce, 0xca, 0xc4, 0x04, 0xa4, 0xec, 0x11, 0xc7, + 0xc4, 0x06, 0x47, 0xca, 0x73, 0x13, 0x47, 0xc4, + 0x0b, 0x9b, 0x49, 0x94, 0x03, 0xee, 0xeb, 0xb7, + 0xcd, 0xc9, 0xc4, 0x05, 0xa4, 0xec, 0x30, 0xc9, + 0xc4, 0x06, 0xab, 0xec, 0x26, 0xc7, 0xc9, 0x47, + 0xc8, 0x47, 0xc5, 0x0b, 0xc8, 0xce, 0xca, 0xc4, + 0x04, 0xa4, 0xec, 0x17, 0xc7, 0xc9, 0x47, 0xca, + 0x73, 0x13, 0x47, 0xc7, 0xc4, 0x06, 0x47, 0xca, + 0x47, 0xc4, 0x0b, 0x9b, 0x9f, 0x49, 0x94, 0x03, + 0xee, 0xe5, 0x94, 0x02, 0xee, 0xcc, 0x94, 0x06, + 0x94, 0x01, 0xef, 0x31, 0xff, 0xc4, 0x04, 0xc4, + 0x06, 0x9f, 0xc5, 0x0a, 0x38, 0xec, 0x00, 0x00, + 0x00, 0xc4, 0x04, 0xc4, 0x0a, 0xf2, 0xc5, 0x08, + 0xb7, 0xce, 0xb7, 0xcc, 0xc8, 0xc4, 0x04, 0xa4, + 0xec, 0x50, 0xc4, 0x09, 0xc8, 0x47, 0x97, 0xec, + 0x45, 0xb7, 0xc5, 0x06, 0xb7, 0xc5, 0x07, 0xb7, + 0xcd, 0xc9, 0xc4, 0x04, 0xa4, 0xec, 0x35, 0xc4, + 0x09, 0xc9, 0x47, 0xec, 0x13, 0xc4, 0x08, 0xc9, + 0x47, 0xca, 0x73, 0xc7, 0xc4, 0x07, 0x47, 0xc8, + 0x47, 0x8d, 0x49, 0x94, 0x07, 0xee, 0x19, 0xc4, + 0x06, 0xca, 0xaa, 0xec, 0x0a, 0xc4, 0x08, 0xc9, + 0x47, 0xca, 0xb8, 0x49, 0xee, 0x08, 0xc4, 0x08, + 0xc9, 0x47, 0xca, 0xb7, 0x49, 0x94, 0x06, 0x94, + 0x02, 0xee, 0xc7, 0x94, 0x03, 0x94, 0x01, 0xee, + 0xac, 0xc4, 0x08, 0x28, 0xdc, 0x04, 0xc8, 0x10, + 0x3b, 0x05, 0x62, 0x62, 0x3f, 0x17, 0x21, 0x35, + 0x1c, 0x12, 0x3a, 0x1c, 0x30, 0x26, 0x0d, 0x17, + 0x17, 0x1c, 0x1c, 0x22, 0x2b, 0x4e, 0x3f, 0x3f, + 0x19, 0x53, 0x2b, 0x3f, 0x18, 0x2b, 0x21, 0x26, + 0x2b, 0x5d, 0x18, 0x17, 0x0e, 0x00, 0x05, 0x08, + 0x26, 0x3f, 0x0d, 0x2b, 0x27, 0x12, 0x12, 0x2b, + 0x21, 0x49, 0x0d, 0x0d, 0x21, 0x26, 0x0d, 0x27, + 0x0e, 0x17, 0x0e, 0x17, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x03, 0x02, 0x04, 0x00, 0x00, 0x2d, + 0x05, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, + 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, 0x00, 0x00, + 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x02, 0x00, 0xd3, 0xeb, 0xd0, 0xd4, 0xeb, 0xab, + 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, 0x04, + 0x15, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0xb7, 0xcd, + 0xb7, 0xcb, 0xc7, 0xc8, 0xa4, 0xec, 0x0f, 0xc9, + 0xd3, 0xc7, 0x47, 0xd4, 0xc7, 0x47, 0x9b, 0x9e, + 0xcd, 0x94, 0x00, 0xee, 0xee, 0xc9, 0x28, 0xdc, + 0x04, 0x92, 0x11, 0x08, 0x04, 0x12, 0x1c, 0x40, + 0x0d, 0x26, 0x35, 0x17, 0x0e, 0x42, 0x07, 0x05, + 0x00, 0x02, 0x01, 0x02, 0x06, 0x00, 0x00, 0x58, + 0x03, 0xf8, 0x07, 0x00, 0x01, 0x00, 0xfa, 0x07, + 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, + 0xd3, 0xeb, 0xba, 0xab, 0x11, 0xed, 0x06, 0x0e, + 0xd4, 0xeb, 0xba, 0xab, 0xec, 0x0d, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0x16, 0x02, 0x00, 0x00, + 0xf1, 0x2f, 0x26, 0x00, 0x00, 0xcf, 0xb7, 0x73, + 0xd3, 0xb8, 0x47, 0xd4, 0xb9, 0x47, 0x9b, 0xd3, + 0xb9, 0x47, 0xd4, 0xb8, 0x47, 0x9b, 0x9f, 0x49, + 0xc7, 0xb8, 0x73, 0xd3, 0xb9, 0x47, 0xd4, 0xb7, + 0x47, 0x9b, 0xd3, 0xb7, 0x47, 0xd4, 0xb9, 0x47, + 0x9b, 0x9f, 0x49, 0xc7, 0xb9, 0x73, 0xd3, 0xb7, + 0x47, 0xd4, 0xb8, 0x47, 0x9b, 0xd3, 0xb8, 0x47, + 0xd4, 0xb7, 0x47, 0x9b, 0x9f, 0x49, 0xc7, 0x28, + 0xdc, 0x04, 0x9f, 0x11, 0x07, 0x04, 0x49, 0x3f, + 0x17, 0x5d, 0x62, 0x62, 0x0e, 0x43, 0x06, 0x05, + 0xdc, 0x05, 0x02, 0x03, 0x02, 0x05, 0x00, 0x00, + 0x30, 0x05, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, + 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, + 0x00, 0x02, 0x00, 0xd3, 0xeb, 0xd1, 0xd4, 0xeb, + 0xab, 0xec, 0x0d, 0x38, 0xd1, 0x00, 0x00, 0x00, + 0x04, 0x17, 0x02, 0x00, 0x00, 0xf1, 0x2f, 0x26, + 0x00, 0x00, 0xcb, 0xb7, 0xcc, 0xc8, 0xc9, 0xa4, + 0xec, 0x10, 0xc7, 0xc8, 0x73, 0xd3, 0xc8, 0x47, + 0xd4, 0xc8, 0x47, 0x9e, 0x49, 0x94, 0x01, 0xee, + 0xed, 0xc7, 0x28, 0xdc, 0x04, 0xab, 0x11, 0x07, + 0x04, 0x12, 0x1c, 0x3f, 0x17, 0x26, 0x4e, 0x0e, + 0x43, 0x06, 0x05, 0xde, 0x05, 0x02, 0x03, 0x02, + 0x05, 0x00, 0x00, 0x30, 0x05, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xd6, + 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, 0x01, + 0x00, 0xde, 0x06, 0x00, 0x02, 0x00, 0xd3, 0xeb, + 0xd1, 0xd4, 0xeb, 0xab, 0xec, 0x0d, 0x38, 0xd1, + 0x00, 0x00, 0x00, 0x04, 0x17, 0x02, 0x00, 0x00, + 0xf1, 0x2f, 0x26, 0x00, 0x00, 0xcb, 0xb7, 0xcc, + 0xc8, 0xc9, 0xa4, 0xec, 0x10, 0xc7, 0xc8, 0x73, + 0xd3, 0xc8, 0x47, 0xd4, 0xc8, 0x47, 0x9f, 0x49, + 0x94, 0x01, 0xee, 0xed, 0xc7, 0x28, 0xdc, 0x04, + 0xb5, 0x11, 0x07, 0x04, 0x12, 0x1c, 0x3f, 0x17, + 0x26, 0x4e, 0x0e, 0x43, 0x06, 0x05, 0xe0, 0x05, + 0x02, 0x03, 0x02, 0x04, 0x00, 0x00, 0x1d, 0x05, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, + 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xae, + 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, + 0x00, 0xd3, 0xeb, 0xcd, 0x26, 0x00, 0x00, 0xcb, + 0xb7, 0xcc, 0xc8, 0xc9, 0xa4, 0xec, 0x0e, 0xc7, + 0xc8, 0x73, 0xd3, 0xc8, 0x47, 0xd4, 0x9b, 0x49, + 0x94, 0x01, 0xee, 0xef, 0xc7, 0x28, 0xdc, 0x04, + 0xbf, 0x11, 0x05, 0x04, 0x12, 0x17, 0x26, 0x44, + 0x0e, 0x43, 0x06, 0x05, 0xe2, 0x05, 0x02, 0x0b, + 0x02, 0x05, 0x00, 0x00, 0xbf, 0x02, 0x0d, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0x90, 0x08, 0x00, 0x00, 0x00, 0x92, 0x08, + 0x00, 0x01, 0x00, 0xa4, 0x08, 0x00, 0x02, 0x00, + 0xae, 0x06, 0x00, 0x03, 0x00, 0xc2, 0x06, 0x00, + 0x04, 0x00, 0xc6, 0x06, 0x00, 0x05, 0x00, 0xd6, + 0x06, 0x00, 0x06, 0x00, 0x94, 0x08, 0x00, 0x07, + 0x00, 0x82, 0x08, 0x00, 0x08, 0x00, 0xb0, 0x08, + 0x00, 0x09, 0x00, 0xb2, 0x08, 0x00, 0x0a, 0x00, + 0xd3, 0xeb, 0xcb, 0x38, 0x98, 0x00, 0x00, 0x00, + 0x42, 0xa5, 0x01, 0x00, 0x00, 0xd3, 0xb7, 0x47, + 0x24, 0x01, 0x00, 0xc6, 0x09, 0xec, 0x08, 0xd3, + 0xb7, 0x47, 0xeb, 0xcd, 0xee, 0x03, 0xb8, 0xcd, + 0xc9, 0xd4, 0xeb, 0xab, 0xec, 0x0d, 0x38, 0xce, + 0x00, 0x00, 0x00, 0x04, 0x1a, 0x02, 0x00, 0x00, + 0xf1, 0x2f, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xd4, 0xb7, 0x47, 0x24, + 0x01, 0x00, 0xc6, 0x0a, 0xec, 0x08, 0xd4, 0xb7, + 0x47, 0xeb, 0xcc, 0xee, 0x03, 0xb8, 0xcc, 0x26, + 0x00, 0x00, 0xc5, 0x06, 0xc4, 0x09, 0xec, 0x55, + 0xc4, 0x0a, 0xec, 0x51, 0xb7, 0xce, 0xca, 0xc7, + 0xa4, 0x6a, 0xda, 0x00, 0x00, 0x00, 0x26, 0x00, + 0x00, 0xc5, 0x07, 0xb7, 0xc5, 0x04, 0xc4, 0x04, + 0xc8, 0xa4, 0xec, 0x2f, 0xb7, 0xc5, 0x08, 0xb7, + 0xc5, 0x05, 0xc4, 0x05, 0xc9, 0xa4, 0xec, 0x18, + 0xc4, 0x08, 0xd3, 0xca, 0x47, 0xc4, 0x05, 0x47, + 0xd4, 0xc4, 0x05, 0x47, 0xc4, 0x04, 0x47, 0x9b, + 0x9e, 0xc5, 0x08, 0x94, 0x05, 0xee, 0xe4, 0xc4, + 0x07, 0xc4, 0x04, 0xc4, 0x08, 0x49, 0x94, 0x04, + 0xee, 0xcd, 0xc4, 0x06, 0xca, 0xc4, 0x07, 0x49, + 0x94, 0x03, 0xee, 0xb3, 0xc4, 0x09, 0xec, 0x3a, + 0xc4, 0x0a, 0x97, 0xec, 0x35, 0xb7, 0xce, 0xca, + 0xc7, 0xa4, 0x6a, 0x81, 0x00, 0x00, 0x00, 0xb7, + 0xc5, 0x08, 0xb7, 0xc5, 0x05, 0xc4, 0x05, 0xc9, + 0xa4, 0xec, 0x15, 0xc4, 0x08, 0xd3, 0xca, 0x47, + 0xc4, 0x05, 0x47, 0xd4, 0xc4, 0x05, 0x47, 0x9b, + 0x9e, 0xc5, 0x08, 0x94, 0x05, 0xee, 0xe7, 0xc4, + 0x06, 0xca, 0xc4, 0x08, 0x49, 0x94, 0x03, 0xee, + 0xcf, 0xc4, 0x09, 0x97, 0xec, 0x38, 0xc4, 0x0a, + 0xec, 0x34, 0xb7, 0xce, 0xca, 0xc7, 0xa4, 0xec, + 0x44, 0x26, 0x00, 0x00, 0xc5, 0x07, 0xb7, 0xc5, + 0x04, 0xc4, 0x04, 0xc8, 0xa4, 0xec, 0x15, 0xc4, + 0x07, 0xc4, 0x04, 0x73, 0xd3, 0xca, 0x47, 0xd4, + 0xb7, 0x47, 0xc4, 0x04, 0x47, 0x9b, 0x49, 0x94, + 0x04, 0xee, 0xe7, 0xc4, 0x06, 0xca, 0xc4, 0x07, + 0x49, 0x94, 0x03, 0xee, 0xd0, 0xb7, 0xce, 0xca, + 0xc7, 0xa4, 0xec, 0x11, 0xc4, 0x06, 0xca, 0x73, + 0xd3, 0xca, 0x47, 0xd4, 0xb7, 0x47, 0x9b, 0x49, + 0x94, 0x03, 0xee, 0xec, 0xc4, 0x06, 0x28, 0xdc, + 0x04, 0xc7, 0x11, 0x2d, 0x04, 0x12, 0x5d, 0x0d, + 0x1c, 0x0d, 0x0e, 0x21, 0x3f, 0x5d, 0x0d, 0x27, + 0x0d, 0x1c, 0x2b, 0x35, 0x1c, 0x30, 0x12, 0x30, + 0x62, 0x17, 0x26, 0x17, 0x21, 0x17, 0x30, 0x35, + 0x12, 0x30, 0x53, 0x17, 0x21, 0x17, 0x30, 0x26, + 0x1c, 0x30, 0x53, 0x17, 0x21, 0x18, 0x26, 0x3f, + 0x18, 0x0e, 0x43, 0x06, 0x05, 0xe4, 0x05, 0x02, + 0x00, 0x02, 0x04, 0x01, 0x00, 0x0e, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0xe2, 0x05, 0x42, 0x01, 0xdf, 0xd3, 0xd4, + 0x42, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x23, 0x02, 0x00, 0xdc, 0x04, 0xfb, 0x11, 0x01, + 0x03, 0x0e, 0x43, 0x06, 0x05, 0xe6, 0x05, 0x01, + 0x03, 0x01, 0x04, 0x00, 0x00, 0x23, 0x04, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, 0x00, + 0x00, 0xae, 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, + 0x00, 0x02, 0x00, 0xd3, 0xeb, 0xcd, 0x26, 0x00, + 0x00, 0xcb, 0xb7, 0xcc, 0xc8, 0xc9, 0xa4, 0xec, + 0x14, 0xc7, 0xc8, 0x73, 0xd3, 0xc8, 0x47, 0x42, + 0xfe, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x49, + 0x94, 0x01, 0xee, 0xe9, 0xc7, 0x28, 0xdc, 0x04, + 0xfe, 0x11, 0x05, 0x04, 0x12, 0x17, 0x26, 0x62, + 0x0e, 0x43, 0x06, 0x05, 0xe8, 0x05, 0x02, 0x02, + 0x02, 0x03, 0x00, 0x00, 0x22, 0x04, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, + 0xde, 0x06, 0x00, 0x00, 0x00, 0xae, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0xeb, 0xcf, 0xd4, 0xeb, 0xab, + 0xec, 0x03, 0x09, 0x28, 0xb7, 0xcc, 0xc8, 0xc7, + 0xa4, 0xec, 0x10, 0xd3, 0xc8, 0x47, 0xd4, 0xc8, + 0x47, 0xab, 0xec, 0x03, 0x09, 0x28, 0x94, 0x01, + 0xee, 0xed, 0x0a, 0x28, 0xdc, 0x04, 0x86, 0x12, + 0x08, 0x04, 0x12, 0x1c, 0x0d, 0x26, 0x30, 0x0d, + 0x17, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xd3, 0x28, 0xdc, 0x04, 0x99, + 0x12, 0x01, 0x03, 0x0e, 0x42, 0x07, 0x05, 0x00, + 0x01, 0x03, 0x01, 0x04, 0x00, 0x00, 0x1c, 0x04, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xae, 0x06, 0x00, + 0x00, 0x00, 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, + 0x06, 0x00, 0x02, 0x00, 0xd3, 0xeb, 0xcc, 0x26, + 0x00, 0x00, 0xcd, 0xb7, 0xcb, 0xc7, 0xc8, 0xa4, + 0xec, 0x0d, 0xc9, 0xc7, 0x73, 0xd3, 0xc7, 0x47, + 0x8d, 0x49, 0x94, 0x00, 0xee, 0xf0, 0xc9, 0x28, + 0xdc, 0x04, 0x9c, 0x12, 0x05, 0x04, 0x12, 0x17, + 0x26, 0x3f, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, + 0x00, 0x02, 0x03, 0x00, 0x00, 0x0c, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0xd4, 0x42, 0xfe, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x9b, 0x28, 0xdc, 0x04, 0xa9, + 0x12, 0x00, 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, + 0x00, 0x02, 0x03, 0x01, 0x00, 0x06, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0xe0, 0x05, 0x41, 0x01, 0xdf, 0xd4, 0xd3, + 0x23, 0x02, 0x00, 0xdc, 0x04, 0xaf, 0x12, 0x00, + 0x0e, 0x42, 0x07, 0x05, 0x00, 0x02, 0x00, 0x02, + 0x03, 0x01, 0x00, 0x06, 0x02, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, 0x00, 0xe6, + 0x05, 0x44, 0x01, 0xd3, 0xdf, 0xd4, 0xf1, 0x9b, + 0x28, 0xdc, 0x04, 0xb0, 0x12, 0x00, 0x0e, 0x42, + 0x07, 0x05, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x00, 0x25, 0x04, 0xae, 0x06, 0x00, 0x00, 0x00, + 0xde, 0x06, 0x00, 0x01, 0x00, 0xd6, 0x06, 0x00, + 0x02, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, 0xce, + 0xca, 0xeb, 0xcc, 0x26, 0x00, 0x00, 0xcd, 0xb7, + 0xcb, 0xc7, 0xc8, 0xa4, 0xec, 0x14, 0xc9, 0xc7, + 0x73, 0xca, 0xc7, 0x47, 0x42, 0xfc, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x49, 0x94, 0x00, 0xee, + 0xe9, 0xc9, 0x28, 0xdc, 0x04, 0xb4, 0x12, 0x05, + 0x0e, 0x12, 0x17, 0x26, 0x62, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, + 0x3f, 0x06, 0xd6, 0x06, 0x00, 0x00, 0x00, 0xae, + 0x06, 0x00, 0x01, 0x00, 0xde, 0x06, 0x00, 0x02, + 0x00, 0xda, 0x07, 0x00, 0x03, 0x00, 0xc0, 0x06, + 0x00, 0x04, 0x00, 0x10, 0x00, 0x01, 0x00, 0x08, + 0xc5, 0x05, 0xc4, 0x05, 0xc5, 0x04, 0x26, 0x00, + 0x00, 0xcb, 0xc4, 0x04, 0xeb, 0xcd, 0xb7, 0xcc, + 0xc8, 0xc9, 0xa4, 0xec, 0x28, 0xc4, 0x04, 0xc8, + 0x47, 0xce, 0x38, 0x98, 0x00, 0x00, 0x00, 0x42, + 0xa5, 0x01, 0x00, 0x00, 0xca, 0x24, 0x01, 0x00, + 0xec, 0x0b, 0xca, 0x42, 0x94, 0x01, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xce, 0xc7, 0xc8, 0xca, 0x49, + 0x94, 0x01, 0xee, 0xd5, 0xc7, 0x28, 0xdc, 0x04, + 0xbc, 0x12, 0x0a, 0x12, 0x17, 0x17, 0x17, 0x26, + 0x1c, 0x53, 0x35, 0x17, 0x17, 0x0e, 0x42, 0x07, + 0x05, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, + 0x10, 0x01, 0x10, 0x00, 0x01, 0x00, 0x08, 0xcb, + 0x38, 0xec, 0x00, 0x00, 0x00, 0x42, 0xfe, 0x00, + 0x00, 0x00, 0xc7, 0x25, 0x01, 0x00, 0xdc, 0x04, + 0xc8, 0x12, 0x01, 0x0d, 0x0e, 0x43, 0x06, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x41, 0x2a, + 0x01, 0x00, 0x00, 0x28, 0xdc, 0x04, 0xd5, 0x12, + 0x00, 0x0e, 0x43, 0x06, 0x05, 0xf0, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, 0xf8, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xe1, + 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, 0xf2, + 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, + 0xf9, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, + 0x04, 0xe6, 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x05, 0xf4, 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x09, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0x42, 0xfa, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xdc, 0x04, 0xeb, 0x12, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x05, 0xf6, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x09, 0x01, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0x42, 0xfb, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0xdc, 0x04, 0xf0, 0x12, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x05, 0xf8, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, 0xfc, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xf5, + 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, 0xfa, + 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, + 0xfd, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, + 0x04, 0xfa, 0x12, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x05, 0xfc, 0x03, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x09, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0x42, 0xfe, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xdc, 0x04, 0xff, 0x12, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x05, 0xfe, 0x03, 0x01, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x72, 0x01, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, + 0x79, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xec, 0x03, 0xd3, 0x28, 0xd3, 0x38, 0xe5, 0x00, + 0x00, 0x00, 0xa8, 0xec, 0x1a, 0x38, 0xe3, 0x00, + 0x00, 0x00, 0x42, 0xb4, 0x01, 0x00, 0x00, 0xd3, + 0x41, 0xc3, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xc4, + 0x01, 0x00, 0x00, 0x25, 0x02, 0x00, 0xd3, 0x38, + 0xe8, 0x00, 0x00, 0x00, 0xa8, 0xec, 0x03, 0xd3, + 0x28, 0xd3, 0x38, 0xea, 0x00, 0x00, 0x00, 0xa8, + 0xec, 0x1d, 0x38, 0xe8, 0x00, 0x00, 0x00, 0x42, + 0x8f, 0x01, 0x00, 0x00, 0xd3, 0x41, 0xc3, 0x01, + 0x00, 0x00, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xb7, 0x47, 0x28, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x01, 0x01, 0x00, 0x00, + 0xd3, 0x25, 0x01, 0x00, 0xdc, 0x04, 0x84, 0x13, + 0x0a, 0x04, 0x53, 0x08, 0x35, 0x80, 0x30, 0x08, + 0x35, 0x8a, 0x08, 0x0e, 0x43, 0x06, 0x05, 0x80, + 0x04, 0x01, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe3, + 0x00, 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xec, 0x03, 0xd3, 0x28, + 0xd3, 0x38, 0xe5, 0x00, 0x00, 0x00, 0xa8, 0xec, + 0x1a, 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x1b, + 0x02, 0x00, 0x00, 0xd3, 0x41, 0xc3, 0x01, 0x00, + 0x00, 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x25, + 0x02, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x00, 0x01, 0x00, 0x00, 0xd3, 0x25, 0x01, 0x00, + 0xdc, 0x04, 0x93, 0x13, 0x05, 0x04, 0x53, 0x08, + 0x35, 0x81, 0x0e, 0x43, 0x06, 0x05, 0x82, 0x04, + 0x01, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x01, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe3, 0x00, + 0x00, 0x00, 0x42, 0x79, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0xec, 0x03, 0xd3, 0x28, 0xd3, + 0x38, 0xe5, 0x00, 0x00, 0x00, 0xa8, 0xec, 0x1a, + 0x38, 0xe3, 0x00, 0x00, 0x00, 0x42, 0x1c, 0x02, + 0x00, 0x00, 0xd3, 0x41, 0xc3, 0x01, 0x00, 0x00, + 0xd3, 0x41, 0xc4, 0x01, 0x00, 0x00, 0x25, 0x02, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x01, + 0x01, 0x00, 0x00, 0xd3, 0x25, 0x01, 0x00, 0xdc, + 0x04, 0x9e, 0x13, 0x05, 0x04, 0x53, 0x08, 0x35, + 0x81, 0x0e, 0x43, 0x06, 0x05, 0x84, 0x04, 0x01, + 0x04, 0x01, 0x05, 0x00, 0x00, 0x8d, 0x01, 0x05, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, + 0x00, 0x00, 0xf0, 0x06, 0x00, 0x01, 0x00, 0xa2, + 0x07, 0x00, 0x02, 0x00, 0xa4, 0x07, 0x00, 0x03, + 0x00, 0xd3, 0x38, 0xeb, 0x00, 0x00, 0x00, 0xa8, + 0xec, 0x07, 0xd3, 0xb8, 0xb9, 0x9c, 0xa0, 0x28, + 0xd3, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xa8, 0xec, + 0x44, 0x38, 0xfb, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0xcb, 0xd3, 0x41, 0xd1, 0x01, 0x00, 0x00, 0xcc, + 0x38, 0x02, 0x01, 0x00, 0x00, 0xc7, 0xc8, 0x9e, + 0xb9, 0x9c, 0xf1, 0xcd, 0x38, 0x02, 0x01, 0x00, + 0x00, 0xc7, 0xc8, 0x9f, 0xb9, 0x9c, 0xf1, 0xce, + 0xd3, 0x41, 0xd2, 0x01, 0x00, 0x00, 0xb7, 0xa4, + 0xec, 0x04, 0xca, 0x8d, 0xce, 0x38, 0xe6, 0x00, + 0x00, 0x00, 0x42, 0x8c, 0x01, 0x00, 0x00, 0xc9, + 0xca, 0x25, 0x02, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0xdb, 0xb7, 0xa4, 0xec, 0x19, + 0x38, 0xe6, 0x00, 0x00, 0x00, 0xb7, 0x38, 0xe4, + 0x00, 0x00, 0x00, 0x42, 0x02, 0x01, 0x00, 0x00, + 0xd3, 0x8d, 0x24, 0x01, 0x00, 0x23, 0x02, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x02, 0x01, + 0x00, 0x00, 0xd3, 0x25, 0x01, 0x00, 0xdc, 0x04, + 0xa9, 0x13, 0x0e, 0x05, 0x30, 0x1c, 0x35, 0x2b, + 0x26, 0x3f, 0x3f, 0x35, 0x12, 0x4f, 0x2b, 0x17, + 0x7c, 0x0e, 0x43, 0x06, 0x05, 0x86, 0x04, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, 0x03, 0x01, + 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, 0x04, 0xc0, + 0x13, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, 0x88, + 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x09, + 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0x42, + 0x04, 0x01, 0x00, 0x00, 0x25, 0x00, 0x00, 0xdc, + 0x04, 0xc5, 0x13, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x05, 0x8a, 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x13, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0x38, 0x04, 0x01, 0x00, 0x00, 0xd3, 0xf1, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x41, 0x88, 0x01, 0x00, + 0x00, 0x9b, 0x28, 0xdc, 0x04, 0xca, 0x13, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x05, 0x8c, 0x04, 0x01, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0x38, 0x04, 0x01, 0x00, + 0x00, 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x41, 0x89, 0x01, 0x00, 0x00, 0x9b, 0x28, 0xdc, + 0x04, 0xcf, 0x13, 0x01, 0x04, 0x0e, 0x43, 0x06, + 0x05, 0x8e, 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x0b, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0x38, 0x06, 0x01, 0x00, 0x00, 0xd3, 0xf1, 0xbf, + 0x0a, 0x9b, 0x28, 0xdc, 0x04, 0xd4, 0x13, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x05, 0x90, 0x04, 0x01, + 0x00, 0x01, 0x03, 0x00, 0x00, 0x08, 0x01, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xbf, 0x0a, 0xd3, 0xbf, + 0x0a, 0x9c, 0xa0, 0x28, 0xdc, 0x04, 0xd9, 0x13, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, 0x92, 0x04, + 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, 0x43, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, + 0x00, 0x00, 0xd3, 0x38, 0xe6, 0x00, 0x00, 0x00, + 0xa8, 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x38, 0xeb, + 0x00, 0x00, 0x00, 0xa8, 0xec, 0x1c, 0x38, 0x03, + 0x01, 0x00, 0x00, 0xd3, 0x38, 0xed, 0x00, 0x00, + 0x00, 0x9b, 0xf1, 0xcf, 0xb8, 0xc7, 0x9c, 0x9f, + 0xb9, 0x38, 0xed, 0x00, 0x00, 0x00, 0x9b, 0x9c, + 0x28, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x09, + 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xde, + 0x13, 0x05, 0x05, 0x67, 0x49, 0x3f, 0x08, 0x0e, + 0x43, 0x06, 0x05, 0x94, 0x04, 0x01, 0x01, 0x01, + 0x04, 0x00, 0x00, 0x3d, 0x02, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xe0, 0x06, 0x00, 0x00, 0x00, 0xd3, + 0x38, 0xe6, 0x00, 0x00, 0x00, 0xa8, 0x11, 0xed, + 0x09, 0x0e, 0xd3, 0x38, 0xeb, 0x00, 0x00, 0x00, + 0xa8, 0xec, 0x16, 0x38, 0x03, 0x01, 0x00, 0x00, + 0xd3, 0x38, 0xed, 0x00, 0x00, 0x00, 0x9b, 0xf1, + 0xcf, 0xb8, 0xc7, 0x9c, 0x9e, 0xb9, 0x9c, 0x28, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x0a, 0x01, + 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, + 0xf1, 0x25, 0x01, 0x00, 0xdc, 0x04, 0xe9, 0x13, + 0x05, 0x05, 0x67, 0x49, 0x21, 0x08, 0x0e, 0x43, + 0x06, 0x05, 0x96, 0x04, 0x01, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x38, 0x01, 0xc0, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0x38, 0xe6, 0x00, 0x00, 0x00, 0xa8, + 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x38, 0xeb, 0x00, + 0x00, 0x00, 0xa8, 0xec, 0x11, 0x38, 0x09, 0x01, + 0x00, 0x00, 0xd3, 0xf1, 0x38, 0x0a, 0x01, 0x00, + 0x00, 0xd3, 0xf1, 0x9c, 0x28, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x42, 0x0b, 0x01, 0x00, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x25, 0x01, + 0x00, 0xdc, 0x04, 0xf4, 0x13, 0x04, 0x04, 0x67, + 0x4e, 0x08, 0x0e, 0x43, 0x06, 0x05, 0x98, 0x04, + 0x01, 0x00, 0x01, 0x04, 0x00, 0x00, 0x14, 0x01, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x42, 0x0c, 0x01, 0x00, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0x25, 0x01, + 0x00, 0xdc, 0x04, 0xfd, 0x13, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x05, 0x9a, 0x04, 0x01, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x14, 0x01, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x0d, 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x25, 0x01, 0x00, 0xdc, 0x04, + 0x82, 0x14, 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, + 0x9c, 0x04, 0x01, 0x00, 0x01, 0x04, 0x00, 0x00, + 0x14, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, 0x38, + 0xe4, 0x00, 0x00, 0x00, 0x42, 0x0e, 0x01, 0x00, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, + 0x25, 0x01, 0x00, 0xdc, 0x04, 0x87, 0x14, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x05, 0x9e, 0x04, 0x02, + 0x00, 0x02, 0x05, 0x00, 0x00, 0x1b, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xc4, 0x06, 0x00, 0x01, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x0f, + 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd4, + 0xf1, 0x25, 0x02, 0x00, 0xdc, 0x04, 0x8c, 0x14, + 0x01, 0x04, 0x0e, 0x43, 0x06, 0x05, 0xa0, 0x04, + 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1e, 0x01, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd3, 0xb7, 0xaa, + 0xec, 0x03, 0xb8, 0x28, 0xd3, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x41, 0x2a, 0x01, 0x00, 0x00, 0x9b, + 0xd7, 0x38, 0x09, 0x01, 0x00, 0x00, 0xd3, 0xf1, + 0xd3, 0x9c, 0x28, 0xdc, 0x04, 0x91, 0x14, 0x05, + 0x04, 0x1c, 0x08, 0x08, 0x44, 0x0e, 0x43, 0x06, + 0x05, 0xa2, 0x04, 0x01, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x11, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x00, + 0xd3, 0xc0, 0xb4, 0x00, 0x9b, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0x41, 0x2a, 0x01, 0x00, 0x00, 0x9c, + 0x28, 0xdc, 0x04, 0x9b, 0x14, 0x01, 0x04, 0x0e, + 0x43, 0x06, 0x05, 0xa4, 0x04, 0x01, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x11, 0x01, 0xc0, 0x06, 0x00, + 0x01, 0x00, 0xd3, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x41, 0x2a, 0x01, 0x00, 0x00, 0x9b, 0xc0, 0xb4, + 0x00, 0x9c, 0x28, 0xdc, 0x04, 0xa0, 0x14, 0x01, + 0x04, 0x0e, 0x43, 0x06, 0x05, 0xa6, 0x04, 0x01, + 0x01, 0x01, 0x04, 0x00, 0x01, 0x20, 0x02, 0xc0, + 0x06, 0x00, 0x01, 0x00, 0xd8, 0x07, 0x00, 0x00, + 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, 0x03, + 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0xd3, 0xf1, 0x24, 0x01, 0x00, 0xcf, 0xb8, 0xc7, + 0x9c, 0x9f, 0xc1, 0x00, 0xbf, 0xed, 0xb3, 0x9b, + 0x28, 0xdc, 0x04, 0xa5, 0x14, 0x02, 0x04, 0x67, + 0x0b, 0x88, 0x02, 0x06, 0xe8, 0x89, 0x04, 0x23, + 0xc7, 0x8a, 0x0e, 0x43, 0x06, 0x05, 0xa8, 0x04, + 0x01, 0x01, 0x01, 0x04, 0x00, 0x01, 0x20, 0x02, + 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd8, 0x07, 0x00, + 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, 0x42, + 0x03, 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0x24, 0x01, 0x00, 0xcf, 0xb8, + 0xc7, 0x9c, 0x9e, 0xc1, 0x00, 0xbf, 0xed, 0xb3, + 0x9b, 0x28, 0xdc, 0x04, 0xab, 0x14, 0x02, 0x04, + 0x67, 0x0b, 0x88, 0x02, 0x06, 0xe8, 0x89, 0x04, + 0x23, 0xc7, 0x8a, 0x0e, 0x43, 0x06, 0x05, 0xaa, + 0x04, 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, 0x1e, + 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xd8, 0x07, + 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, 0x00, + 0x42, 0x03, 0x01, 0x00, 0x00, 0x38, 0xe4, 0x00, + 0x00, 0x00, 0xd3, 0xf1, 0xb9, 0x9b, 0x24, 0x01, + 0x00, 0xcf, 0xb8, 0x9f, 0xc7, 0xb8, 0x9e, 0x9c, + 0x28, 0xdc, 0x04, 0xb1, 0x14, 0x02, 0x04, 0x71, + 0x0e, 0x43, 0x06, 0x05, 0xac, 0x04, 0x01, 0x01, + 0x01, 0x04, 0x00, 0x00, 0x1d, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xea, 0x06, 0x00, 0x00, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xcb, + 0x38, 0x04, 0x01, 0x00, 0x00, 0x38, 0x02, 0x01, + 0x00, 0x00, 0xc7, 0xc7, 0x9b, 0xb8, 0x9e, 0xf1, + 0xc7, 0x9e, 0x23, 0x01, 0x00, 0xdc, 0x04, 0xb7, + 0x14, 0x02, 0x04, 0x2b, 0x0e, 0x43, 0x06, 0x05, + 0xae, 0x04, 0x01, 0x01, 0x01, 0x04, 0x00, 0x00, + 0x1d, 0x02, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xea, + 0x06, 0x00, 0x00, 0x00, 0x38, 0xe4, 0x00, 0x00, + 0x00, 0xd3, 0xf1, 0xcb, 0x38, 0x04, 0x01, 0x00, + 0x00, 0x38, 0x02, 0x01, 0x00, 0x00, 0xc7, 0xc7, + 0x9b, 0xb8, 0x9f, 0xf1, 0xc7, 0x9e, 0x23, 0x01, + 0x00, 0xdc, 0x04, 0xbd, 0x14, 0x02, 0x04, 0x2b, + 0x0e, 0x43, 0x06, 0x05, 0xb0, 0x04, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x01, 0x1c, 0x02, 0xc0, 0x06, + 0x00, 0x01, 0x00, 0xea, 0x06, 0x00, 0x00, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xcb, + 0xc1, 0x00, 0xbf, 0xed, 0xb3, 0x38, 0x04, 0x01, + 0x00, 0x00, 0xb8, 0xc7, 0x9e, 0xb8, 0xc7, 0x9f, + 0x9c, 0xf1, 0x9b, 0x28, 0xdc, 0x04, 0xc3, 0x14, + 0x02, 0x04, 0x2b, 0x0b, 0x88, 0x02, 0x06, 0xe8, + 0x89, 0x04, 0x23, 0xc7, 0x8a, 0x0e, 0x43, 0x06, + 0x05, 0xb2, 0x04, 0x01, 0x00, 0x01, 0x04, 0x00, + 0x00, 0x15, 0x01, 0xea, 0x06, 0x00, 0x01, 0x00, + 0x38, 0xe4, 0x00, 0x00, 0x00, 0xd3, 0xf1, 0xd7, + 0xb8, 0xb8, 0x38, 0x03, 0x01, 0x00, 0x00, 0xd3, + 0x8d, 0xf1, 0x9e, 0x9c, 0x28, 0xdc, 0x04, 0xc9, + 0x14, 0x02, 0x04, 0x2b, 0x0e, 0x43, 0x06, 0x05, + 0xb4, 0x04, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x08, 0x03, 0xc0, 0x06, 0x00, 0x01, 0x00, 0xc4, + 0x06, 0x00, 0x01, 0x00, 0xe0, 0x06, 0x00, 0x01, + 0x00, 0xd3, 0xd4, 0xd3, 0x9f, 0xd5, 0x9b, 0x9e, + 0x28, 0xdc, 0x04, 0xcf, 0x14, 0x01, 0x04, +}; + diff --git a/deps/quickjs/qjscalc.js b/deps/quickjs/qjscalc.js new file mode 100644 index 0000000..b1ad1e8 --- /dev/null +++ b/deps/quickjs/qjscalc.js @@ -0,0 +1,2657 @@ +/* + * QuickJS Javascript Calculator + * + * Copyright (c) 2017-2020 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +"use strict"; +"use math"; + +var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunction, Series, Matrix; + +(function(global) { + global.Integer = global.BigInt; + global.Float = global.BigFloat; + global.algebraicMode = true; + + /* add non enumerable properties */ + function add_props(obj, props) { + var i, val, prop, tab, desc; + tab = Reflect.ownKeys(props); + for(i = 0; i < tab.length; i++) { + prop = tab[i]; + desc = Object.getOwnPropertyDescriptor(props, prop); + desc.enumerable = false; + if ("value" in desc) { + if (typeof desc.value !== "function") { + desc.writable = false; + desc.configurable = false; + } + } else { + /* getter/setter */ + desc.configurable = false; + } + Object.defineProperty(obj, prop, desc); + } + } + + /* same as proto[Symbol.operatorSet] = Operators.create(..op_list) + but allow shortcuts: left: [], right: [] or both + */ + function operators_set(proto, ...op_list) + { + var new_op_list, i, a, j, b, k, obj, tab; + var fields = [ "left", "right" ]; + new_op_list = []; + for(i = 0; i < op_list.length; i++) { + a = op_list[i]; + if (a.left || a.right) { + tab = [ a.left, a.right ]; + delete a.left; + delete a.right; + for(k = 0; k < 2; k++) { + obj = tab[k]; + if (obj) { + if (!Array.isArray(obj)) { + obj = [ obj ]; + } + for(j = 0; j < obj.length; j++) { + b = {}; + Object.assign(b, a); + b[fields[k]] = obj[j]; + new_op_list.push(b); + } + } + } + } else { + new_op_list.push(a); + } + } + proto[Symbol.operatorSet] = + Operators.create.call(null, ...new_op_list); + } + + /* Integer */ + + function generic_pow(a, b) { + var r, is_neg, i; + if (!Integer.isInteger(b)) { + return exp(log(a) * b); + } + if (Array.isArray(a) && !(a instanceof Polynomial || + a instanceof Series)) { + r = idn(Matrix.check_square(a)); + } else { + r = 1; + } + if (b == 0) + return r; + is_neg = false; + if (b < 0) { + is_neg = true; + b = -b; + } + r = a; + for(i = Integer.floorLog2(b) - 1; i >= 0; i--) { + r *= r; + if ((b >> i) & 1) + r *= a; + } + if (is_neg) { + if (typeof r.inverse != "function") + throw "negative powers are not supported for this type"; + r = r.inverse(); + } + return r; + } + + var small_primes = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499 ]; + + function miller_rabin_test(n, t) { + var d, r, s, i, j, a; + d = n - 1; + s = 0; + while ((d & 1) == 0) { + d >>= 1; + s++; + } + if (small_primes.length < t) + t = small_primes.length; + loop: for(j = 0; j < t; j++) { + a = small_primes[j]; + r = Integer.pmod(a, d, n); + if (r == 1 || r == (n - 1)) + continue; + for(i = 1; i < s; i++) { + r = (r * r) % n; + if (r == 1) + return false; + if (r == (n - 1)) + continue loop; + } + return false; /* n is composite */ + } + return true; /* n is probably prime with probability (1-0.5^t) */ + } + + function fact_rec(a, b) { /* assumes a <= b */ + var i, r; + if ((b - a) <= 5) { + r = a; + for(i = a + 1; i <= b; i++) + r *= i; + return r; + } else { + /* to avoid a quadratic running time it is better to + multiply numbers of similar size */ + i = (a + b) >> 1; + return fact_rec(a, i) * fact_rec(i + 1, b); + } + } + + /* math mode specific quirk to overload the integer division and power */ + Operators.updateBigIntOperators( + { + "/"(a, b) { + if (algebraicMode) { + return Fraction.toFraction(a, b); + } else { + return Float(a) / Float(b); + } + }, + "**"(a, b) { + if (algebraicMode) { + return generic_pow(a, b); + } else { + return Float(a) ** Float(b); + } + } + }); + + add_props(Integer, { + isInteger(a) { + /* integers are represented either as bigint or as number */ + return typeof a === "bigint" || + (typeof a === "number" && Number.isSafeInteger(a)); + }, + gcd(a, b) { + var r; + while (b != 0) { + r = a % b; + a = b; + b = r; + } + return a; + }, + fact(n) { + return n <= 0 ? 1 : fact_rec(1, n); + }, + /* binomial coefficient */ + comb(n, k) { + if (k < 0 || k > n) + return 0; + if (k > n - k) + k = n - k; + if (k == 0) + return 1; + return Integer.tdiv(fact_rec(n - k + 1, n), fact_rec(1, k)); + }, + /* inverse of x modulo y */ + invmod(x, y) { + var q, u, v, a, c, t; + u = x; + v = y; + c = 1; + a = 0; + while (u != 0) { + t = Integer.fdivrem(v, u); + q = t[0]; + v = u; + u = t[1]; + t = c; + c = a - q * c; + a = t; + } + /* v = gcd(x, y) */ + if (v != 1) + throw RangeError("not invertible"); + return a % y; + }, + /* return a ^ b modulo m */ + pmod(a, b, m) { + var r; + if (b == 0) + return 1; + if (b < 0) { + a = Integer.invmod(a, m); + b = -b; + } + r = 1; + for(;;) { + if (b & 1) { + r = (r * a) % m; + } + b >>= 1; + if (b == 0) + break; + a = (a * a) % m; + } + return r; + }, + + /* return true if n is prime (or probably prime with + probability 1-0.5^t) */ + isPrime(n, t) { + var i, d, n1; + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + if (n <= 1) + return false; + n1 = small_primes.length; + /* XXX: need Integer.sqrt() */ + for(i = 0; i < n1; i++) { + d = small_primes[i]; + if (d == n) + return true; + if (d > n) + return false; + if ((n % d) == 0) + return false; + } + if (n < d * d) + return true; + if (typeof t == "undefined") + t = 64; + return miller_rabin_test(n, t); + }, + nextPrime(n) { + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + if (n < 1) + n = 1; + for(;;) { + n++; + if (Integer.isPrime(n)) + return n; + } + }, + factor(n) { + var r, d; + if (!Integer.isInteger(n)) + throw TypeError("invalid type"); + r = []; + if (abs(n) <= 1) { + r.push(n); + return r; + } + if (n < 0) { + r.push(-1); + n = -n; + } + + while ((n % 2) == 0) { + n >>= 1; + r.push(2); + } + + d = 3; + while (n != 1) { + if (Integer.isPrime(n)) { + r.push(n); + break; + } + /* we are sure there is at least one divisor, so one test */ + for(;;) { + if ((n % d) == 0) + break; + d += 2; + } + for(;;) { + r.push(d); + n = Integer.tdiv(n, d); + if ((n % d) != 0) + break; + } + } + return r; + }, + }); + + add_props(Integer.prototype, { + inverse() { + return 1 / this; + }, + norm2() { + return this * this; + }, + abs() { + var v = this; + if (v < 0) + v = -v; + return v; + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + if (this == 0) + return 1; + else + return Float.exp(this); + }, + log() { + if (this == 1) + return 0; + else + return Float(this).log(); + }, + }); + + /* Fraction */ + + Fraction = function Fraction(a, b) + { + var d, r, obj; + + if (new.target) + throw TypeError("not a constructor"); + if (a instanceof Fraction) + return a; + if (!Integer.isInteger(a)) + throw TypeError("integer expected"); + if (typeof b === "undefined") { + b = 1; + } else { + if (!Integer.isInteger(b)) + throw TypeError("integer expected"); + if (b == 0) + throw RangeError("division by zero"); + d = Integer.gcd(a, b); + if (d != 1) { + a = Integer.tdiv(a, d); + b = Integer.tdiv(b, d); + } + + /* the fractions are normalized with den > 0 */ + if (b < 0) { + a = -a; + b = -b; + } + } + obj = Object.create(Fraction.prototype); + obj.num = a; + obj.den = b; + return obj; + } + + function fraction_add(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den + a.den * b.num, a.den * b.den); + } + function fraction_sub(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den - a.den * b.num, a.den * b.den); + } + function fraction_mul(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.num, a.den * b.den); + } + function fraction_div(a, b) { + a = Fraction(a); + b = Fraction(b); + return Fraction.toFraction(a.num * b.den, a.den * b.num); + } + function fraction_mod(a, b) { + var a1 = Fraction(a); + var b1 = Fraction(b); + return a - Integer.ediv(a1.num * b1.den, a1.den * b1.num) * b; + } + function fraction_eq(a, b) { + a = Fraction(a); + b = Fraction(b); + /* we assume the fractions are normalized */ + return (a.num == b.num && a.den == b.den); + } + function fraction_lt(a, b) { + a = Fraction(a); + b = Fraction(b); + return (a.num * b.den < b.num * a.den); + } + + /* operators are needed for fractions */ + function float_add(a, b) { + return Float(a) + Float(b); + } + function float_sub(a, b) { + return Float(a) - Float(b); + } + function float_mul(a, b) { + return Float(a) * Float(b); + } + function float_div(a, b) { + return Float(a) / Float(b); + } + function float_mod(a, b) { + return Float(a) % Float(b); + } + function float_pow(a, b) { + return Float(a) ** Float(b); + } + function float_eq(a, b) { + /* XXX: may be better to use infinite precision for the comparison */ + return Float(a) === Float(b); + } + function float_lt(a, b) { + a = Float(a); + b = Float(b); + /* XXX: may be better to use infinite precision for the comparison */ + if (Float.isNaN(a) || Float.isNaN(b)) + return undefined; + else + return a < b; + } + + operators_set(Fraction.prototype, + { + "+": fraction_add, + "-": fraction_sub, + "*": fraction_mul, + "/": fraction_div, + "%": fraction_mod, + "**": generic_pow, + "==": fraction_eq, + "<": fraction_lt, + "pos"(a) { + return a; + }, + "neg"(a) { + return Fraction(-a.num, a.den); + }, + }, + { + left: [Number, BigInt], + right: [Number, BigInt], + "+": fraction_add, + "-": fraction_sub, + "*": fraction_mul, + "/": fraction_div, + "%": fraction_mod, + "**": generic_pow, + "==": fraction_eq, + "<": fraction_lt, + }, + { + left: Float, + right: Float, + "+": float_add, + "-": float_sub, + "*": float_mul, + "/": float_div, + "%": float_mod, + "**": float_pow, + "==": float_eq, + "<": float_lt, + }); + + add_props(Fraction, { + /* (internal use) simplify 'a' to an integer when possible */ + toFraction(a, b) { + var r = Fraction(a, b); + if (algebraicMode && r.den == 1) + return r.num; + else + return r; + }, + }); + + add_props(Fraction.prototype, { + [Symbol.toPrimitive](hint) { + if (hint === "string") { + return this.toString(); + } else { + return Float(this.num) / this.den; + } + }, + inverse() { + return Fraction(this.den, this.num); + }, + toString() { + return this.num + "/" + this.den; + }, + norm2() { + return this * this; + }, + abs() { + if (this.num < 0) + return -this; + else + return this; + }, + conj() { + return this; + }, + arg() { + if (this.num >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(Float(this)); + }, + log() { + return Float(this).log(); + }, + }); + + /* Number (Float64) */ + + add_props(Number.prototype, { + inverse() { + return 1 / this; + }, + norm2() { + return this * this; + }, + abs() { + return Math.abs(this); + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(this); + }, + log() { + if (this < 0) { + return Complex(this).log(); + } else { + return Float.log(this); + } + }, + }); + + /* Float */ + + var const_tab = []; + + /* we cache the constants for small precisions */ + function get_const(n) { + var t, c, p; + t = const_tab[n]; + p = BigFloatEnv.prec; + if (t && t.prec == p) { + return t.val; + } else { + switch(n) { + case 0: c = Float.exp(1); break; + case 1: c = Float.log(10); break; +// case 2: c = Float.log(2); break; + case 3: c = 1/Float.log(2); break; + case 4: c = 1/Float.log(10); break; +// case 5: c = Float.atan(1) * 4; break; + case 6: c = Float.sqrt(0.5); break; + case 7: c = Float.sqrt(2); break; + } + if (p <= 1024) { + const_tab[n] = { prec: p, val: c }; + } + return c; + } + } + + add_props(Float, { + isFloat(a) { + return typeof a === "number" || typeof a === "bigfloat"; + }, + bestappr(u, b) { + var num1, num0, den1, den0, u, num, den, n; + + if (typeof b === "undefined") + throw TypeError("second argument expected"); + num1 = 1; + num0 = 0; + den1 = 0; + den0 = 1; + for(;;) { + n = Integer(Float.floor(u)); + num = n * num1 + num0; + den = n * den1 + den0; + if (den > b) + break; + u = 1.0 / (u - n); + num0 = num1; + num1 = num; + den0 = den1; + den1 = den; + } + return Fraction(num1, den1); + }, + /* similar constants as Math.x */ + get E() { return get_const(0); }, + get LN10() { return get_const(1); }, +// get LN2() { return get_const(2); }, + get LOG2E() { return get_const(3); }, + get LOG10E() { return get_const(4); }, +// get PI() { return get_const(5); }, + get SQRT1_2() { return get_const(6); }, + get SQRT2() { return get_const(7); }, + }); + + add_props(Float.prototype, { + inverse() { + return 1.0 / this; + }, + norm2() { + return this * this; + }, + abs() { + return Float.abs(this); + }, + conj() { + return this; + }, + arg() { + if (this >= 0) + return 0; + else + return Float.PI; + }, + exp() { + return Float.exp(this); + }, + log() { + if (this < 0) { + return Complex(this).log(); + } else { + return Float.log(this); + } + }, + }); + + /* Complex */ + + Complex = function Complex(re, im) + { + var obj; + if (new.target) + throw TypeError("not a constructor"); + if (re instanceof Complex) + return re; + if (typeof im === "undefined") { + im = 0; + } + obj = Object.create(Complex.prototype); + obj.re = re; + obj.im = im; + return obj; + } + + + function complex_add(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re + b.re, a.im + b.im); + } + function complex_sub(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re - b.re, a.im - b.im); + } + function complex_mul(a, b) { + a = Complex(a); + b = Complex(b); + return Complex.toComplex(a.re * b.re - a.im * b.im, + a.re * b.im + a.im * b.re); + } + function complex_div(a, b) { + a = Complex(a); + b = Complex(b); + return a * b.inverse(); + } + function complex_eq(a, b) { + a = Complex(a); + b = Complex(b); + return a.re == b.re && a.im == b.im; + } + + operators_set(Complex.prototype, + { + "+": complex_add, + "-": complex_sub, + "*": complex_mul, + "/": complex_div, + "**": generic_pow, + "==": complex_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return Complex(-a.re, -a.im); + } + }, + { + left: [Number, BigInt, Float, Fraction], + right: [Number, BigInt, Float, Fraction], + "+": complex_add, + "-": complex_sub, + "*": complex_mul, + "/": complex_div, + "**": generic_pow, + "==": complex_eq, + }); + + add_props(Complex, { + /* simplify to real number when possible */ + toComplex(re, im) { + if (algebraicMode && im == 0) + return re; + else + return Complex(re, im); + }, + }); + + add_props(Complex.prototype, { + inverse() { + var c = this.norm2(); + return Complex(this.re / c, -this.im / c); + }, + toString() { + var v, s = "", a = this; + if (a.re != 0) + s += a.re.toString(); + if (a.im == 1) { + if (s != "") + s += "+"; + s += "I"; + } else if (a.im == -1) { + s += "-I"; + } else { + v = a.im.toString(); + if (v[0] != "-" && s != "") + s += "+"; + s += v + "*I"; + } + return s; + }, + norm2() { + return this.re * this.re + this.im * this.im; + }, + abs() { + return Float.sqrt(norm2(this)); + }, + conj() { + return Complex(this.re, -this.im); + }, + arg() { + return Float.atan2(this.im, this.re); + }, + exp() { + var arg = this.im, r = this.re.exp(); + return Complex(r * cos(arg), r * sin(arg)); + }, + log() { + return Complex(abs(this).log(), atan2(this.im, this.re)); + }, + }); + + /* Mod */ + + Mod = function Mod(a, m) { + var obj, t; + if (new.target) + throw TypeError("not a constructor"); + obj = Object.create(Mod.prototype); + if (Integer.isInteger(m)) { + if (m <= 0) + throw RangeError("the modulo cannot be <= 0"); + if (Integer.isInteger(a)) { + a %= m; + } else if (a instanceof Fraction) { + return Mod(a.num, m) / a.den; + } else { + throw TypeError("invalid types"); + } + } else { + throw TypeError("invalid types"); + } + obj.res = a; + obj.mod = m; + return obj; + }; + + function mod_add(a, b) { + if (!(a instanceof Mod)) { + return Mod(a + b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res + b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res + b.res, a.mod); + } + } + function mod_sub(a, b) { + if (!(a instanceof Mod)) { + return Mod(a - b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res - b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res - b.res, a.mod); + } + } + function mod_mul(a, b) { + if (!(a instanceof Mod)) { + return Mod(a * b.res, b.mod); + } else if (!(b instanceof Mod)) { + return Mod(a.res * b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return Mod(a.res * b.res, a.mod); + } + } + function mod_div(a, b) { + if (!(b instanceof Mod)) + b = Mod(b, a.mod); + return mod_mul(a, b.inverse()); + } + function mod_eq(a, b) { + return (a.mod == b.mod && a.res == b.res); + } + + operators_set(Mod.prototype, + { + "+": mod_add, + "-": mod_sub, + "*": mod_mul, + "/": mod_div, + "**": generic_pow, + "==": mod_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return Mod(-a.res, a.mod); + } + }, + { + left: [Number, BigInt, Float, Fraction], + right: [Number, BigInt, Float, Fraction], + "+": mod_add, + "-": mod_sub, + "*": mod_mul, + "/": mod_div, + "**": generic_pow, + }); + + add_props(Mod.prototype, { + inverse() { + var a = this, m = a.mod; + if (Integer.isInteger(m)) { + return Mod(Integer.invmod(a.res, m), m); + } else { + throw TypeError("unsupported type"); + } + }, + toString() { + return "Mod(" + this.res + "," + this.mod + ")"; + }, + }); + + /* Polynomial */ + + function polynomial_is_scalar(a) + { + if (typeof a === "number" || + typeof a === "bigint" || + typeof a === "bigfloat") + return true; + if (a instanceof Fraction || + a instanceof Complex || + a instanceof Mod) + return true; + return false; + } + + Polynomial = function Polynomial(a) + { + if (new.target) + throw TypeError("not a constructor"); + if (a instanceof Polynomial) { + return a; + } else if (Array.isArray(a)) { + if (a.length == 0) + a = [ 0 ]; + Object.setPrototypeOf(a, Polynomial.prototype); + return a.trim(); + } else if (polynomial_is_scalar(a)) { + a = [a]; + Object.setPrototypeOf(a, Polynomial.prototype); + return a; + } else { + throw TypeError("invalid type"); + } + } + + function number_need_paren(c) + { + return !(Integer.isInteger(c) || + Float.isFloat(c) || + c instanceof Fraction || + (c instanceof Complex && c.re == 0)); + } + + /* string for c*X^i */ + function monomial_toString(c, i) + { + var str1; + if (i == 0) { + str1 = c.toString(); + } else { + if (c == 1) { + str1 = ""; + } else if (c == -1) { + str1 = "-"; + } else { + if (number_need_paren(c)) { + str1 = "(" + c + ")"; + } else { + str1 = String(c); + } + str1 += "*"; + } + str1 += "X"; + if (i != 1) { + str1 += "^" + i; + } + } + return str1; + } + + /* find one complex root of 'p' starting from z at precision eps using + at most max_it iterations. Return null if could not find root. */ + function poly_root_laguerre1(p, z, max_it) + { + var p1, p2, i, z0, z1, z2, d, t0, t1, d1, d2, e, el, zl; + + d = p.deg(); + if (d == 1) { + /* monomial case */ + return -p[0] / p[1]; + } + /* trivial zero */ + if (p[0] == 0) + return 0.0; + + p1 = p.deriv(); + p2 = p1.deriv(); + el = 0.0; + zl = 0.0; + for(i = 0; i < max_it; i++) { + z0 = p.apply(z); + if (z0 == 0) + return z; /* simple exit case */ + + /* Ward stopping criteria */ + e = abs(z - zl); +// print("e", i, e); + if (i >= 2 && e >= el) { + if (abs(zl) < 1e-4) { + if (e < 1e-7) + return zl; + } else { + if (e < abs(zl) * 1e-3) + return zl; + } + } + el = e; + zl = z; + + z1 = p1.apply(z); + z2 = p2.apply(z); + t0 = (d - 1) * z1; + t0 = t0 * t0; + t1 = d * (d - 1) * z0 * z2; + t0 = sqrt(t0 - t1); + d1 = z1 + t0; + d2 = z1 - t0; + if (norm2(d2) > norm2(d1)) + d1 = d2; + if (d1 == 0) + return null; + z = z - d * z0 / d1; + } + return null; + } + + function poly_roots(p) + { + var d, i, roots, j, z, eps; + var start_points = [ 0.1, -1.4, 1.7 ]; + + if (!(p instanceof Polynomial)) + throw TypeError("polynomial expected"); + d = p.deg(); + if (d <= 0) + return []; + eps = 2.0 ^ (-BigFloatEnv.prec); + roots = []; + for(i = 0; i < d; i++) { + /* XXX: should select another start point if error */ + for(j = 0; j < 3; j++) { + z = poly_root_laguerre1(p, start_points[j], 100); + if (z !== null) + break; + } + if (j == 3) + throw RangeError("error in root finding algorithm"); + roots[i] = z; + p = Polynomial.divrem(p, X - z)[0]; + } + return roots; + } + + add_props(Polynomial.prototype, { + trim() { + var a = this, i; + i = a.length; + while (i > 1 && a[i - 1] == 0) + i--; + a.length = i; + return a; + }, + conj() { + var r, i, n, a; + a = this; + n = a.length; + r = []; + for(i = 0; i < n; i++) + r[i] = a[i].conj(); + return Polynomial(r); + }, + inverse() { + return RationalFunction(Polynomial([1]), this); + }, + toString() { + var i, str, str1, c, a = this; + if (a.length == 1) { + return a[0].toString(); + } + str=""; + for(i = a.length - 1; i >= 0; i--) { + c = a[i]; + if (c == 0 || + (c instanceof Mod) && c.res == 0) + continue; + str1 = monomial_toString(c, i); + if (str1[0] != "-") { + if (str != "") + str += "+"; + } + str += str1; + } + return str; + }, + deg() { + if (this.length == 1 && this[0] == 0) + return -Infinity; + else + return this.length - 1; + }, + apply(b) { + var i, n, r, a = this; + n = a.length - 1; + r = a[n]; + while (n > 0) { + n--; + r = r * b + a[n]; + } + return r; + }, + deriv() { + var a = this, n, r, i; + n = a.length; + if (n == 1) { + return Polynomial(0); + } else { + r = []; + for(i = 1; i < n; i++) { + r[i - 1] = i * a[i]; + } + return Polynomial(r); + } + }, + integ() { + var a = this, n, r, i; + n = a.length; + r = [0]; + for(i = 0; i < n; i++) { + r[i + 1] = a[i] / (i + 1); + } + return Polynomial(r); + }, + norm2() { + var a = this, n, r, i; + n = a.length; + r = 0; + for(i = 0; i < n; i++) { + r += a[i].norm2(); + } + return r; + }, + }); + + + function polynomial_add(a, b) { + var tmp, r, i, n1, n2; + a = Polynomial(a); + b = Polynomial(b); + if (a.length < b.length) { + tmp = a; + a = b; + b = tmp; + } + n1 = b.length; + n2 = a.length; + r = []; + for(i = 0; i < n1; i++) + r[i] = a[i] + b[i]; + for(i = n1; i < n2; i++) + r[i] = a[i]; + return Polynomial(r); + } + function polynomial_sub(a, b) { + return polynomial_add(a, -b); + } + function polynomial_mul(a, b) { + var i, j, n1, n2, n, r; + a = Polynomial(a); + b = Polynomial(b); + n1 = a.length; + n2 = b.length; + n = n1 + n2 - 1; + r = []; + for(i = 0; i < n; i++) + r[i] = 0; + for(i = 0; i < n1; i++) { + for(j = 0; j < n2; j++) { + r[i + j] += a[i] * b[j]; + } + } + return Polynomial(r); + } + function polynomial_div_scalar(a, b) { + return a * (1 / b); + } + function polynomial_div(a, b) + { + return RationalFunction(Polynomial(a), + Polynomial(b)); + } + function polynomial_mod(a, b) { + return Polynomial.divrem(a, b)[1]; + } + function polynomial_eq(a, b) { + var n, i; + n = a.length; + if (n != b.length) + return false; + for(i = 0; i < n; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + operators_set(Polynomial.prototype, + { + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div, + "**": generic_pow, + "==": polynomial_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + var r, i, n, a; + n = a.length; + r = []; + for(i = 0; i < n; i++) + r[i] = -a[i]; + return Polynomial(r); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod], + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div, + "**": generic_pow, /* XXX: only for integer */ + }, + { + right: [Number, BigInt, Float, Fraction, Complex, Mod], + "+": polynomial_add, + "-": polynomial_sub, + "*": polynomial_mul, + "/": polynomial_div_scalar, + "**": generic_pow, /* XXX: only for integer */ + }); + + add_props(Polynomial, { + divrem(a, b) { + var n1, n2, i, j, q, r, n, c; + if (b.deg() < 0) + throw RangeError("division by zero"); + n1 = a.length; + n2 = b.length; + if (n1 < n2) + return [Polynomial([0]), a]; + r = Array.prototype.dup.call(a); + q = []; + n2--; + n = n1 - n2; + for(i = 0; i < n; i++) + q[i] = 0; + for(i = n - 1; i >= 0; i--) { + c = r[i + n2]; + if (c != 0) { + c = c / b[n2]; + r[i + n2] = 0; + for(j = 0; j < n2; j++) { + r[i + j] -= b[j] * c; + } + q[i] = c; + } + } + return [Polynomial(q), Polynomial(r)]; + }, + gcd(a, b) { + var t; + while (b.deg() >= 0) { + t = Polynomial.divrem(a, b); + a = b; + b = t[1]; + } + /* convert to monic form */ + return a / a[a.length - 1]; + }, + invmod(x, y) { + var q, u, v, a, c, t; + u = x; + v = y; + c = Polynomial([1]); + a = Polynomial([0]); + while (u.deg() >= 0) { + t = Polynomial.divrem(v, u); + q = t[0]; + v = u; + u = t[1]; + t = c; + c = a - q * c; + a = t; + } + /* v = gcd(x, y) */ + if (v.deg() > 0) + throw RangeError("not invertible"); + return Polynomial.divrem(a, y)[1]; + }, + roots(p) { + return poly_roots(p); + } + }); + + /* Polynomial Modulo Q */ + + PolyMod = function PolyMod(a, m) { + var obj, t; + if (new.target) + throw TypeError("not a constructor"); + obj = Object.create(PolyMod.prototype); + if (m instanceof Polynomial) { + if (m.deg() <= 0) + throw RangeError("the modulo cannot have a degree <= 0"); + if (a instanceof RationalFunction) { + return PolyMod(a.num, m) / a.den; + } else { + a = Polynomial(a); + t = Polynomial.divrem(a, m); + a = t[1]; + } + } else { + throw TypeError("invalid types"); + } + obj.res = a; + obj.mod = m; + return obj; + }; + + function polymod_add(a, b) { + if (!(a instanceof PolyMod)) { + return PolyMod(a + b.res, b.mod); + } else if (!(b instanceof PolyMod)) { + return PolyMod(a.res + b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return PolyMod(a.res + b.res, a.mod); + } + } + function polymod_sub(a, b) { + return polymod_add(a, -b); + } + function polymod_mul(a, b) { + if (!(a instanceof PolyMod)) { + return PolyMod(a * b.res, b.mod); + } else if (!(b instanceof PolyMod)) { + return PolyMod(a.res * b, a.mod); + } else { + if (a.mod != b.mod) + throw TypeError("different modulo for binary operator"); + return PolyMod(a.res * b.res, a.mod); + } + } + function polymod_div(a, b) { + if (!(b instanceof PolyMod)) + b = PolyMod(b, a.mod); + return polymod_mul(a, b.inverse()); + } + function polymod_eq(a, b) { + return (a.mod == b.mod && a.res == b.res); + } + + operators_set(PolyMod.prototype, + { + "+": polymod_add, + "-": polymod_sub, + "*": polymod_mul, + "/": polymod_div, + "**": generic_pow, + "==": polymod_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return PolyMod(-a.res, a.mod); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": polymod_add, + "-": polymod_sub, + "*": polymod_mul, + "/": polymod_div, + "**": generic_pow, /* XXX: only for integer */ + }); + + add_props(PolyMod.prototype, { + inverse() { + var a = this, m = a.mod; + if (m instanceof Polynomial) { + return PolyMod(Polynomial.invmod(a.res, m), m); + } else { + throw TypeError("unsupported type"); + } + }, + toString() { + return "PolyMod(" + this.res + "," + this.mod + ")"; + }, + }); + + /* Rational function */ + + RationalFunction = function RationalFunction(a, b) + { + var t, r, d, obj; + if (new.target) + throw TypeError("not a constructor"); + if (!(a instanceof Polynomial) || + !(b instanceof Polynomial)) + throw TypeError("polynomial expected"); + t = Polynomial.divrem(a, b); + r = t[1]; + if (r.deg() < 0) + return t[0]; /* no need for a fraction */ + d = Polynomial.gcd(b, r); + if (d.deg() > 0) { + a = Polynomial.divrem(a, d)[0]; + b = Polynomial.divrem(b, d)[0]; + } + obj = Object.create(RationalFunction.prototype); + obj.num = a; + obj.den = b; + return obj; + } + + add_props(RationalFunction.prototype, { + inverse() { + return RationalFunction(this.den, this.num); + }, + conj() { + return RationalFunction(this.num.conj(), this.den.conj()); + }, + toString() { + var str; + if (this.num.deg() <= 0 && + !number_need_paren(this.num[0])) + str = this.num.toString(); + else + str = "(" + this.num.toString() + ")"; + str += "/(" + this.den.toString() + ")" + return str; + }, + apply(b) { + return this.num.apply(b) / this.den.apply(b); + }, + deriv() { + var n = this.num, d = this.den; + return RationalFunction(n.deriv() * d - n * d.deriv(), d * d); + }, + }); + + function ratfunc_add(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den + a.den * b.num, a.den * b.den); + } + function ratfunc_sub(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den - a.den * b.num, a.den * b.den); + } + function ratfunc_mul(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.num, a.den * b.den); + } + function ratfunc_div(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + return RationalFunction(a.num * b.den, a.den * b.num); + } + function ratfunc_eq(a, b) { + a = RationalFunction.toRationalFunction(a); + b = RationalFunction.toRationalFunction(b); + /* we assume the fractions are normalized */ + return (a.num == b.num && a.den == b.den); + } + + operators_set(RationalFunction.prototype, + { + "+": ratfunc_add, + "-": ratfunc_sub, + "*": ratfunc_mul, + "/": ratfunc_div, + "**": generic_pow, + "==": ratfunc_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + return RationalFunction(-this.num, this.den); + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": ratfunc_add, + "-": ratfunc_sub, + "*": ratfunc_mul, + "/": ratfunc_div, + "**": generic_pow, /* should only be used with integers */ + }); + + add_props(RationalFunction, { + /* This function always return a RationalFunction object even + if it could simplified to a polynomial, so it is not + equivalent to RationalFunction(a) */ + toRationalFunction(a) { + var obj; + if (a instanceof RationalFunction) { + return a; + } else { + obj = Object.create(RationalFunction.prototype); + obj.num = Polynomial(a); + obj.den = Polynomial(1); + return obj; + } + }, + }); + + /* Power series */ + + /* 'a' is an array */ + function get_emin(a) { + var i, n; + n = a.length; + for(i = 0; i < n; i++) { + if (a[i] != 0) + return i; + } + return n; + }; + + function series_is_scalar_or_polynomial(a) + { + return polynomial_is_scalar(a) || + (a instanceof Polynomial); + } + + /* n is the maximum number of terms if 'a' is not a serie */ + Series = function Series(a, n) { + var emin, r, i; + + if (a instanceof Series) { + return a; + } else if (series_is_scalar_or_polynomial(a)) { + if (n <= 0) { + /* XXX: should still use the polynomial degree */ + return Series.zero(0, 0); + } else { + a = Polynomial(a); + emin = get_emin(a); + r = Series.zero(n, emin); + n = Math.min(a.length - emin, n); + for(i = 0; i < n; i++) + r[i] = a[i + emin]; + return r; + } + } else if (a instanceof RationalFunction) { + return Series(a.num, n) / a.den; + } else { + throw TypeError("invalid type"); + } + }; + + function series_add(v1, v2) { + var tmp, d, emin, n, r, i, j, v2_emin, c1, c2; + if (!(v1 instanceof Series)) { + tmp = v1; + v1 = v2; + v2 = tmp; + } + d = v1.emin + v1.length; + if (series_is_scalar_or_polynomial(v2)) { + v2 = Polynomial(v2); + if (d <= 0) + return v1; + v2_emin = 0; + } else if (v2 instanceof RationalFunction) { + /* compute the emin of the rational fonction */ + i = get_emin(v2.num) - get_emin(v2.den); + if (d <= i) + return v1; + /* compute the serie with the required terms */ + v2 = Series(v2, d - i); + v2_emin = v2.emin; + } else { + v2_emin = v2.emin; + d = Math.min(d, v2_emin + v2.length); + } + emin = Math.min(v1.emin, v2_emin); + n = d - emin; + r = Series.zero(n, emin); + /* XXX: slow */ + for(i = emin; i < d; i++) { + j = i - v1.emin; + if (j >= 0 && j < v1.length) + c1 = v1[j]; + else + c1 = 0; + j = i - v2_emin; + if (j >= 0 && j < v2.length) + c2 = v2[j]; + else + c2 = 0; + r[i - emin] = c1 + c2; + } + return r.trim(); + } + function series_sub(a, b) { + return series_add(a, -b); + } + function series_mul(v1, v2) { + var n, i, j, r, n, emin, n1, n2, k; + if (!(v1 instanceof Series)) + v1 = Series(v1, v2.length); + else if (!(v2 instanceof Series)) + v2 = Series(v2, v1.length); + emin = v1.emin + v2.emin; + n = Math.min(v1.length, v2.length); + n1 = v1.length; + n2 = v2.length; + r = Series.zero(n, emin); + for(i = 0; i < n1; i++) { + k = Math.min(n2, n - i); + for(j = 0; j < k; j++) { + r[i + j] += v1[i] * v2[j]; + } + } + return r.trim(); + } + function series_div(v1, v2) { + if (!(v2 instanceof Series)) + v2 = Series(v2, v1.length); + return series_mul(v1, v2.inverse()); + } + function series_pow(a, b) { + if (Integer.isInteger(b)) { + return generic_pow(a, b); + } else { + if (!(a instanceof Series)) + a = Series(a, b.length); + return exp(log(a) * b); + } + } + function series_eq(a, b) { + var n, i; + if (a.emin != b.emin) + return false; + n = a.length; + if (n != b.length) + return false; + for(i = 0; i < n; i++) { + if (a[i] != b[i]) + return false; + } + return true; + } + + operators_set(Series.prototype, + { + "+": series_add, + "-": series_sub, + "*": series_mul, + "/": series_div, + "**": series_pow, + "==": series_eq, + "pos"(a) { + return a; + }, + "neg"(a) { + var obj, n, i; + n = a.length; + obj = Series.zero(a.length, a.emin); + for(i = 0; i < n; i++) { + obj[i] = -a[i]; + } + return obj; + }, + }, + { + left: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + right: [Number, BigInt, Float, Fraction, Complex, Mod, Polynomial], + "+": series_add, + "-": series_sub, + "*": series_mul, + "/": series_div, + "**": series_pow, + }); + + add_props(Series.prototype, { + conj() { + var obj, n, i; + n = this.length; + obj = Series.zero(this.length, this.emin); + for(i = 0; i < n; i++) { + obj[i] = this[i].conj(); + } + return obj; + }, + inverse() { + var r, n, i, j, sum, v1 = this; + n = v1.length; + if (n == 0) + throw RangeError("division by zero"); + r = Series.zero(n, -v1.emin); + r[0] = 1 / v1[0]; + for(i = 1; i < n; i++) { + sum = 0; + for(j = 1; j <= i; j++) { + sum += v1[j] * r[i - j]; + } + r[i] = -sum * r[0]; + } + return r; + }, + /* remove leading zero terms */ + trim() { + var i, j, n, r, v1 = this; + n = v1.length; + i = 0; + while (i < n && v1[i] == 0) + i++; + if (i == 0) + return v1; + for(j = i; j < n; j++) + v1[j - i] = v1[j]; + v1.length = n - i; + v1.__proto__.emin += i; + return v1; + }, + toString() { + var i, j, str, str1, c, a = this, emin, n; + str=""; + emin = this.emin; + n = this.length; + for(j = 0; j < n; j++) { + i = j + emin; + c = a[j]; + if (c != 0) { + str1 = monomial_toString(c, i); + if (str1[0] != "-") { + if (str != "") + str += "+"; + } + str += str1; + } + } + if (str != "") + str += "+"; + str += "O(" + monomial_toString(1, n + emin) + ")"; + return str; + }, + apply(b) { + var i, n, r, a = this; + n = a.length; + if (n == 0) + return 0; + r = a[--n]; + while (n > 0) { + n--; + r = r * b + a[n]; + } + if (a.emin != 0) + r *= b ^ a.emin; + return r; + }, + deriv() { + var a = this, n = a.length, emin = a.emin, r, i, j; + if (n == 0 && emin == 0) { + return Series.zero(0, 0); + } else { + r = Series.zero(n, emin - 1); + for(i = 0; i < n; i++) { + j = emin + i; + if (j == 0) + r[i] = 0; + else + r[i] = j * a[i]; + } + return r.trim(); + } + }, + integ() { + var a = this, n = a.length, emin = a.emin, i, j, r; + r = Series.zero(n, emin + 1); + for(i = 0; i < n; i++) { + j = emin + i; + if (j == -1) { + if (a[i] != 0) + throw RangeError("cannot represent integ(1/X)"); + } else { + r[i] = a[i] / (j + 1); + } + } + return r.trim(); + }, + exp() { + var c, i, r, n, a = this; + if (a.emin < 0) + throw RangeError("negative exponent in exp"); + n = a.emin + a.length; + if (a.emin > 0 || a[0] == 0) { + c = 1; + } else { + c = global.exp(a[0]); + a -= a[0]; + } + r = Series.zero(n, 0); + for(i = 0; i < n; i++) { + r[i] = c / fact(i); + } + return r.apply(a); + }, + log() { + var a = this, r; + if (a.emin != 0) + throw RangeError("log argument must have a non zero constant term"); + r = integ(deriv(a) / a); + /* add the constant term */ + r += global.log(a[0]); + return r; + }, + }); + + add_props(Series, { + /* new series of length n and first exponent emin */ + zero(n, emin) { + var r, i, obj; + + r = []; + for(i = 0; i < n; i++) + r[i] = 0; + /* we return an array and store emin in its prototype */ + obj = Object.create(Series.prototype); + obj.emin = emin; + Object.setPrototypeOf(r, obj); + return r; + }, + O(a) { + function ErrorO() { + return TypeError("invalid O() argument"); + } + var n; + if (series_is_scalar_or_polynomial(a)) { + a = Polynomial(a); + n = a.deg(); + if (n < 0) + throw ErrorO(); + } else if (a instanceof RationalFunction) { + if (a.num.deg() != 0) + throw ErrorO(); + n = a.den.deg(); + if (n < 0) + throw ErrorO(); + n = -n; + } else + throw ErrorO(); + return Series.zero(0, n); + }, + }); + + /* Array (Matrix) */ + + Matrix = function Matrix(h, w) { + var i, j, r, rl; + if (typeof w === "undefined") + w = h; + r = []; + for(i = 0; i < h; i++) { + rl = []; + for(j = 0; j < w; j++) + rl[j] = 0; + r[i] = rl; + } + return r; + }; + + add_props(Matrix, { + idn(n) { + var r, i; + r = Matrix(n, n); + for(i = 0; i < n; i++) + r[i][i] = 1; + return r; + }, + diag(a) { + var r, i, n; + n = a.length; + r = Matrix(n, n); + for(i = 0; i < n; i++) + r[i][i] = a[i]; + return r; + }, + hilbert(n) { + var i, j, r; + r = Matrix(n); + for(i = 0; i < n; i++) { + for(j = 0; j < n; j++) { + r[i][j] = 1 / (1 + i + j); + } + } + return r; + }, + trans(a) { + var h, w, r, i, j; + if (!Array.isArray(a)) + throw TypeError("matrix expected"); + h = a.length; + if (!Array.isArray(a[0])) { + w = 1; + r = Matrix(w, h); + for(i = 0; i < h; i++) { + r[0][i] = a[i]; + } + } else { + w = a[0].length; + r = Matrix(w, h); + for(i = 0; i < h; i++) { + for(j = 0; j < w; j++) { + r[j][i] = a[i][j]; + } + } + } + return r; + }, + check_square(a) { + var a, n; + if (!Array.isArray(a)) + throw TypeError("array expected"); + n = a.length; + if (!Array.isArray(a[0]) || n != a[0].length) + throw TypeError("square matrix expected"); + return n; + }, + trace(a) { + var n, r, i; + n = Matrix.check_square(a); + r = a[0][0]; + for(i = 1; i < n; i++) { + r += a[i][i]; + } + return r; + }, + charpoly(a) { + var n, p, c, i, j, coef; + n = Matrix.check_square(a); + p = []; + for(i = 0; i < n + 1; i++) + p[i] = 0; + p[n] = 1; + c = Matrix.idn(n); + for(i = 0; i < n; i++) { + c = c * a; + coef = -trace(c) / (i + 1); + p[n - i - 1] = coef; + for(j = 0; j < n; j++) + c[j][j] += coef; + } + return Polynomial(p); + }, + eigenvals(a) { + return Polynomial.roots(Matrix.charpoly(a)); + }, + det(a) { + var n, i, j, k, s, src, v, c; + + n = Matrix.check_square(a); + s = 1; + src = a.dup(); + for(i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) +#include +#include +#include +#else +#include +#include +#include +#include + +#if defined(__APPLE__) +typedef sig_t sighandler_t; +#if !defined(environ) +#include +#define environ (*_NSGetEnviron()) +#endif +#endif /* __APPLE__ */ + +#endif + +#if !defined(_WIN32) +/* enable the os.Worker API. IT relies on POSIX threads */ +#define USE_WORKER +#endif + +#ifdef USE_WORKER +#include +#include +#endif + +#include "cutils.h" +#include "list.h" +#include "quickjs-libc.h" + +/* TODO: + - add socket calls +*/ + +typedef struct { + struct list_head link; + int fd; + JSValue rw_func[2]; +} JSOSRWHandler; + +typedef struct { + struct list_head link; + int sig_num; + JSValue func; +} JSOSSignalHandler; + +typedef struct { + struct list_head link; + BOOL has_object; + int64_t timeout; + JSValue func; +} JSOSTimer; + +typedef struct { + struct list_head link; + uint8_t *data; + size_t data_len; + /* list of SharedArrayBuffers, necessary to free the message */ + uint8_t **sab_tab; + size_t sab_tab_len; +} JSWorkerMessage; + +typedef struct { + int ref_count; +#ifdef USE_WORKER + pthread_mutex_t mutex; +#endif + struct list_head msg_queue; /* list of JSWorkerMessage.link */ + int read_fd; + int write_fd; +} JSWorkerMessagePipe; + +typedef struct { + struct list_head link; + JSWorkerMessagePipe *recv_pipe; + JSValue on_message_func; +} JSWorkerMessageHandler; + +typedef struct JSThreadState { + struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */ + struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */ + struct list_head os_timers; /* list of JSOSTimer.link */ + struct list_head port_list; /* list of JSWorkerMessageHandler.link */ + int eval_script_recurse; /* only used in the main thread */ + /* not used in the main thread */ + JSWorkerMessagePipe *recv_pipe, *send_pipe; +} JSThreadState; + +static uint64_t os_pending_signals; +static int (*os_poll_func)(JSContext *ctx); + +static void js_std_dbuf_init(JSContext *ctx, DynBuf *s) +{ + dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt); +} + +static BOOL my_isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + +static JSValue js_printf_internal(JSContext *ctx, + int argc, JSValueConst *argv, FILE *fp) +{ + char fmtbuf[32]; + uint8_t cbuf[UTF8_CHAR_LEN_MAX+1]; + JSValue res; + DynBuf dbuf; + const char *fmt_str; + const uint8_t *fmt, *fmt_end; + const uint8_t *p; + char *q; + int i, c, len, mod; + size_t fmt_len; + int32_t int32_arg; + int64_t int64_arg; + double double_arg; + const char *string_arg; + /* Use indirect call to dbuf_printf to prevent gcc warning */ + int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf; + + js_std_dbuf_init(ctx, &dbuf); + + if (argc > 0) { + fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]); + if (!fmt_str) + goto fail; + + i = 1; + fmt = (const uint8_t *)fmt_str; + fmt_end = fmt + fmt_len; + while (fmt < fmt_end) { + for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++) + continue; + dbuf_put(&dbuf, p, fmt - p); + if (fmt >= fmt_end) + break; + q = fmtbuf; + *q++ = *fmt++; /* copy '%' */ + + /* flags */ + for(;;) { + c = *fmt; + if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' || + c == '\'') { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = c; + fmt++; + } else { + break; + } + } + /* width */ + if (*fmt == '*') { + if (i >= argc) + goto missing; + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); + fmt++; + } else { + while (my_isdigit(*fmt)) { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + } + } + if (*fmt == '.') { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + if (*fmt == '*') { + if (i >= argc) + goto missing; + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg); + fmt++; + } else { + while (my_isdigit(*fmt)) { + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = *fmt++; + } + } + } + + /* we only support the "l" modifier for 64 bit numbers */ + mod = ' '; + if (*fmt == 'l') { + mod = *fmt++; + } + + /* type */ + c = *fmt++; + if (q >= fmtbuf + sizeof(fmtbuf) - 1) + goto invalid; + *q++ = c; + *q = '\0'; + + switch (c) { + case 'c': + if (i >= argc) + goto missing; + if (JS_IsString(argv[i])) { + string_arg = JS_ToCString(ctx, argv[i++]); + if (!string_arg) + goto fail; + int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p); + JS_FreeCString(ctx, string_arg); + } else { + if (JS_ToInt32(ctx, &int32_arg, argv[i++])) + goto fail; + } + /* handle utf-8 encoding explicitly */ + if ((unsigned)int32_arg > 0x10FFFF) + int32_arg = 0xFFFD; + /* ignore conversion flags, width and precision */ + len = unicode_to_utf8(cbuf, int32_arg); + dbuf_put(&dbuf, cbuf, len); + break; + + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (i >= argc) + goto missing; + if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++])) + goto fail; + if (mod == 'l') { + /* 64 bit number */ +#if defined(_WIN32) + if (q >= fmtbuf + sizeof(fmtbuf) - 3) + goto invalid; + q[2] = q[-1]; + q[-1] = 'I'; + q[0] = '6'; + q[1] = '4'; + q[3] = '\0'; + dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg); +#else + if (q >= fmtbuf + sizeof(fmtbuf) - 2) + goto invalid; + q[1] = q[-1]; + q[-1] = q[0] = 'l'; + q[2] = '\0'; + dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg); +#endif + } else { + dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg); + } + break; + + case 's': + if (i >= argc) + goto missing; + /* XXX: handle strings containing null characters */ + string_arg = JS_ToCString(ctx, argv[i++]); + if (!string_arg) + goto fail; + dbuf_printf_fun(&dbuf, fmtbuf, string_arg); + JS_FreeCString(ctx, string_arg); + break; + + case 'e': + case 'f': + case 'g': + case 'a': + case 'E': + case 'F': + case 'G': + case 'A': + if (i >= argc) + goto missing; + if (JS_ToFloat64(ctx, &double_arg, argv[i++])) + goto fail; + dbuf_printf_fun(&dbuf, fmtbuf, double_arg); + break; + + case '%': + dbuf_putc(&dbuf, '%'); + break; + + default: + /* XXX: should support an extension mechanism */ + invalid: + JS_ThrowTypeError(ctx, "invalid conversion specifier in format string"); + goto fail; + missing: + JS_ThrowReferenceError(ctx, "missing argument for conversion specifier"); + goto fail; + } + } + JS_FreeCString(ctx, fmt_str); + } + if (dbuf.error) { + res = JS_ThrowOutOfMemory(ctx); + } else { + if (fp) { + len = fwrite(dbuf.buf, 1, dbuf.size, fp); + res = JS_NewInt32(ctx, len); + } else { + res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size); + } + } + dbuf_free(&dbuf); + return res; + +fail: + dbuf_free(&dbuf); + return JS_EXCEPTION; +} + +uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename) +{ + FILE *f; + uint8_t *buf; + size_t buf_len; + long lret; + + f = fopen(filename, "rb"); + if (!f) + return NULL; + if (fseek(f, 0, SEEK_END) < 0) + goto fail; + lret = ftell(f); + if (lret < 0) + goto fail; + /* XXX: on Linux, ftell() return LONG_MAX for directories */ + if (lret == LONG_MAX) { + errno = EISDIR; + goto fail; + } + buf_len = lret; + if (fseek(f, 0, SEEK_SET) < 0) + goto fail; + if (ctx) + buf = js_malloc(ctx, buf_len + 1); + else + buf = malloc(buf_len + 1); + if (!buf) + goto fail; + if (fread(buf, 1, buf_len, f) != buf_len) { + errno = EIO; + if (ctx) + js_free(ctx, buf); + else + free(buf); + fail: + fclose(f); + return NULL; + } + buf[buf_len] = '\0'; + fclose(f); + *pbuf_len = buf_len; + return buf; +} + +/* load and evaluate a file */ +static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + const char *filename; + JSValue ret; + size_t buf_len; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + buf = js_load_file(ctx, &buf_len, filename); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load '%s'", filename); + JS_FreeCString(ctx, filename); + return JS_EXCEPTION; + } + ret = JS_Eval(ctx, (char *)buf, buf_len, filename, + JS_EVAL_TYPE_GLOBAL); + js_free(ctx, buf); + JS_FreeCString(ctx, filename); + return ret; +} + +/* load a file as a UTF-8 encoded string */ +static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + const char *filename; + JSValue ret; + size_t buf_len; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + buf = js_load_file(ctx, &buf_len, filename); + JS_FreeCString(ctx, filename); + if (!buf) + return JS_NULL; + ret = JS_NewStringLen(ctx, (char *)buf, buf_len); + js_free(ctx, buf); + return ret; +} + +typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx, + const char *module_name); + + +#if defined(_WIN32) +static JSModuleDef *js_module_loader_so(JSContext *ctx, + const char *module_name) +{ + JS_ThrowReferenceError(ctx, "shared library modules are not supported yet"); + return NULL; +} +#else +static JSModuleDef *js_module_loader_so(JSContext *ctx, + const char *module_name) +{ + JSModuleDef *m; + void *hd; + JSInitModuleFunc *init; + char *filename; + + if (!strchr(module_name, '/')) { + /* must add a '/' so that the DLL is not searched in the + system library paths */ + filename = js_malloc(ctx, strlen(module_name) + 2 + 1); + if (!filename) + return NULL; + strcpy(filename, "./"); + strcpy(filename + 2, module_name); + } else { + filename = (char *)module_name; + } + + /* C module */ + hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL); + if (filename != module_name) + js_free(ctx, filename); + if (!hd) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library", + module_name); + goto fail; + } + + init = dlsym(hd, "js_init_module"); + if (!init) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found", + module_name); + goto fail; + } + + m = init(ctx, module_name); + if (!m) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error", + module_name); + fail: + if (hd) + dlclose(hd); + return NULL; + } + return m; +} +#endif /* !_WIN32 */ + +int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + JS_BOOL use_realpath, JS_BOOL is_main) +{ + JSModuleDef *m; + char buf[PATH_MAX + 16]; + JSValue meta_obj; + JSAtom module_name_atom; + const char *module_name; + + assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE); + m = JS_VALUE_GET_PTR(func_val); + + module_name_atom = JS_GetModuleName(ctx, m); + module_name = JS_AtomToCString(ctx, module_name_atom); + JS_FreeAtom(ctx, module_name_atom); + if (!module_name) + return -1; + if (!strchr(module_name, ':')) { + strcpy(buf, "file://"); +#if !defined(_WIN32) + /* realpath() cannot be used with modules compiled with qjsc + because the corresponding module source code is not + necessarily present */ + if (use_realpath) { + char *res = realpath(module_name, buf + strlen(buf)); + if (!res) { + JS_ThrowTypeError(ctx, "realpath failure"); + JS_FreeCString(ctx, module_name); + return -1; + } + } else +#endif + { + pstrcat(buf, sizeof(buf), module_name); + } + } else { + pstrcpy(buf, sizeof(buf), module_name); + } + JS_FreeCString(ctx, module_name); + + meta_obj = JS_GetImportMeta(ctx, m); + if (JS_IsException(meta_obj)) + return -1; + JS_DefinePropertyValueStr(ctx, meta_obj, "url", + JS_NewString(ctx, buf), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, meta_obj, "main", + JS_NewBool(ctx, is_main), + JS_PROP_C_W_E); + JS_FreeValue(ctx, meta_obj); + return 0; +} + +JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque) +{ + JSModuleDef *m; + + if (has_suffix(module_name, ".so")) { + m = js_module_loader_so(ctx, module_name); + } else { + size_t buf_len; + uint8_t *buf; + JSValue func_val; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + /* XXX: could propagate the exception */ + js_module_set_import_meta(ctx, func_val, TRUE, FALSE); + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + } + return m; +} + +static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int status; + if (JS_ToInt32(ctx, &status, argv[0])) + status = -1; + exit(status); + return JS_UNDEFINED; +} + +static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name, *str; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + str = getenv(name); + JS_FreeCString(ctx, name); + if (!str) + return JS_UNDEFINED; + else + return JS_NewString(ctx, str); +} + +#if defined(_WIN32) +static void setenv(const char *name, const char *value, int overwrite) +{ + char *str; + size_t name_len, value_len; + name_len = strlen(name); + value_len = strlen(value); + str = malloc(name_len + 1 + value_len + 1); + memcpy(str, name, name_len); + str[name_len] = '='; + memcpy(str + name_len + 1, value, value_len); + str[name_len + 1 + value_len] = '\0'; + _putenv(str); + free(str); +} + +static void unsetenv(const char *name) +{ + setenv(name, "", TRUE); +} +#endif /* _WIN32 */ + +static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name, *value; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + value = JS_ToCString(ctx, argv[1]); + if (!value) { + JS_FreeCString(ctx, name); + return JS_EXCEPTION; + } + setenv(name, value, TRUE); + JS_FreeCString(ctx, name); + JS_FreeCString(ctx, value); + return JS_UNDEFINED; +} + +static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *name; + name = JS_ToCString(ctx, argv[0]); + if (!name) + return JS_EXCEPTION; + unsetenv(name); + JS_FreeCString(ctx, name); + return JS_UNDEFINED; +} + +/* return an object containing the list of the available environment + variables. */ +static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char **envp; + const char *name, *p, *value; + JSValue obj; + uint32_t idx; + size_t name_len; + JSAtom atom; + int ret; + + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + envp = environ; + for(idx = 0; envp[idx] != NULL; idx++) { + name = envp[idx]; + p = strchr(name, '='); + name_len = p - name; + if (!p) + continue; + value = p + 1; + atom = JS_NewAtomLen(ctx, name, name_len); + if (atom == JS_ATOM_NULL) + goto fail; + ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value), + JS_PROP_C_W_E); + JS_FreeAtom(ctx, atom); + if (ret < 0) + goto fail; + } + return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JS_RunGC(JS_GetRuntime(ctx)); + return JS_UNDEFINED; +} + +static int interrupt_handler(JSRuntime *rt, void *opaque) +{ + return (os_pending_signals >> SIGINT) & 1; +} + +static int get_bool_option(JSContext *ctx, BOOL *pbool, + JSValueConst obj, + const char *option) +{ + JSValue val; + val = JS_GetPropertyStr(ctx, obj, option); + if (JS_IsException(val)) + return -1; + if (!JS_IsUndefined(val)) { + *pbool = JS_ToBool(ctx, val); + } + JS_FreeValue(ctx, val); + return 0; +} + +static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + const char *str; + size_t len; + JSValue ret; + JSValueConst options_obj; + BOOL backtrace_barrier = FALSE; + BOOL is_async = FALSE; + int flags; + + if (argc >= 2) { + options_obj = argv[1]; + if (get_bool_option(ctx, &backtrace_barrier, options_obj, + "backtrace_barrier")) + return JS_EXCEPTION; + if (get_bool_option(ctx, &is_async, options_obj, + "async")) + return JS_EXCEPTION; + } + + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) { + /* install the interrupt handler */ + JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL); + } + flags = JS_EVAL_TYPE_GLOBAL; + if (backtrace_barrier) + flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER; + if (is_async) + flags |= JS_EVAL_FLAG_ASYNC; + ret = JS_Eval(ctx, str, len, "", flags); + JS_FreeCString(ctx, str); + if (!ts->recv_pipe && --ts->eval_script_recurse == 0) { + /* remove the interrupt handler */ + JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL); + os_pending_signals &= ~((uint64_t)1 << SIGINT); + /* convert the uncatchable "interrupted" error into a normal error + so that it can be caught by the REPL */ + if (JS_IsException(ret)) + JS_ResetUncatchableError(ctx); + } + return ret; +} + +static JSClassID js_std_file_class_id; + +typedef struct { + FILE *f; + BOOL close_in_finalizer; + BOOL is_popen; +} JSSTDFile; + +static void js_std_file_finalizer(JSRuntime *rt, JSValue val) +{ + JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id); + if (s) { + if (s->f && s->close_in_finalizer) { + if (s->is_popen) + pclose(s->f); + else + fclose(s->f); + } + js_free_rt(rt, s); + } +} + +static ssize_t js_get_errno(ssize_t ret) +{ + if (ret == -1) + ret = -errno; + return ret; +} + +static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int err; + if (JS_ToInt32(ctx, &err, argv[0])) + return JS_EXCEPTION; + return JS_NewString(ctx, strerror(err)); +} + +static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue obj; + const char *str; + size_t len; + + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + obj = JS_ParseJSON2(ctx, str, len, "", JS_PARSE_JSON_EXT); + JS_FreeCString(ctx, str); + return obj; +} + +static JSValue js_new_std_file(JSContext *ctx, FILE *f, + BOOL close_in_finalizer, + BOOL is_popen) +{ + JSSTDFile *s; + JSValue obj; + obj = JS_NewObjectClass(ctx, js_std_file_class_id); + if (JS_IsException(obj)) + return obj; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + s->close_in_finalizer = close_in_finalizer; + s->is_popen = is_popen; + s->f = f; + JS_SetOpaque(obj, s); + return obj; +} + +static void js_set_error_object(JSContext *ctx, JSValue obj, int err) +{ + if (!JS_IsUndefined(obj)) { + JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err)); + } +} + +static JSValue js_std_open(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename, *mode = NULL; + FILE *f; + int err; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (mode[strspn(mode, "rwa+b")] != '\0') { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = fopen(filename, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, TRUE, FALSE); + fail: + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} + +static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename, *mode = NULL; + FILE *f; + int err; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (mode[strspn(mode, "rw")] != '\0') { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = popen(filename, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, TRUE, TRUE); + fail: + JS_FreeCString(ctx, filename); + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} + +static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *mode; + FILE *f; + int fd, err; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + mode = JS_ToCString(ctx, argv[1]); + if (!mode) + goto fail; + if (mode[strspn(mode, "rwa+")] != '\0') { + JS_ThrowTypeError(ctx, "invalid file mode"); + goto fail; + } + + f = fdopen(fd, mode); + if (!f) + err = errno; + else + err = 0; + if (argc >= 3) + js_set_error_object(ctx, argv[2], err); + JS_FreeCString(ctx, mode); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, TRUE, FALSE); + fail: + JS_FreeCString(ctx, mode); + return JS_EXCEPTION; +} + +static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f; + f = tmpfile(); + if (argc >= 1) + js_set_error_object(ctx, argv[0], f ? 0 : errno); + if (!f) + return JS_NULL; + return js_new_std_file(ctx, f, TRUE, FALSE); +} + +static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return js_printf_internal(ctx, argc, argv, NULL); +} + +static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return js_printf_internal(ctx, argc, argv, stdout); +} + +static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj) +{ + JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id); + if (!s) + return NULL; + if (!s->f) { + JS_ThrowTypeError(ctx, "invalid file handle"); + return NULL; + } + return s->f; +} + +static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + FILE *f; + int i; + const char *str; + size_t len; + + if (magic == 0) { + f = stdout; + } else { + f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + } + + for(i = 0; i < argc; i++) { + str = JS_ToCStringLen(ctx, &len, argv[i]); + if (!str) + return JS_EXCEPTION; + fwrite(str, 1, len, f); + JS_FreeCString(ctx, str); + } + return JS_UNDEFINED; +} + +static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id); + int err; + if (!s) + return JS_EXCEPTION; + if (!s->f) + return JS_ThrowTypeError(ctx, "invalid file handle"); + if (s->is_popen) + err = js_get_errno(pclose(s->f)); + else + err = js_get_errno(fclose(s->f)); + s->f = NULL; + return JS_NewInt32(ctx, err); +} + +static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return js_printf_internal(ctx, argc, argv, f); +} + +static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + fflush(f); + return JS_UNDEFINED; +} + +static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_bigint) +{ + FILE *f = js_std_file_get(ctx, this_val); + int64_t pos; + if (!f) + return JS_EXCEPTION; +#if defined(__linux__) + pos = ftello(f); +#else + pos = ftell(f); +#endif + if (is_bigint) + return JS_NewBigInt64(ctx, pos); + else + return JS_NewInt64(ctx, pos); +} + +static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int64_t pos; + int whence, ret; + if (!f) + return JS_EXCEPTION; + if (JS_ToInt64Ext(ctx, &pos, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &whence, argv[1])) + return JS_EXCEPTION; +#if defined(__linux__) + ret = fseeko(f, pos, whence); +#else + ret = fseek(f, pos, whence); +#endif + if (ret < 0) + ret = -errno; + return JS_NewInt32(ctx, ret); +} + +static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewBool(ctx, feof(f)); +} + +static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewBool(ctx, ferror(f)); +} + +static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + clearerr(f); + return JS_UNDEFINED; +} + +static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewInt32(ctx, fileno(f)); +} + +static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + FILE *f = js_std_file_get(ctx, this_val); + uint64_t pos, len; + size_t size, ret; + uint8_t *buf; + + if (!f) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[2])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); + if (magic) + ret = fwrite(buf + pos, 1, len, f); + else + ret = fread(buf + pos, 1, len, f); + return JS_NewInt64(ctx, ret); +} + +/* XXX: could use less memory and go faster */ +static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + DynBuf dbuf; + JSValue obj; + + if (!f) + return JS_EXCEPTION; + + js_std_dbuf_init(ctx, &dbuf); + for(;;) { + c = fgetc(f); + if (c == EOF) { + if (dbuf.size == 0) { + /* EOF */ + dbuf_free(&dbuf); + return JS_NULL; + } else { + break; + } + } + if (c == '\n') + break; + if (dbuf_putc(&dbuf, c)) { + dbuf_free(&dbuf); + return JS_ThrowOutOfMemory(ctx); + } + } + obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); + dbuf_free(&dbuf); + return obj; +} + +/* XXX: could use less memory and go faster */ +static JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + DynBuf dbuf; + JSValue obj; + uint64_t max_size64; + size_t max_size; + JSValueConst max_size_val; + + if (!f) + return JS_EXCEPTION; + + if (argc >= 1) + max_size_val = argv[0]; + else + max_size_val = JS_UNDEFINED; + max_size = (size_t)-1; + if (!JS_IsUndefined(max_size_val)) { + if (JS_ToIndex(ctx, &max_size64, max_size_val)) + return JS_EXCEPTION; + if (max_size64 < max_size) + max_size = max_size64; + } + + js_std_dbuf_init(ctx, &dbuf); + while (max_size != 0) { + c = fgetc(f); + if (c == EOF) + break; + if (dbuf_putc(&dbuf, c)) { + dbuf_free(&dbuf); + return JS_EXCEPTION; + } + max_size--; + } + obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); + dbuf_free(&dbuf); + return obj; +} + +static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + if (!f) + return JS_EXCEPTION; + return JS_NewInt32(ctx, fgetc(f)); +} + +static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + FILE *f = js_std_file_get(ctx, this_val); + int c; + if (!f) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &c, argv[0])) + return JS_EXCEPTION; + c = fputc(c, f); + return JS_NewInt32(ctx, c); +} + +/* urlGet */ + +#define URL_GET_PROGRAM "curl -s -i" +#define URL_GET_BUF_SIZE 4096 + +static int http_get_header_line(FILE *f, char *buf, size_t buf_size, + DynBuf *dbuf) +{ + int c; + char *p; + + p = buf; + for(;;) { + c = fgetc(f); + if (c < 0) + return -1; + if ((p - buf) < buf_size - 1) + *p++ = c; + if (dbuf) + dbuf_putc(dbuf, c); + if (c == '\n') + break; + } + *p = '\0'; + return 0; +} + +static int http_get_status(const char *buf) +{ + const char *p = buf; + while (*p != ' ' && *p != '\0') + p++; + if (*p != ' ') + return 0; + while (*p == ' ') + p++; + return atoi(p); +} + +static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *url; + DynBuf cmd_buf; + DynBuf data_buf_s, *data_buf = &data_buf_s; + DynBuf header_buf_s, *header_buf = &header_buf_s; + char *buf; + size_t i, len; + int c, status; + JSValue response = JS_UNDEFINED, ret_obj; + JSValueConst options_obj; + FILE *f; + BOOL binary_flag, full_flag; + + url = JS_ToCString(ctx, argv[0]); + if (!url) + return JS_EXCEPTION; + + binary_flag = FALSE; + full_flag = FALSE; + + if (argc >= 2) { + options_obj = argv[1]; + + if (get_bool_option(ctx, &binary_flag, options_obj, "binary")) + goto fail_obj; + + if (get_bool_option(ctx, &full_flag, options_obj, "full")) { + fail_obj: + JS_FreeCString(ctx, url); + return JS_EXCEPTION; + } + } + + js_std_dbuf_init(ctx, &cmd_buf); + dbuf_printf(&cmd_buf, "%s ''", URL_GET_PROGRAM); + len = strlen(url); + for(i = 0; i < len; i++) { + c = url[i]; + if (c == '\'' || c == '\\') + dbuf_putc(&cmd_buf, '\\'); + dbuf_putc(&cmd_buf, c); + } + JS_FreeCString(ctx, url); + dbuf_putstr(&cmd_buf, "''"); + dbuf_putc(&cmd_buf, '\0'); + if (dbuf_error(&cmd_buf)) { + dbuf_free(&cmd_buf); + return JS_EXCEPTION; + } + // printf("%s\n", (char *)cmd_buf.buf); + f = popen((char *)cmd_buf.buf, "r"); + dbuf_free(&cmd_buf); + if (!f) { + return JS_ThrowTypeError(ctx, "could not start curl"); + } + + js_std_dbuf_init(ctx, data_buf); + js_std_dbuf_init(ctx, header_buf); + + buf = js_malloc(ctx, URL_GET_BUF_SIZE); + if (!buf) + goto fail; + + /* get the HTTP status */ + if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) { + status = 0; + goto bad_header; + } + status = http_get_status(buf); + if (!full_flag && !(status >= 200 && status <= 299)) { + goto bad_header; + } + + /* wait until there is an empty line */ + for(;;) { + if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) { + bad_header: + response = JS_NULL; + goto done; + } + if (!strcmp(buf, "\r\n")) + break; + } + if (dbuf_error(header_buf)) + goto fail; + header_buf->size -= 2; /* remove the trailing CRLF */ + + /* download the data */ + for(;;) { + len = fread(buf, 1, URL_GET_BUF_SIZE, f); + if (len == 0) + break; + dbuf_put(data_buf, (uint8_t *)buf, len); + } + if (dbuf_error(data_buf)) + goto fail; + if (binary_flag) { + response = JS_NewArrayBufferCopy(ctx, + data_buf->buf, data_buf->size); + } else { + response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size); + } + if (JS_IsException(response)) + goto fail; + done: + js_free(ctx, buf); + buf = NULL; + pclose(f); + f = NULL; + dbuf_free(data_buf); + data_buf = NULL; + + if (full_flag) { + ret_obj = JS_NewObject(ctx); + if (JS_IsException(ret_obj)) + goto fail; + JS_DefinePropertyValueStr(ctx, ret_obj, "response", + response, + JS_PROP_C_W_E); + if (!JS_IsNull(response)) { + JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders", + JS_NewStringLen(ctx, (char *)header_buf->buf, + header_buf->size), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, ret_obj, "status", + JS_NewInt32(ctx, status), + JS_PROP_C_W_E); + } + } else { + ret_obj = response; + } + dbuf_free(header_buf); + return ret_obj; + fail: + if (f) + pclose(f); + js_free(ctx, buf); + if (data_buf) + dbuf_free(data_buf); + if (header_buf) + dbuf_free(header_buf); + JS_FreeValue(ctx, response); + return JS_EXCEPTION; +} + +static JSClassDef js_std_file_class = { + "FILE", + .finalizer = js_std_file_finalizer, +}; + +static const JSCFunctionListEntry js_std_error_props[] = { + /* various errno values */ +#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) + DEF(EINVAL), + DEF(EIO), + DEF(EACCES), + DEF(EEXIST), + DEF(ENOSPC), + DEF(ENOSYS), + DEF(EBUSY), + DEF(ENOENT), + DEF(EPERM), + DEF(EPIPE), + DEF(EBADF), +#undef DEF +}; + +static const JSCFunctionListEntry js_std_funcs[] = { + JS_CFUNC_DEF("exit", 1, js_std_exit ), + JS_CFUNC_DEF("gc", 0, js_std_gc ), + JS_CFUNC_DEF("evalScript", 1, js_evalScript ), + JS_CFUNC_DEF("loadScript", 1, js_loadScript ), + JS_CFUNC_DEF("getenv", 1, js_std_getenv ), + JS_CFUNC_DEF("setenv", 1, js_std_setenv ), + JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ), + JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ), + JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ), + JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ), + JS_CFUNC_DEF("strerror", 1, js_std_strerror ), + JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ), + + /* FILE I/O */ + JS_CFUNC_DEF("open", 2, js_std_open ), + JS_CFUNC_DEF("popen", 2, js_std_popen ), + JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ), + JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ), + JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ), + JS_CFUNC_DEF("printf", 1, js_std_printf ), + JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ), + JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ), + JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ), + JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), + JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), +}; + +static const JSCFunctionListEntry js_std_file_proto_funcs[] = { + JS_CFUNC_DEF("close", 0, js_std_file_close ), + JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ), + JS_CFUNC_DEF("printf", 1, js_std_file_printf ), + JS_CFUNC_DEF("flush", 0, js_std_file_flush ), + JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ), + JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ), + JS_CFUNC_DEF("seek", 2, js_std_file_seek ), + JS_CFUNC_DEF("eof", 0, js_std_file_eof ), + JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ), + JS_CFUNC_DEF("error", 0, js_std_file_error ), + JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ), + JS_CFUNC_MAGIC_DEF("read", 3, js_std_file_read_write, 0 ), + JS_CFUNC_MAGIC_DEF("write", 3, js_std_file_read_write, 1 ), + JS_CFUNC_DEF("getline", 0, js_std_file_getline ), + JS_CFUNC_DEF("readAsString", 0, js_std_file_readAsString ), + JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ), + JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ), + /* setvbuf, ... */ +}; + +static int js_std_init(JSContext *ctx, JSModuleDef *m) +{ + JSValue proto; + + /* FILE class */ + /* the class ID is created once */ + JS_NewClassID(&js_std_file_class_id); + /* the class is created once per runtime */ + JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class); + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs, + countof(js_std_file_proto_funcs)); + JS_SetClassProto(ctx, js_std_file_class_id, proto); + + JS_SetModuleExportList(ctx, m, js_std_funcs, + countof(js_std_funcs)); + JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, FALSE, FALSE)); + JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, FALSE, FALSE)); + JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, FALSE, FALSE)); + return 0; +} + +JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_std_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs)); + JS_AddModuleExport(ctx, m, "in"); + JS_AddModuleExport(ctx, m, "out"); + JS_AddModuleExport(ctx, m, "err"); + return m; +} + +/**********************************************************/ +/* 'os' object */ + +static JSValue js_os_open(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename; + int flags, mode, ret; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &flags, argv[1])) + goto fail; + if (argc >= 3 && !JS_IsUndefined(argv[2])) { + if (JS_ToInt32(ctx, &mode, argv[2])) { + fail: + JS_FreeCString(ctx, filename); + return JS_EXCEPTION; + } + } else { + mode = 0666; + } +#if defined(_WIN32) + /* force binary mode by default */ + if (!(flags & O_TEXT)) + flags |= O_BINARY; +#endif + ret = js_get_errno(open(filename, flags, mode)); + JS_FreeCString(ctx, filename); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_close(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, ret; + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + ret = js_get_errno(close(fd)); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, whence; + int64_t pos, ret; + BOOL is_bigint; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + is_bigint = JS_IsBigInt(ctx, argv[1]); + if (JS_ToInt64Ext(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &whence, argv[2])) + return JS_EXCEPTION; + ret = lseek(fd, pos, whence); + if (ret == -1) + ret = -errno; + if (is_bigint) + return JS_NewBigInt64(ctx, ret); + else + return JS_NewInt64(ctx, ret); +} + +static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + int fd; + uint64_t pos, len; + size_t size; + ssize_t ret; + uint8_t *buf; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &pos, argv[2])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[3])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[1]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "read/write array buffer overflow"); + if (magic) + ret = js_get_errno(write(fd, buf + pos, len)); + else + ret = js_get_errno(read(fd, buf + pos, len)); + return JS_NewInt64(ctx, ret); +} + +static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + return JS_NewBool(ctx, (isatty(fd) != 0)); +} + +#if defined(_WIN32) +static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + HANDLE handle; + CONSOLE_SCREEN_BUFFER_INFO info; + JSValue obj; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + handle = (HANDLE)_get_osfhandle(fd); + + if (!GetConsoleScreenBufferInfo(handle, &info)) + return JS_NULL; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E); + return obj; +} + +/* Windows 10 built-in VT100 emulation */ +#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 + +static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + HANDLE handle; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + handle = (HANDLE)_get_osfhandle(fd); + SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT); + _setmode(fd, _O_BINARY); + if (fd == 0) { + handle = (HANDLE)_get_osfhandle(1); /* corresponding output */ + SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING); + } + return JS_UNDEFINED; +} +#else +static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd; + struct winsize ws; + JSValue obj; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (ioctl(fd, TIOCGWINSZ, &ws) == 0 && + ws.ws_col >= 4 && ws.ws_row >= 4) { + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E); + return obj; + } else { + return JS_NULL; + } +} + +static struct termios oldtty; + +static void term_exit(void) +{ + tcsetattr(0, TCSANOW, &oldtty); +} + +/* XXX: should add a way to go back to normal mode */ +static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + struct termios tty; + int fd; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + + memset(&tty, 0, sizeof(tty)); + tcgetattr(fd, &tty); + oldtty = tty; + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); + tty.c_oflag |= OPOST; + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); + tty.c_cflag &= ~(CSIZE|PARENB); + tty.c_cflag |= CS8; + tty.c_cc[VMIN] = 1; + tty.c_cc[VTIME] = 0; + + tcsetattr(fd, TCSANOW, &tty); + + atexit(term_exit); + return JS_UNDEFINED; +} + +#endif /* !_WIN32 */ + +static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *filename; + int ret; + + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + return JS_EXCEPTION; +#if defined(_WIN32) + { + struct stat st; + if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) { + ret = rmdir(filename); + } else { + ret = unlink(filename); + } + } +#else + ret = remove(filename); +#endif + ret = js_get_errno(ret); + JS_FreeCString(ctx, filename); + return JS_NewInt32(ctx, ret); +} + +static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *oldpath, *newpath; + int ret; + + oldpath = JS_ToCString(ctx, argv[0]); + if (!oldpath) + return JS_EXCEPTION; + newpath = JS_ToCString(ctx, argv[1]); + if (!newpath) { + JS_FreeCString(ctx, oldpath); + return JS_EXCEPTION; + } + ret = js_get_errno(rename(oldpath, newpath)); + JS_FreeCString(ctx, oldpath); + JS_FreeCString(ctx, newpath); + return JS_NewInt32(ctx, ret); +} + +static BOOL is_main_thread(JSRuntime *rt) +{ + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + return !ts->recv_pipe; +} + +static JSOSRWHandler *find_rh(JSThreadState *ts, int fd) +{ + JSOSRWHandler *rh; + struct list_head *el; + + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == fd) + return rh; + } + return NULL; +} + +static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh) +{ + int i; + list_del(&rh->link); + for(i = 0; i < 2; i++) { + JS_FreeValueRT(rt, rh->rw_func[i]); + } + js_free_rt(rt, rh); +} + +static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + JSOSRWHandler *rh; + int fd; + JSValueConst func; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + func = argv[1]; + if (JS_IsNull(func)) { + rh = find_rh(ts, fd); + if (rh) { + JS_FreeValue(ctx, rh->rw_func[magic]); + rh->rw_func[magic] = JS_NULL; + if (JS_IsNull(rh->rw_func[0]) && + JS_IsNull(rh->rw_func[1])) { + /* remove the entry */ + free_rw_handler(JS_GetRuntime(ctx), rh); + } + } + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + rh = find_rh(ts, fd); + if (!rh) { + rh = js_mallocz(ctx, sizeof(*rh)); + if (!rh) + return JS_EXCEPTION; + rh->fd = fd; + rh->rw_func[0] = JS_NULL; + rh->rw_func[1] = JS_NULL; + list_add_tail(&rh->link, &ts->os_rw_handlers); + } + JS_FreeValue(ctx, rh->rw_func[magic]); + rh->rw_func[magic] = JS_DupValue(ctx, func); + } + return JS_UNDEFINED; +} + +static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num) +{ + JSOSSignalHandler *sh; + struct list_head *el; + list_for_each(el, &ts->os_signal_handlers) { + sh = list_entry(el, JSOSSignalHandler, link); + if (sh->sig_num == sig_num) + return sh; + } + return NULL; +} + +static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh) +{ + list_del(&sh->link); + JS_FreeValueRT(rt, sh->func); + js_free_rt(rt, sh); +} + +static void os_signal_handler(int sig_num) +{ + os_pending_signals |= ((uint64_t)1 << sig_num); +} + +#if defined(_WIN32) +typedef void (*sighandler_t)(int sig_num); +#endif + +static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + JSOSSignalHandler *sh; + uint32_t sig_num; + JSValueConst func; + sighandler_t handler; + + if (!is_main_thread(rt)) + return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread"); + + if (JS_ToUint32(ctx, &sig_num, argv[0])) + return JS_EXCEPTION; + if (sig_num >= 64) + return JS_ThrowRangeError(ctx, "invalid signal number"); + func = argv[1]; + /* func = null: SIG_DFL, func = undefined, SIG_IGN */ + if (JS_IsNull(func) || JS_IsUndefined(func)) { + sh = find_sh(ts, sig_num); + if (sh) { + free_sh(JS_GetRuntime(ctx), sh); + } + if (JS_IsNull(func)) + handler = SIG_DFL; + else + handler = SIG_IGN; + signal(sig_num, handler); + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + sh = find_sh(ts, sig_num); + if (!sh) { + sh = js_mallocz(ctx, sizeof(*sh)); + if (!sh) + return JS_EXCEPTION; + sh->sig_num = sig_num; + list_add_tail(&sh->link, &ts->os_signal_handlers); + } + JS_FreeValue(ctx, sh->func); + sh->func = JS_DupValue(ctx, func); + signal(sig_num, os_signal_handler); + } + return JS_UNDEFINED; +} + +#if defined(__linux__) || defined(__APPLE__) +static int64_t get_time_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); +} + +static int64_t get_time_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +} +#else +/* more portable, but does not work if the date is updated */ +static int64_t get_time_ms(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); +} + +static int64_t get_time_ns(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000); +} +#endif + +static JSValue js_os_now(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6); +} + +static void unlink_timer(JSRuntime *rt, JSOSTimer *th) +{ + if (th->link.prev) { + list_del(&th->link); + th->link.prev = th->link.next = NULL; + } +} + +static void free_timer(JSRuntime *rt, JSOSTimer *th) +{ + JS_FreeValueRT(rt, th->func); + js_free_rt(rt, th); +} + +static JSClassID js_os_timer_class_id; + +static void js_os_timer_finalizer(JSRuntime *rt, JSValue val) +{ + JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id); + if (th) { + th->has_object = FALSE; + if (!th->link.prev) + free_timer(rt, th); + } +} + +static void js_os_timer_mark(JSRuntime *rt, JSValueConst val, + JS_MarkFunc *mark_func) +{ + JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id); + if (th) { + JS_MarkValue(rt, th->func, mark_func); + } +} + +static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int64_t delay; + JSValueConst func; + JSOSTimer *th; + JSValue obj; + + func = argv[0]; + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + if (JS_ToInt64(ctx, &delay, argv[1])) + return JS_EXCEPTION; + obj = JS_NewObjectClass(ctx, js_os_timer_class_id); + if (JS_IsException(obj)) + return obj; + th = js_mallocz(ctx, sizeof(*th)); + if (!th) { + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; + } + th->has_object = TRUE; + th->timeout = get_time_ms() + delay; + th->func = JS_DupValue(ctx, func); + list_add_tail(&th->link, &ts->os_timers); + JS_SetOpaque(obj, th); + return obj; +} + +static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSOSTimer *th = JS_GetOpaque2(ctx, argv[0], js_os_timer_class_id); + if (!th) + return JS_EXCEPTION; + unlink_timer(JS_GetRuntime(ctx), th); + return JS_UNDEFINED; +} + +static JSClassDef js_os_timer_class = { + "OSTimer", + .finalizer = js_os_timer_finalizer, + .gc_mark = js_os_timer_mark, +}; + +/* return a promise */ +static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int64_t delay; + JSOSTimer *th; + JSValue promise, resolving_funcs[2]; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + + th = js_mallocz(ctx, sizeof(*th)); + if (!th) { + JS_FreeValue(ctx, promise); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return JS_EXCEPTION; + } + th->has_object = FALSE; + th->timeout = get_time_ms() + delay; + th->func = JS_DupValue(ctx, resolving_funcs[0]); + list_add_tail(&th->link, &ts->os_timers); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; +} + +static void call_handler(JSContext *ctx, JSValueConst func) +{ + JSValue ret, func1; + /* 'func' might be destroyed when calling itself (if it frees the + handler), so must take extra care */ + func1 = JS_DupValue(ctx, func); + ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL); + JS_FreeValue(ctx, func1); + if (JS_IsException(ret)) + js_std_dump_error(ctx); + JS_FreeValue(ctx, ret); +} + +#if defined(_WIN32) + +static int js_os_poll(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int min_delay, console_fd; + int64_t cur_time, delay; + JSOSRWHandler *rh; + struct list_head *el; + + /* XXX: handle signals if useful */ + + if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers)) + return -1; /* no more events */ + + /* XXX: only timers and basic console input are supported */ + if (!list_empty(&ts->os_timers)) { + cur_time = get_time_ms(); + min_delay = 10000; + list_for_each(el, &ts->os_timers) { + JSOSTimer *th = list_entry(el, JSOSTimer, link); + delay = th->timeout - cur_time; + if (delay <= 0) { + JSValue func; + /* the timer expired */ + func = th->func; + th->func = JS_UNDEFINED; + unlink_timer(rt, th); + if (!th->has_object) + free_timer(rt, th); + call_handler(ctx, func); + JS_FreeValue(ctx, func); + return 0; + } else if (delay < min_delay) { + min_delay = delay; + } + } + } else { + min_delay = -1; + } + + console_fd = -1; + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { + console_fd = rh->fd; + break; + } + } + + if (console_fd >= 0) { + DWORD ti, ret; + HANDLE handle; + if (min_delay == -1) + ti = INFINITE; + else + ti = min_delay; + handle = (HANDLE)_get_osfhandle(console_fd); + ret = WaitForSingleObject(handle, ti); + if (ret == WAIT_OBJECT_0) { + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) { + call_handler(ctx, rh->rw_func[0]); + /* must stop because the list may have been modified */ + break; + } + } + } + } else { + Sleep(min_delay); + } + return 0; +} +#else + +#ifdef USE_WORKER + +static void js_free_message(JSWorkerMessage *msg); + +/* return 1 if a message was handled, 0 if no message */ +static int handle_posted_message(JSRuntime *rt, JSContext *ctx, + JSWorkerMessageHandler *port) +{ + JSWorkerMessagePipe *ps = port->recv_pipe; + int ret; + struct list_head *el; + JSWorkerMessage *msg; + JSValue obj, data_obj, func, retval; + + pthread_mutex_lock(&ps->mutex); + if (!list_empty(&ps->msg_queue)) { + el = ps->msg_queue.next; + msg = list_entry(el, JSWorkerMessage, link); + + /* remove the message from the queue */ + list_del(&msg->link); + + if (list_empty(&ps->msg_queue)) { + uint8_t buf[16]; + int ret; + for(;;) { + ret = read(ps->read_fd, buf, sizeof(buf)); + if (ret >= 0) + break; + if (errno != EAGAIN && errno != EINTR) + break; + } + } + + pthread_mutex_unlock(&ps->mutex); + + data_obj = JS_ReadObject(ctx, msg->data, msg->data_len, + JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE); + + js_free_message(msg); + + if (JS_IsException(data_obj)) + goto fail; + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) { + JS_FreeValue(ctx, data_obj); + goto fail; + } + JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E); + + /* 'func' might be destroyed when calling itself (if it frees the + handler), so must take extra care */ + func = JS_DupValue(ctx, port->on_message_func); + retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj); + JS_FreeValue(ctx, obj); + JS_FreeValue(ctx, func); + if (JS_IsException(retval)) { + fail: + js_std_dump_error(ctx); + } else { + JS_FreeValue(ctx, retval); + } + ret = 1; + } else { + pthread_mutex_unlock(&ps->mutex); + ret = 0; + } + return ret; +} +#else +static int handle_posted_message(JSRuntime *rt, JSContext *ctx, + JSWorkerMessageHandler *port) +{ + return 0; +} +#endif + +static int js_os_poll(JSContext *ctx) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + int ret, fd_max, min_delay; + int64_t cur_time, delay; + fd_set rfds, wfds; + JSOSRWHandler *rh; + struct list_head *el; + struct timeval tv, *tvp; + + /* only check signals in the main thread */ + if (!ts->recv_pipe && + unlikely(os_pending_signals != 0)) { + JSOSSignalHandler *sh; + uint64_t mask; + + list_for_each(el, &ts->os_signal_handlers) { + sh = list_entry(el, JSOSSignalHandler, link); + mask = (uint64_t)1 << sh->sig_num; + if (os_pending_signals & mask) { + os_pending_signals &= ~mask; + call_handler(ctx, sh->func); + return 0; + } + } + } + + if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) && + list_empty(&ts->port_list)) + return -1; /* no more events */ + + if (!list_empty(&ts->os_timers)) { + cur_time = get_time_ms(); + min_delay = 10000; + list_for_each(el, &ts->os_timers) { + JSOSTimer *th = list_entry(el, JSOSTimer, link); + delay = th->timeout - cur_time; + if (delay <= 0) { + JSValue func; + /* the timer expired */ + func = th->func; + th->func = JS_UNDEFINED; + unlink_timer(rt, th); + if (!th->has_object) + free_timer(rt, th); + call_handler(ctx, func); + JS_FreeValue(ctx, func); + return 0; + } else if (delay < min_delay) { + min_delay = delay; + } + } + tv.tv_sec = min_delay / 1000; + tv.tv_usec = (min_delay % 1000) * 1000; + tvp = &tv; + } else { + tvp = NULL; + } + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + fd_max = -1; + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + fd_max = max_int(fd_max, rh->fd); + if (!JS_IsNull(rh->rw_func[0])) + FD_SET(rh->fd, &rfds); + if (!JS_IsNull(rh->rw_func[1])) + FD_SET(rh->fd, &wfds); + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + fd_max = max_int(fd_max, ps->read_fd); + FD_SET(ps->read_fd, &rfds); + } + } + + ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp); + if (ret > 0) { + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (!JS_IsNull(rh->rw_func[0]) && + FD_ISSET(rh->fd, &rfds)) { + call_handler(ctx, rh->rw_func[0]); + /* must stop because the list may have been modified */ + goto done; + } + if (!JS_IsNull(rh->rw_func[1]) && + FD_ISSET(rh->fd, &wfds)) { + call_handler(ctx, rh->rw_func[1]); + /* must stop because the list may have been modified */ + goto done; + } + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + if (FD_ISSET(ps->read_fd, &rfds)) { + if (handle_posted_message(rt, ctx, port)) + goto done; + } + } + } + } + done: + return 0; +} +#endif /* !_WIN32 */ + +static JSValue make_obj_error(JSContext *ctx, + JSValue obj, + int err) +{ + JSValue arr; + if (JS_IsException(obj)) + return obj; + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) + return JS_EXCEPTION; + JS_DefinePropertyValueUint32(ctx, arr, 0, obj, + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err), + JS_PROP_C_W_E); + return arr; +} + +static JSValue make_string_error(JSContext *ctx, + const char *buf, + int err) +{ + return make_obj_error(ctx, JS_NewString(ctx, buf), err); +} + +/* return [cwd, errorcode] */ +static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + char buf[PATH_MAX]; + int err; + + if (!getcwd(buf, sizeof(buf))) { + buf[0] = '\0'; + err = errno; + } else { + err = 0; + } + return make_string_error(ctx, buf, err); +} + +static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *target; + int err; + + target = JS_ToCString(ctx, argv[0]); + if (!target) + return JS_EXCEPTION; + err = js_get_errno(chdir(target)); + JS_FreeCString(ctx, target); + return JS_NewInt32(ctx, err); +} + +static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int mode, ret; + const char *path; + + if (argc >= 2) { + if (JS_ToInt32(ctx, &mode, argv[1])) + return JS_EXCEPTION; + } else { + mode = 0777; + } + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + (void)mode; + ret = js_get_errno(mkdir(path)); +#else + ret = js_get_errno(mkdir(path, mode)); +#endif + JS_FreeCString(ctx, path); + return JS_NewInt32(ctx, ret); +} + +/* return [array, errorcode] */ +static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + DIR *f; + struct dirent *d; + JSValue obj; + int err; + uint32_t len; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) { + JS_FreeCString(ctx, path); + return JS_EXCEPTION; + } + f = opendir(path); + if (!f) + err = errno; + else + err = 0; + JS_FreeCString(ctx, path); + if (!f) + goto done; + len = 0; + for(;;) { + errno = 0; + d = readdir(f); + if (!d) { + err = errno; + break; + } + JS_DefinePropertyValueUint32(ctx, obj, len++, + JS_NewString(ctx, d->d_name), + JS_PROP_C_W_E); + } + closedir(f); + done: + return make_obj_error(ctx, obj, err); +} + +#if !defined(_WIN32) +static int64_t timespec_to_ms(const struct timespec *tv) +{ + return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000); +} +#endif + +/* return [obj, errcode] */ +static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_lstat) +{ + const char *path; + int err, res; + struct stat st; + JSValue obj; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + res = stat(path, &st); +#else + if (is_lstat) + res = lstat(path, &st); + else + res = stat(path, &st); +#endif + JS_FreeCString(ctx, path); + if (res < 0) { + err = errno; + obj = JS_NULL; + } else { + err = 0; + obj = JS_NewObject(ctx); + if (JS_IsException(obj)) + return JS_EXCEPTION; + JS_DefinePropertyValueStr(ctx, obj, "dev", + JS_NewInt64(ctx, st.st_dev), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ino", + JS_NewInt64(ctx, st.st_ino), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mode", + JS_NewInt32(ctx, st.st_mode), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "nlink", + JS_NewInt64(ctx, st.st_nlink), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "uid", + JS_NewInt64(ctx, st.st_uid), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "gid", + JS_NewInt64(ctx, st.st_gid), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "rdev", + JS_NewInt64(ctx, st.st_rdev), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "size", + JS_NewInt64(ctx, st.st_size), + JS_PROP_C_W_E); +#if !defined(_WIN32) + JS_DefinePropertyValueStr(ctx, obj, "blocks", + JS_NewInt64(ctx, st.st_blocks), + JS_PROP_C_W_E); +#endif +#if defined(_WIN32) + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, (int64_t)st.st_atime * 1000), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000), + JS_PROP_C_W_E); +#elif defined(__APPLE__) + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)), + JS_PROP_C_W_E); +#else + JS_DefinePropertyValueStr(ctx, obj, "atime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "mtime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, obj, "ctime", + JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)), + JS_PROP_C_W_E); +#endif + } + return make_obj_error(ctx, obj, err); +} + +#if !defined(_WIN32) +static void ms_to_timeval(struct timeval *tv, uint64_t v) +{ + tv->tv_sec = v / 1000; + tv->tv_usec = (v % 1000) * 1000; +} +#endif + +static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + int64_t atime, mtime; + int ret; + + if (JS_ToInt64(ctx, &atime, argv[1])) + return JS_EXCEPTION; + if (JS_ToInt64(ctx, &mtime, argv[2])) + return JS_EXCEPTION; + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; +#if defined(_WIN32) + { + struct _utimbuf times; + times.actime = atime / 1000; + times.modtime = mtime / 1000; + ret = js_get_errno(_utime(path, ×)); + } +#else + { + struct timeval times[2]; + ms_to_timeval(×[0], atime); + ms_to_timeval(×[1], mtime); + ret = js_get_errno(utimes(path, times)); + } +#endif + JS_FreeCString(ctx, path); + return JS_NewInt32(ctx, ret); +} + +/* sleep(delay_ms) */ +static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int64_t delay; + int ret; + + if (JS_ToInt64(ctx, &delay, argv[0])) + return JS_EXCEPTION; + if (delay < 0) + delay = 0; +#if defined(_WIN32) + { + if (delay > INT32_MAX) + delay = INT32_MAX; + Sleep(delay); + ret = 0; + } +#else + { + struct timespec ts; + + ts.tv_sec = delay / 1000; + ts.tv_nsec = (delay % 1000) * 1000000; + ret = js_get_errno(nanosleep(&ts, NULL)); + } +#endif + return JS_NewInt32(ctx, ret); +} + +#if defined(_WIN32) +static char *realpath(const char *path, char *buf) +{ + if (!_fullpath(buf, path, PATH_MAX)) { + errno = ENOENT; + return NULL; + } else { + return buf; + } +} +#endif + +/* return [path, errorcode] */ +static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + char buf[PATH_MAX], *res; + int err; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + res = realpath(path, buf); + JS_FreeCString(ctx, path); + if (!res) { + buf[0] = '\0'; + err = errno; + } else { + err = 0; + } + return make_string_error(ctx, buf, err); +} + +#if !defined(_WIN32) +static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *target, *linkpath; + int err; + + target = JS_ToCString(ctx, argv[0]); + if (!target) + return JS_EXCEPTION; + linkpath = JS_ToCString(ctx, argv[1]); + if (!linkpath) { + JS_FreeCString(ctx, target); + return JS_EXCEPTION; + } + err = js_get_errno(symlink(target, linkpath)); + JS_FreeCString(ctx, target); + JS_FreeCString(ctx, linkpath); + return JS_NewInt32(ctx, err); +} + +/* return [path, errorcode] */ +static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + const char *path; + char buf[PATH_MAX]; + int err; + ssize_t res; + + path = JS_ToCString(ctx, argv[0]); + if (!path) + return JS_EXCEPTION; + res = readlink(path, buf, sizeof(buf) - 1); + if (res < 0) { + buf[0] = '\0'; + err = errno; + } else { + buf[res] = '\0'; + err = 0; + } + JS_FreeCString(ctx, path); + return make_string_error(ctx, buf, err); +} + +static char **build_envp(JSContext *ctx, JSValueConst obj) +{ + uint32_t len, i; + JSPropertyEnum *tab; + char **envp, *pair; + const char *key, *str; + JSValue val; + size_t key_len, str_len; + + if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj, + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) + return NULL; + envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1)); + if (!envp) + goto fail; + for(i = 0; i < len; i++) { + val = JS_GetProperty(ctx, obj, tab[i].atom); + if (JS_IsException(val)) + goto fail; + str = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!str) + goto fail; + key = JS_AtomToCString(ctx, tab[i].atom); + if (!key) { + JS_FreeCString(ctx, str); + goto fail; + } + key_len = strlen(key); + str_len = strlen(str); + pair = js_malloc(ctx, key_len + str_len + 2); + if (!pair) { + JS_FreeCString(ctx, key); + JS_FreeCString(ctx, str); + goto fail; + } + memcpy(pair, key, key_len); + pair[key_len] = '='; + memcpy(pair + key_len + 1, str, str_len); + pair[key_len + 1 + str_len] = '\0'; + envp[i] = pair; + JS_FreeCString(ctx, key); + JS_FreeCString(ctx, str); + } + done: + for(i = 0; i < len; i++) + JS_FreeAtom(ctx, tab[i].atom); + js_free(ctx, tab); + return envp; + fail: + if (envp) { + for(i = 0; i < len; i++) + js_free(ctx, envp[i]); + js_free(ctx, envp); + envp = NULL; + } + goto done; +} + +/* execvpe is not available on non GNU systems */ +static int my_execvpe(const char *filename, char **argv, char **envp) +{ + char *path, *p, *p_next, *p1; + char buf[PATH_MAX]; + size_t filename_len, path_len; + BOOL eacces_error; + + filename_len = strlen(filename); + if (filename_len == 0) { + errno = ENOENT; + return -1; + } + if (strchr(filename, '/')) + return execve(filename, argv, envp); + + path = getenv("PATH"); + if (!path) + path = (char *)"/bin:/usr/bin"; + eacces_error = FALSE; + p = path; + for(p = path; p != NULL; p = p_next) { + p1 = strchr(p, ':'); + if (!p1) { + p_next = NULL; + path_len = strlen(p); + } else { + p_next = p1 + 1; + path_len = p1 - p; + } + /* path too long */ + if ((path_len + 1 + filename_len + 1) > PATH_MAX) + continue; + memcpy(buf, p, path_len); + buf[path_len] = '/'; + memcpy(buf + path_len + 1, filename, filename_len); + buf[path_len + 1 + filename_len] = '\0'; + + execve(buf, argv, envp); + + switch(errno) { + case EACCES: + eacces_error = TRUE; + break; + case ENOENT: + case ENOTDIR: + break; + default: + return -1; + } + } + if (eacces_error) + errno = EACCES; + return -1; +} + +/* exec(args[, options]) -> exitcode */ +static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValueConst options, args = argv[0]; + JSValue val, ret_val; + const char **exec_argv, *file = NULL, *str, *cwd = NULL; + char **envp = environ; + uint32_t exec_argc, i; + int ret, pid, status; + BOOL block_flag = TRUE, use_path = TRUE; + static const char *std_name[3] = { "stdin", "stdout", "stderr" }; + int std_fds[3]; + uint32_t uid = -1, gid = -1; + + val = JS_GetPropertyStr(ctx, args, "length"); + if (JS_IsException(val)) + return JS_EXCEPTION; + ret = JS_ToUint32(ctx, &exec_argc, val); + JS_FreeValue(ctx, val); + if (ret) + return JS_EXCEPTION; + /* arbitrary limit to avoid overflow */ + if (exec_argc < 1 || exec_argc > 65535) { + return JS_ThrowTypeError(ctx, "invalid number of arguments"); + } + exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1)); + if (!exec_argv) + return JS_EXCEPTION; + for(i = 0; i < exec_argc; i++) { + val = JS_GetPropertyUint32(ctx, args, i); + if (JS_IsException(val)) + goto exception; + str = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!str) + goto exception; + exec_argv[i] = str; + } + exec_argv[exec_argc] = NULL; + + for(i = 0; i < 3; i++) + std_fds[i] = i; + + /* get the options, if any */ + if (argc >= 2) { + options = argv[1]; + + if (get_bool_option(ctx, &block_flag, options, "block")) + goto exception; + if (get_bool_option(ctx, &use_path, options, "usePath")) + goto exception; + + val = JS_GetPropertyStr(ctx, options, "file"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + file = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!file) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "cwd"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + cwd = JS_ToCString(ctx, val); + JS_FreeValue(ctx, val); + if (!cwd) + goto exception; + } + + /* stdin/stdout/stderr handles */ + for(i = 0; i < 3; i++) { + val = JS_GetPropertyStr(ctx, options, std_name[i]); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + int fd; + ret = JS_ToInt32(ctx, &fd, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + std_fds[i] = fd; + } + } + + val = JS_GetPropertyStr(ctx, options, "env"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + envp = build_envp(ctx, val); + JS_FreeValue(ctx, val); + if (!envp) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "uid"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + ret = JS_ToUint32(ctx, &uid, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + } + + val = JS_GetPropertyStr(ctx, options, "gid"); + if (JS_IsException(val)) + goto exception; + if (!JS_IsUndefined(val)) { + ret = JS_ToUint32(ctx, &gid, val); + JS_FreeValue(ctx, val); + if (ret) + goto exception; + } + } + + pid = fork(); + if (pid < 0) { + JS_ThrowTypeError(ctx, "fork error"); + goto exception; + } + if (pid == 0) { + /* child */ + int fd_max = sysconf(_SC_OPEN_MAX); + + /* remap the stdin/stdout/stderr handles if necessary */ + for(i = 0; i < 3; i++) { + if (std_fds[i] != i) { + if (dup2(std_fds[i], i) < 0) + _exit(127); + } + } + + for(i = 3; i < fd_max; i++) + close(i); + if (cwd) { + if (chdir(cwd) < 0) + _exit(127); + } + if (uid != -1) { + if (setuid(uid) < 0) + _exit(127); + } + if (gid != -1) { + if (setgid(gid) < 0) + _exit(127); + } + + if (!file) + file = exec_argv[0]; + if (use_path) + ret = my_execvpe(file, (char **)exec_argv, envp); + else + ret = execve(file, (char **)exec_argv, envp); + _exit(127); + } + /* parent */ + if (block_flag) { + for(;;) { + ret = waitpid(pid, &status, 0); + if (ret == pid) { + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + break; + } else if (WIFSIGNALED(status)) { + ret = -WTERMSIG(status); + break; + } + } + } + } else { + ret = pid; + } + ret_val = JS_NewInt32(ctx, ret); + done: + JS_FreeCString(ctx, file); + JS_FreeCString(ctx, cwd); + for(i = 0; i < exec_argc; i++) + JS_FreeCString(ctx, exec_argv[i]); + js_free(ctx, exec_argv); + if (envp != environ) { + char **p; + p = envp; + while (*p != NULL) { + js_free(ctx, *p); + p++; + } + js_free(ctx, envp); + } + return ret_val; + exception: + ret_val = JS_EXCEPTION; + goto done; +} + +/* getpid() -> pid */ +static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + return JS_NewInt32(ctx, getpid()); +} + +/* waitpid(pid, block) -> [pid, status] */ +static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pid, status, options, ret; + JSValue obj; + + if (JS_ToInt32(ctx, &pid, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &options, argv[1])) + return JS_EXCEPTION; + + ret = waitpid(pid, &status, options); + if (ret < 0) { + ret = -errno; + status = 0; + } + + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret), + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status), + JS_PROP_C_W_E); + return obj; +} + +/* pipe() -> [read_fd, write_fd] or null if error */ +static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pipe_fds[2], ret; + JSValue obj; + + ret = pipe(pipe_fds); + if (ret < 0) + return JS_NULL; + obj = JS_NewArray(ctx); + if (JS_IsException(obj)) + return obj; + JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]), + JS_PROP_C_W_E); + JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]), + JS_PROP_C_W_E); + return obj; +} + +/* kill(pid, sig) */ +static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int pid, sig, ret; + + if (JS_ToInt32(ctx, &pid, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &sig, argv[1])) + return JS_EXCEPTION; + ret = js_get_errno(kill(pid, sig)); + return JS_NewInt32(ctx, ret); +} + +/* dup(fd) */ +static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, ret; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + ret = js_get_errno(dup(fd)); + return JS_NewInt32(ctx, ret); +} + +/* dup2(fd) */ +static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int fd, fd2, ret; + + if (JS_ToInt32(ctx, &fd, argv[0])) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &fd2, argv[1])) + return JS_EXCEPTION; + ret = js_get_errno(dup2(fd, fd2)); + return JS_NewInt32(ctx, ret); +} + +#endif /* !_WIN32 */ + +#ifdef USE_WORKER + +/* Worker */ + +typedef struct { + JSWorkerMessagePipe *recv_pipe; + JSWorkerMessagePipe *send_pipe; + JSWorkerMessageHandler *msg_handler; +} JSWorkerData; + +typedef struct { + char *filename; /* module filename */ + char *basename; /* module base name */ + JSWorkerMessagePipe *recv_pipe, *send_pipe; +} WorkerFuncArgs; + +typedef struct { + int ref_count; + uint64_t buf[0]; +} JSSABHeader; + +static JSClassID js_worker_class_id; +static JSContext *(*js_worker_new_context_func)(JSRuntime *rt); + +static int atomic_add_int(int *ptr, int v) +{ + return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v; +} + +/* shared array buffer allocator */ +static void *js_sab_alloc(void *opaque, size_t size) +{ + JSSABHeader *sab; + sab = malloc(sizeof(JSSABHeader) + size); + if (!sab) + return NULL; + sab->ref_count = 1; + return sab->buf; +} + +static void js_sab_free(void *opaque, void *ptr) +{ + JSSABHeader *sab; + int ref_count; + sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); + ref_count = atomic_add_int(&sab->ref_count, -1); + assert(ref_count >= 0); + if (ref_count == 0) { + free(sab); + } +} + +static void js_sab_dup(void *opaque, void *ptr) +{ + JSSABHeader *sab; + sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader)); + atomic_add_int(&sab->ref_count, 1); +} + +static JSWorkerMessagePipe *js_new_message_pipe(void) +{ + JSWorkerMessagePipe *ps; + int pipe_fds[2]; + + if (pipe(pipe_fds) < 0) + return NULL; + + ps = malloc(sizeof(*ps)); + if (!ps) { + close(pipe_fds[0]); + close(pipe_fds[1]); + return NULL; + } + ps->ref_count = 1; + init_list_head(&ps->msg_queue); + pthread_mutex_init(&ps->mutex, NULL); + ps->read_fd = pipe_fds[0]; + ps->write_fd = pipe_fds[1]; + return ps; +} + +static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps) +{ + atomic_add_int(&ps->ref_count, 1); + return ps; +} + +static void js_free_message(JSWorkerMessage *msg) +{ + size_t i; + /* free the SAB */ + for(i = 0; i < msg->sab_tab_len; i++) { + js_sab_free(NULL, msg->sab_tab[i]); + } + free(msg->sab_tab); + free(msg->data); + free(msg); +} + +static void js_free_message_pipe(JSWorkerMessagePipe *ps) +{ + struct list_head *el, *el1; + JSWorkerMessage *msg; + int ref_count; + + if (!ps) + return; + + ref_count = atomic_add_int(&ps->ref_count, -1); + assert(ref_count >= 0); + if (ref_count == 0) { + list_for_each_safe(el, el1, &ps->msg_queue) { + msg = list_entry(el, JSWorkerMessage, link); + js_free_message(msg); + } + pthread_mutex_destroy(&ps->mutex); + close(ps->read_fd); + close(ps->write_fd); + free(ps); + } +} + +static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port) +{ + if (port) { + js_free_message_pipe(port->recv_pipe); + JS_FreeValueRT(rt, port->on_message_func); + list_del(&port->link); + js_free_rt(rt, port); + } +} + +static void js_worker_finalizer(JSRuntime *rt, JSValue val) +{ + JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id); + if (worker) { + js_free_message_pipe(worker->recv_pipe); + js_free_message_pipe(worker->send_pipe); + js_free_port(rt, worker->msg_handler); + js_free_rt(rt, worker); + } +} + +static JSClassDef js_worker_class = { + "Worker", + .finalizer = js_worker_finalizer, +}; + +static void *worker_func(void *opaque) +{ + WorkerFuncArgs *args = opaque; + JSRuntime *rt; + JSThreadState *ts; + JSContext *ctx; + JSValue promise; + + rt = JS_NewRuntime(); + if (rt == NULL) { + fprintf(stderr, "JS_NewRuntime failure"); + exit(1); + } + js_std_init_handlers(rt); + + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); + + /* set the pipe to communicate with the parent */ + ts = JS_GetRuntimeOpaque(rt); + ts->recv_pipe = args->recv_pipe; + ts->send_pipe = args->send_pipe; + + /* function pointer to avoid linking the whole JS_NewContext() if + not needed */ + ctx = js_worker_new_context_func(rt); + if (ctx == NULL) { + fprintf(stderr, "JS_NewContext failure"); + } + + JS_SetCanBlock(rt, TRUE); + + js_std_add_helpers(ctx, -1, NULL); + + promise = JS_LoadModule(ctx, args->basename, args->filename); + if (JS_IsException(promise)) + js_std_dump_error(ctx); + /* XXX: check */ + JS_FreeValue(ctx, promise); + free(args->filename); + free(args->basename); + free(args); + + js_std_loop(ctx); + + JS_FreeContext(ctx); + js_std_free_handlers(rt); + JS_FreeRuntime(rt); + return NULL; +} + +static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target, + JSWorkerMessagePipe *recv_pipe, + JSWorkerMessagePipe *send_pipe) +{ + JSValue obj = JS_UNDEFINED, proto; + JSWorkerData *s; + + /* create the object */ + if (JS_IsUndefined(new_target)) { + proto = JS_GetClassProto(ctx, js_worker_class_id); + } else { + proto = JS_GetPropertyStr(ctx, new_target, "prototype"); + if (JS_IsException(proto)) + goto fail; + } + obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id); + JS_FreeValue(ctx, proto); + if (JS_IsException(obj)) + goto fail; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + goto fail; + s->recv_pipe = js_dup_message_pipe(recv_pipe); + s->send_pipe = js_dup_message_pipe(send_pipe); + + JS_SetOpaque(obj, s); + return obj; + fail: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, + int argc, JSValueConst *argv) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + WorkerFuncArgs *args = NULL; + pthread_t tid; + pthread_attr_t attr; + JSValue obj = JS_UNDEFINED; + int ret; + const char *filename = NULL, *basename; + JSAtom basename_atom; + + /* XXX: in order to avoid problems with resource liberation, we + don't support creating workers inside workers */ + if (!is_main_thread(rt)) + return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker"); + + /* base name, assuming the calling function is a normal JS + function */ + basename_atom = JS_GetScriptOrModuleName(ctx, 1); + if (basename_atom == JS_ATOM_NULL) { + return JS_ThrowTypeError(ctx, "could not determine calling script or module name"); + } + basename = JS_AtomToCString(ctx, basename_atom); + JS_FreeAtom(ctx, basename_atom); + if (!basename) + goto fail; + + /* module name */ + filename = JS_ToCString(ctx, argv[0]); + if (!filename) + goto fail; + + args = malloc(sizeof(*args)); + if (!args) + goto oom_fail; + memset(args, 0, sizeof(*args)); + args->filename = strdup(filename); + args->basename = strdup(basename); + + /* ports */ + args->recv_pipe = js_new_message_pipe(); + if (!args->recv_pipe) + goto oom_fail; + args->send_pipe = js_new_message_pipe(); + if (!args->send_pipe) + goto oom_fail; + + obj = js_worker_ctor_internal(ctx, new_target, + args->send_pipe, args->recv_pipe); + if (JS_IsException(obj)) + goto fail; + + pthread_attr_init(&attr); + /* no join at the end */ + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + ret = pthread_create(&tid, &attr, worker_func, args); + pthread_attr_destroy(&attr); + if (ret != 0) { + JS_ThrowTypeError(ctx, "could not create worker"); + goto fail; + } + JS_FreeCString(ctx, basename); + JS_FreeCString(ctx, filename); + return obj; + oom_fail: + JS_ThrowOutOfMemory(ctx); + fail: + JS_FreeCString(ctx, basename); + JS_FreeCString(ctx, filename); + if (args) { + free(args->filename); + free(args->basename); + js_free_message_pipe(args->recv_pipe); + js_free_message_pipe(args->send_pipe); + free(args); + } + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); + JSWorkerMessagePipe *ps; + size_t data_len, sab_tab_len, i; + uint8_t *data; + JSWorkerMessage *msg; + uint8_t **sab_tab; + + if (!worker) + return JS_EXCEPTION; + + data = JS_WriteObject2(ctx, &data_len, argv[0], + JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE, + &sab_tab, &sab_tab_len); + if (!data) + return JS_EXCEPTION; + + msg = malloc(sizeof(*msg)); + if (!msg) + goto fail; + msg->data = NULL; + msg->sab_tab = NULL; + + /* must reallocate because the allocator may be different */ + msg->data = malloc(data_len); + if (!msg->data) + goto fail; + memcpy(msg->data, data, data_len); + msg->data_len = data_len; + + msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len); + if (!msg->sab_tab) + goto fail; + memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len); + msg->sab_tab_len = sab_tab_len; + + js_free(ctx, data); + js_free(ctx, sab_tab); + + /* increment the SAB reference counts */ + for(i = 0; i < msg->sab_tab_len; i++) { + js_sab_dup(NULL, msg->sab_tab[i]); + } + + ps = worker->send_pipe; + pthread_mutex_lock(&ps->mutex); + /* indicate that data is present */ + if (list_empty(&ps->msg_queue)) { + uint8_t ch = '\0'; + int ret; + for(;;) { + ret = write(ps->write_fd, &ch, 1); + if (ret == 1) + break; + if (ret < 0 && (errno != EAGAIN || errno != EINTR)) + break; + } + } + list_add_tail(&msg->link, &ps->msg_queue); + pthread_mutex_unlock(&ps->mutex); + return JS_UNDEFINED; + fail: + if (msg) { + free(msg->data); + free(msg->sab_tab); + free(msg); + } + js_free(ctx, data); + js_free(ctx, sab_tab); + return JS_EXCEPTION; + +} + +static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val, + JSValueConst func) +{ + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); + JSWorkerMessageHandler *port; + + if (!worker) + return JS_EXCEPTION; + + port = worker->msg_handler; + if (JS_IsNull(func)) { + if (port) { + js_free_port(rt, port); + worker->msg_handler = NULL; + } + } else { + if (!JS_IsFunction(ctx, func)) + return JS_ThrowTypeError(ctx, "not a function"); + if (!port) { + port = js_mallocz(ctx, sizeof(*port)); + if (!port) + return JS_EXCEPTION; + port->recv_pipe = js_dup_message_pipe(worker->recv_pipe); + port->on_message_func = JS_NULL; + list_add_tail(&port->link, &ts->port_list); + worker->msg_handler = port; + } + JS_FreeValue(ctx, port->on_message_func); + port->on_message_func = JS_DupValue(ctx, func); + } + return JS_UNDEFINED; +} + +static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val) +{ + JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id); + JSWorkerMessageHandler *port; + if (!worker) + return JS_EXCEPTION; + port = worker->msg_handler; + if (port) { + return JS_DupValue(ctx, port->on_message_func); + } else { + return JS_NULL; + } +} + +static const JSCFunctionListEntry js_worker_proto_funcs[] = { + JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ), + JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ), +}; + +#endif /* USE_WORKER */ + +void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)) +{ +#ifdef USE_WORKER + js_worker_new_context_func = func; +#endif +} + +#if defined(_WIN32) +#define OS_PLATFORM "win32" +#elif defined(__APPLE__) +#define OS_PLATFORM "darwin" +#elif defined(EMSCRIPTEN) +#define OS_PLATFORM "js" +#else +#define OS_PLATFORM "linux" +#endif + +#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE ) + +static const JSCFunctionListEntry js_os_funcs[] = { + JS_CFUNC_DEF("open", 2, js_os_open ), + OS_FLAG(O_RDONLY), + OS_FLAG(O_WRONLY), + OS_FLAG(O_RDWR), + OS_FLAG(O_APPEND), + OS_FLAG(O_CREAT), + OS_FLAG(O_EXCL), + OS_FLAG(O_TRUNC), +#if defined(_WIN32) + OS_FLAG(O_BINARY), + OS_FLAG(O_TEXT), +#endif + JS_CFUNC_DEF("close", 1, js_os_close ), + JS_CFUNC_DEF("seek", 3, js_os_seek ), + JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ), + JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ), + JS_CFUNC_DEF("isatty", 1, js_os_isatty ), + JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ), + JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ), + JS_CFUNC_DEF("remove", 1, js_os_remove ), + JS_CFUNC_DEF("rename", 2, js_os_rename ), + JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ), + JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ), + JS_CFUNC_DEF("signal", 2, js_os_signal ), + OS_FLAG(SIGINT), + OS_FLAG(SIGABRT), + OS_FLAG(SIGFPE), + OS_FLAG(SIGILL), + OS_FLAG(SIGSEGV), + OS_FLAG(SIGTERM), +#if !defined(_WIN32) + OS_FLAG(SIGQUIT), + OS_FLAG(SIGPIPE), + OS_FLAG(SIGALRM), + OS_FLAG(SIGUSR1), + OS_FLAG(SIGUSR2), + OS_FLAG(SIGCHLD), + OS_FLAG(SIGCONT), + OS_FLAG(SIGSTOP), + OS_FLAG(SIGTSTP), + OS_FLAG(SIGTTIN), + OS_FLAG(SIGTTOU), +#endif + JS_CFUNC_DEF("now", 0, js_os_now ), + JS_CFUNC_DEF("setTimeout", 2, js_os_setTimeout ), + JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ), + JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ), + JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ), + JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ), + JS_CFUNC_DEF("chdir", 0, js_os_chdir ), + JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ), + JS_CFUNC_DEF("readdir", 1, js_os_readdir ), + /* st_mode constants */ + OS_FLAG(S_IFMT), + OS_FLAG(S_IFIFO), + OS_FLAG(S_IFCHR), + OS_FLAG(S_IFDIR), + OS_FLAG(S_IFBLK), + OS_FLAG(S_IFREG), +#if !defined(_WIN32) + OS_FLAG(S_IFSOCK), + OS_FLAG(S_IFLNK), + OS_FLAG(S_ISGID), + OS_FLAG(S_ISUID), +#endif + JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ), + JS_CFUNC_DEF("utimes", 3, js_os_utimes ), + JS_CFUNC_DEF("sleep", 1, js_os_sleep ), + JS_CFUNC_DEF("realpath", 1, js_os_realpath ), +#if !defined(_WIN32) + JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ), + JS_CFUNC_DEF("symlink", 2, js_os_symlink ), + JS_CFUNC_DEF("readlink", 1, js_os_readlink ), + JS_CFUNC_DEF("exec", 1, js_os_exec ), + JS_CFUNC_DEF("getpid", 0, js_os_getpid ), + JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ), + OS_FLAG(WNOHANG), + JS_CFUNC_DEF("pipe", 0, js_os_pipe ), + JS_CFUNC_DEF("kill", 2, js_os_kill ), + JS_CFUNC_DEF("dup", 1, js_os_dup ), + JS_CFUNC_DEF("dup2", 2, js_os_dup2 ), +#endif +}; + +static int js_os_init(JSContext *ctx, JSModuleDef *m) +{ + os_poll_func = js_os_poll; + + /* OSTimer class */ + JS_NewClassID(&js_os_timer_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_os_timer_class_id, &js_os_timer_class); + +#ifdef USE_WORKER + { + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + JSValue proto, obj; + /* Worker class */ + JS_NewClassID(&js_worker_class_id); + JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class); + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs)); + + obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1, + JS_CFUNC_constructor, 0); + JS_SetConstructor(ctx, obj, proto); + + JS_SetClassProto(ctx, js_worker_class_id, proto); + + /* set 'Worker.parent' if necessary */ + if (ts->recv_pipe && ts->send_pipe) { + JS_DefinePropertyValueStr(ctx, obj, "parent", + js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe), + JS_PROP_C_W_E); + } + + JS_SetModuleExport(ctx, m, "Worker", obj); + } +#endif /* USE_WORKER */ + + return JS_SetModuleExportList(ctx, m, js_os_funcs, + countof(js_os_funcs)); +} + +JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_os_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs)); +#ifdef USE_WORKER + JS_AddModuleExport(ctx, m, "Worker"); +#endif + return m; +} + +/**********************************************************/ + +static JSValue js_print(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int i; + const char *str; + size_t len; + + for(i = 0; i < argc; i++) { + if (i != 0) + putchar(' '); + str = JS_ToCStringLen(ctx, &len, argv[i]); + if (!str) + return JS_EXCEPTION; + fwrite(str, 1, len, stdout); + JS_FreeCString(ctx, str); + } + putchar('\n'); + return JS_UNDEFINED; +} + +void js_std_add_helpers(JSContext *ctx, int argc, char **argv) +{ + JSValue global_obj, console, args; + int i; + + /* XXX: should these global definitions be enumerable? */ + global_obj = JS_GetGlobalObject(ctx); + + console = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, console, "log", + JS_NewCFunction(ctx, js_print, "log", 1)); + JS_SetPropertyStr(ctx, global_obj, "console", console); + + /* same methods as the mozilla JS shell */ + if (argc >= 0) { + args = JS_NewArray(ctx); + for(i = 0; i < argc; i++) { + JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i])); + } + JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args); + } + + JS_SetPropertyStr(ctx, global_obj, "print", + JS_NewCFunction(ctx, js_print, "print", 1)); + JS_SetPropertyStr(ctx, global_obj, "__loadScript", + JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1)); + + JS_FreeValue(ctx, global_obj); +} + +void js_std_init_handlers(JSRuntime *rt) +{ + JSThreadState *ts; + + ts = malloc(sizeof(*ts)); + if (!ts) { + fprintf(stderr, "Could not allocate memory for the worker"); + exit(1); + } + memset(ts, 0, sizeof(*ts)); + init_list_head(&ts->os_rw_handlers); + init_list_head(&ts->os_signal_handlers); + init_list_head(&ts->os_timers); + init_list_head(&ts->port_list); + + JS_SetRuntimeOpaque(rt, ts); + +#ifdef USE_WORKER + /* set the SharedArrayBuffer memory handlers */ + { + JSSharedArrayBufferFunctions sf; + memset(&sf, 0, sizeof(sf)); + sf.sab_alloc = js_sab_alloc; + sf.sab_free = js_sab_free; + sf.sab_dup = js_sab_dup; + JS_SetSharedArrayBufferFunctions(rt, &sf); + } +#endif +} + +void js_std_free_handlers(JSRuntime *rt) +{ + JSThreadState *ts = JS_GetRuntimeOpaque(rt); + struct list_head *el, *el1; + + list_for_each_safe(el, el1, &ts->os_rw_handlers) { + JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link); + free_rw_handler(rt, rh); + } + + list_for_each_safe(el, el1, &ts->os_signal_handlers) { + JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link); + free_sh(rt, sh); + } + + list_for_each_safe(el, el1, &ts->os_timers) { + JSOSTimer *th = list_entry(el, JSOSTimer, link); + unlink_timer(rt, th); + if (!th->has_object) + free_timer(rt, th); + } + +#ifdef USE_WORKER + /* XXX: free port_list ? */ + js_free_message_pipe(ts->recv_pipe); + js_free_message_pipe(ts->send_pipe); +#endif + + free(ts); + JS_SetRuntimeOpaque(rt, NULL); /* fail safe */ +} + +static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val) +{ + const char *str; + + str = JS_ToCString(ctx, val); + if (str) { + fprintf(f, "%s\n", str); + JS_FreeCString(ctx, str); + } else { + fprintf(f, "[exception]\n"); + } +} + +static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val) +{ + JSValue val; + BOOL is_error; + + is_error = JS_IsError(ctx, exception_val); + js_dump_obj(ctx, stderr, exception_val); + if (is_error) { + val = JS_GetPropertyStr(ctx, exception_val, "stack"); + if (!JS_IsUndefined(val)) { + js_dump_obj(ctx, stderr, val); + } + JS_FreeValue(ctx, val); + } +} + +void js_std_dump_error(JSContext *ctx) +{ + JSValue exception_val; + + exception_val = JS_GetException(ctx); + js_std_dump_error1(ctx, exception_val); + JS_FreeValue(ctx, exception_val); +} + +void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, + JSValueConst reason, + BOOL is_handled, void *opaque) +{ + if (!is_handled) { + fprintf(stderr, "Possibly unhandled promise rejection: "); + js_std_dump_error1(ctx, reason); + } +} + +/* main loop which calls the user JS callbacks */ +void js_std_loop(JSContext *ctx) +{ + JSContext *ctx1; + int err; + + for(;;) { + /* execute the pending jobs */ + for(;;) { + err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (err <= 0) { + if (err < 0) { + js_std_dump_error(ctx1); + } + break; + } + } + + if (!os_poll_func || os_poll_func(ctx)) + break; + } +} + +void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int load_only) +{ + JSValue obj, val; + obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE); + if (JS_IsException(obj)) + goto exception; + if (load_only) { + if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { + js_module_set_import_meta(ctx, obj, FALSE, FALSE); + } + } else { + if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) { + if (JS_ResolveModule(ctx, obj) < 0) { + JS_FreeValue(ctx, obj); + goto exception; + } + js_module_set_import_meta(ctx, obj, FALSE, TRUE); + } + val = JS_EvalFunction(ctx, obj); + if (JS_IsException(val)) { + exception: + js_std_dump_error(ctx); + exit(1); + } + JS_FreeValue(ctx, val); + } +} diff --git a/deps/quickjs/quickjs-libc.h b/deps/quickjs/quickjs-libc.h new file mode 100644 index 0000000..fbbe5b0 --- /dev/null +++ b/deps/quickjs/quickjs-libc.h @@ -0,0 +1,59 @@ +/* + * QuickJS C library + * + * Copyright (c) 2017-2018 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QUICKJS_LIBC_H +#define QUICKJS_LIBC_H + +#include +#include + +#include "quickjs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); +JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); +void js_std_add_helpers(JSContext *ctx, int argc, char **argv); +void js_std_loop(JSContext *ctx); +void js_std_init_handlers(JSRuntime *rt); +void js_std_free_handlers(JSRuntime *rt); +void js_std_dump_error(JSContext *ctx); +uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); +int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + JS_BOOL use_realpath, JS_BOOL is_main); +JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque); +void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, + int flags); +void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, + JSValueConst reason, + JS_BOOL is_handled, void *opaque); +void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); + +#ifdef __cplusplus +} /* extern "C" { */ +#endif + +#endif /* QUICKJS_LIBC_H */ diff --git a/quickjs/quickjs-opcode.h b/deps/quickjs/quickjs-opcode.h similarity index 95% rename from quickjs/quickjs-opcode.h rename to deps/quickjs/quickjs-opcode.h index c731a14..6d2d6e9 100644 --- a/quickjs/quickjs-opcode.h +++ b/deps/quickjs/quickjs-opcode.h @@ -172,6 +172,7 @@ DEF(set_loc_uninitialized, 3, 0, 0, loc) DEF( get_loc_check, 3, 0, 1, loc) DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ DEF( put_loc_check_init, 3, 1, 0, loc) +DEF(get_loc_checkthis, 3, 0, 1, loc) DEF(get_var_ref_check, 3, 0, 1, var_ref) DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ DEF(put_var_ref_check_init, 3, 1, 0, var_ref) @@ -182,6 +183,7 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */ DEF( catch, 5, 0, 1, label) DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ +DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */ DEF( to_object, 1, 1, 1, none) //DEF( to_string, 1, 1, 1, none) @@ -208,7 +210,6 @@ DEF( for_of_next, 2, 3, 5, u8) DEF(iterator_check_object, 1, 1, 1, none) DEF(iterator_get_value_done, 1, 1, 2, none) DEF( iterator_close, 1, 3, 0, none) -DEF(iterator_close_return, 1, 4, 4, none) DEF( iterator_next, 1, 4, 4, none) DEF( iterator_call, 2, 4, 5, u8) DEF( initial_yield, 1, 0, 0, none) @@ -256,6 +257,7 @@ DEF( and, 1, 2, 1, none) DEF( xor, 1, 2, 1, none) DEF( or, 1, 2, 1, none) DEF(is_undefined_or_null, 1, 1, 1, none) +DEF( private_in, 1, 2, 1, none) #ifdef CONFIG_BIGNUM DEF( mul_pow10, 1, 2, 1, none) DEF( math_mod, 1, 2, 1, none) @@ -270,6 +272,8 @@ def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ +/* the following opcodes must be in the same order as the 'with_x' and + get_var_undef, get_var and put_var opcodes */ def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ @@ -277,10 +281,13 @@ def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ +def(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */ def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ -def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ - +def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ +def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */ +def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */ +def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ diff --git a/quickjs/quickjs.c b/deps/quickjs/quickjs.c similarity index 94% rename from quickjs/quickjs.c rename to deps/quickjs/quickjs.c index 7f3b1ea..4e58a98 100644 --- a/quickjs/quickjs.c +++ b/deps/quickjs/quickjs.c @@ -23,37 +23,28 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" - #include -#include -#include "my_inttypes.h" -#include -// #include -// #include -// #include -// #include -#include "my_math.h" +#include #include -#include "my_string.h" +#include +#include +#include +#include +#include +#if defined(__APPLE__) +#include +#elif defined(__linux__) +#include +#elif defined(__FreeBSD__) +#include +#endif #include "cutils.h" #include "list.h" #include "quickjs.h" #include "libregexp.h" -#ifdef CONFIG_BIGNUM #include "libbf.h" -#endif - -#include "mocked.h" - -int isnan(double x) { return __builtin_isnan(x); } - -int isfinite(double x) { return __builtin_isfinite(x); } - -double trunc(double x) { return __builtin_truncl(x); } #define OPTIMIZE 1 #define SHORT_OPCODES 1 @@ -69,21 +60,21 @@ double trunc(double x) { return __builtin_truncl(x); } #define MALLOC_OVERHEAD 8 #endif -// #if !defined(_WIN32) +#if !defined(_WIN32) /* define it if printf uses the RNDN rounding mode instead of RNDNA */ -// #define CONFIG_PRINTF_RNDN -// #endif +#define CONFIG_PRINTF_RNDN +#endif /* define to include Atomics.* operations which depend on the OS threads */ -// #if !defined(EMSCRIPTEN) -// #define CONFIG_ATOMICS -// #endif +#if !defined(EMSCRIPTEN) +#define CONFIG_ATOMICS +#endif -// #if !defined(EMSCRIPTEN) +#if !defined(EMSCRIPTEN) /* enable stack limitation */ -// #define CONFIG_STACK_CHECK -// #endif +#define CONFIG_STACK_CHECK +#endif /* dump object free */ @@ -96,6 +87,7 @@ double trunc(double x) { return __builtin_truncl(x); } 8: dump stdlib functions 16: dump bytecode in hex 32: dump line number table + 64: dump compute_stack_size */ //#define DUMP_BYTECODE (1) /* dump the occurence of the automatic GC */ @@ -151,15 +143,13 @@ enum { JS_CLASS_UINT16_ARRAY, /* u.array (typed_array) */ JS_CLASS_INT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_UINT32_ARRAY, /* u.array (typed_array) */ -#ifdef CONFIG_BIGNUM JS_CLASS_BIG_INT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_BIG_UINT64_ARRAY, /* u.array (typed_array) */ -#endif JS_CLASS_FLOAT32_ARRAY, /* u.array (typed_array) */ JS_CLASS_FLOAT64_ARRAY, /* u.array (typed_array) */ JS_CLASS_DATAVIEW, /* u.typed_array */ -#ifdef CONFIG_BIGNUM JS_CLASS_BIG_INT, /* u.object_data */ +#ifdef CONFIG_BIGNUM JS_CLASS_BIG_FLOAT, /* u.object_data */ JS_CLASS_FLOAT_ENV, /* u.float_env */ JS_CLASS_BIG_DECIMAL, /* u.object_data */ @@ -207,7 +197,7 @@ typedef enum JSErrorEnum { JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */ } JSErrorEnum; -#define JS_MAX_LOCAL_VARS 65536 +#define JS_MAX_LOCAL_VARS 65535 #define JS_STACK_SIZE_MAX 65534 #define JS_STRING_LEN_MAX ((1 << 30) - 1) @@ -225,7 +215,6 @@ typedef enum { typedef enum OPCodeEnum OPCodeEnum; -#ifdef CONFIG_BIGNUM /* function pointers are used for numeric operations so that it is possible to remove some numeric types */ typedef struct { @@ -243,7 +232,6 @@ typedef struct { int64_t exponent); int (*mul_pow10)(JSContext *ctx, JSValue *sp); } JSNumericOperations; -#endif struct JSRuntime { JSMallocFunctions mf; @@ -295,7 +283,9 @@ struct JSRuntime { JSModuleNormalizeFunc *module_normalize_func; JSModuleLoaderFunc *module_loader_func; void *module_loader_opaque; - + /* timestamp for internal use in module evaluation */ + int64_t module_async_evaluation_next_timestamp; + BOOL can_block : 8; /* TRUE if Atomics.wait can block */ /* used to allocate, free and clone SharedArrayBuffers */ JSSharedArrayBufferFunctions sab_funcs; @@ -305,9 +295,9 @@ struct JSRuntime { int shape_hash_size; int shape_hash_count; /* number of hashed shapes */ JSShape **shape_hash; -#ifdef CONFIG_BIGNUM bf_context_t bf_ctx; JSNumericOperations bigint_ops; +#ifdef CONFIG_BIGNUM JSNumericOperations bigfloat_ops; JSNumericOperations bigdecimal_ops; uint32_t operator_count; @@ -328,17 +318,18 @@ struct JSClass { #define JS_MODE_STRICT (1 << 0) #define JS_MODE_STRIP (1 << 1) #define JS_MODE_MATH (1 << 2) +#define JS_MODE_ASYNC (1 << 3) /* async function */ typedef struct JSStackFrame { struct JSStackFrame *prev_frame; /* NULL if first stack frame */ JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */ JSValue *arg_buf; /* arguments */ JSValue *var_buf; /* variables */ - struct list_head var_ref_list; /* list of JSVarRef.link */ + struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ const uint8_t *cur_pc; /* only used in bytecode functions : PC of the instruction after the call */ int arg_count; - int js_mode; /* 0 or JS_MODE_MATH for C functions */ + int js_mode; /* for C functions, only JS_MODE_MATH may be set */ /* only used in generators. Current stack pointer value. NULL if the function is running. */ JSValue *cur_sp; @@ -371,11 +362,6 @@ typedef struct JSVarRef { struct { int __gc_ref_count; /* corresponds to header.ref_count */ uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */ - - /* 0 : the JSVarRef is on the stack. header.link is an element - of JSStackFrame.var_ref_list. - 1 : the JSVarRef is detached. header.link has the normal meanning - */ uint8_t is_detached : 1; uint8_t is_arg : 1; uint16_t var_idx; /* index of the corresponding function variable on @@ -384,16 +370,15 @@ typedef struct JSVarRef { }; JSValue *pvalue; /* pointer to the value, either on the stack or to 'value' */ - JSValue value; /* used when the variable is no longer on the stack */ + union { + JSValue value; /* used when is_detached = TRUE */ + struct { + struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */ + struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */ + }; /* used when is_detached = FALSE */ + }; } JSVarRef; -#ifdef CONFIG_BIGNUM -typedef struct JSFloatEnv { - limb_t prec; - bf_flags_t flags; - unsigned int status; -} JSFloatEnv; - /* the same structure is used for big integers and big floats. Big integers are never infinite or NaNs */ typedef struct JSBigFloat { @@ -401,6 +386,13 @@ typedef struct JSBigFloat { bf_t num; } JSBigFloat; +#ifdef CONFIG_BIGNUM +typedef struct JSFloatEnv { + limb_t prec; + bf_flags_t flags; + unsigned int status; +} JSFloatEnv; + typedef struct JSBigDecimal { JSRefCountHeader header; /* must come first, 32-bit */ bfdec_t num; @@ -444,15 +436,14 @@ struct JSContext { JSValue global_var_obj; /* contains the global let/const definitions */ uint64_t random_state; -#ifdef CONFIG_BIGNUM bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */ +#ifdef CONFIG_BIGNUM JSFloatEnv fp_env; /* global FP environment */ BOOL bignum_ext : 8; /* enable math mode */ BOOL allow_operator_overloading : 8; #endif /* when the counter reaches zero, JSRutime.interrupt_handler is called */ int interrupt_counter; - BOOL is_error_property_enabled; struct list_head loaded_modules; /* list of JSModuleDef.link */ @@ -565,6 +556,7 @@ typedef struct JSVarDef { uint8_t is_const : 1; uint8_t is_lexical : 1; uint8_t is_captured : 1; + uint8_t is_static_private : 1; /* only used during private class field parsing */ uint8_t var_kind : 4; /* see JSVarKindEnum */ /* only used during compilation: function pool index for lexical variables with var_kind = @@ -605,6 +597,7 @@ typedef struct JSFunctionBytecode { uint8_t has_debug : 1; uint8_t backtrace_barrier : 1; /* stop backtrace on this function */ uint8_t read_only_bytecode : 1; + uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */ /* XXX: 4 bits available */ uint8_t *byte_code_buf; /* (self pointer) */ int byte_code_len; @@ -645,9 +638,11 @@ typedef enum JSIteratorKindEnum { typedef struct JSForInIterator { JSValue obj; - BOOL is_array; - uint32_t array_length; uint32_t idx; + uint32_t atom_count; + uint8_t in_prototype_chain; + uint8_t is_array; + JSPropertyEnum *tab_atom; /* is_array = FALSE */ } JSForInIterator; typedef struct JSRegExp { @@ -681,21 +676,16 @@ typedef struct JSTypedArray { } JSTypedArray; typedef struct JSAsyncFunctionState { - JSValue this_val; /* 'this' generator argument */ + JSGCObjectHeader header; + JSValue this_val; /* 'this' argument */ int argc; /* number of function arguments */ BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */ + BOOL is_completed; /* TRUE if the function has returned. The stack + frame is no longer valid */ + JSValue resolving_funcs[2]; /* only used in JS async functions */ JSStackFrame frame; } JSAsyncFunctionState; -/* XXX: could use an object instead to avoid the - JS_TAG_ASYNC_FUNCTION tag for the GC */ -typedef struct JSAsyncFunctionData { - JSGCObjectHeader header; /* must come first */ - JSValue resolving_funcs[2]; - BOOL is_active; /* true if the async function state is valid */ - JSAsyncFunctionState func_state; -} JSAsyncFunctionData; - typedef enum { /* binary operators */ JS_OVOP_ADD, @@ -777,6 +767,15 @@ typedef struct JSImportEntry { int req_module_idx; /* in req_module_entries */ } JSImportEntry; +typedef enum { + JS_MODULE_STATUS_UNLINKED, + JS_MODULE_STATUS_LINKING, + JS_MODULE_STATUS_LINKED, + JS_MODULE_STATUS_EVALUATING, + JS_MODULE_STATUS_EVALUATING_ASYNC, + JS_MODULE_STATUS_EVALUATED, +} JSModuleStatus; + struct JSModuleDef { JSRefCountHeader header; /* must come first, 32-bit */ JSAtom module_name; @@ -801,11 +800,24 @@ struct JSModuleDef { JSValue module_ns; JSValue func_obj; /* only used for JS modules */ JSModuleInitFunc *init_func; /* only used for C modules */ + BOOL has_tla : 8; /* true if func_obj contains await */ BOOL resolved : 8; BOOL func_created : 8; - BOOL instantiated : 8; - BOOL evaluated : 8; - BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */ + JSModuleStatus status : 8; + /* temp use during js_module_link() & js_module_evaluate() */ + int dfs_index, dfs_ancestor_index; + JSModuleDef *stack_prev; + /* temp use during js_module_evaluate() */ + JSModuleDef **async_parent_modules; + int async_parent_modules_count; + int async_parent_modules_size; + int pending_async_dependencies; + BOOL async_evaluation; + int64_t async_evaluation_timestamp; + JSModuleDef *cycle_root; + JSValue promise; /* corresponds to spec field: capability */ + JSValue resolving_funcs[2]; /* corresponds to spec field: capability */ + /* true if evaluation yielded an exception. It is saved in eval_exception */ BOOL eval_has_exception : 8; @@ -913,7 +925,7 @@ struct JSObject { struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */ struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */ struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */ - struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ + struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */ struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */ struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */ struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ @@ -1124,6 +1136,18 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val); static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val); static JSProperty *add_property(JSContext *ctx, JSObject *p, JSAtom prop, int prop_flags); +static JSValue JS_NewBigInt(JSContext *ctx); +static inline bf_t *JS_GetBigInt(JSValueConst val) +{ + JSBigFloat *p = JS_VALUE_GET_PTR(val); + return &p->num; +} +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, + BOOL convert_to_safe_integer); +static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); +static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); +static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); +static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); #ifdef CONFIG_BIGNUM static void js_float_env_finalizer(JSRuntime *rt, JSValue val); static JSValue JS_NewBigFloat(JSContext *ctx); @@ -1138,18 +1162,6 @@ static inline bfdec_t *JS_GetBigDecimal(JSValueConst val) JSBigDecimal *p = JS_VALUE_GET_PTR(val); return &p->num; } -static JSValue JS_NewBigInt(JSContext *ctx); -static inline bf_t *JS_GetBigInt(JSValueConst val) -{ - JSBigFloat *p = JS_VALUE_GET_PTR(val); - return &p->num; -} -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer); -static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val); -static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val); -static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val); -static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf); static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val); static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val, BOOL allow_null_or_undefined); @@ -1180,11 +1192,17 @@ static JSValue js_typed_array_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int classid); +static JSValue js_typed_array_constructor_ta(JSContext *ctx, + JSValueConst new_target, + JSValueConst src_obj, + int classid); static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p); static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p); static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx); static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg); +static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s); static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, @@ -1210,6 +1228,8 @@ static __exception int perform_promise_then(JSContext *ctx, JSValueConst *cap_resolving_funcs); static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); +static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); static int js_string_compare(JSContext *ctx, const JSString *p1, const JSString *p2); static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val); @@ -1221,8 +1241,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val); static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc, JSObject *p, JSAtom prop); static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc); -static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, - JS_MarkFunc *mark_func); static void JS_AddIntrinsicBasicObjects(JSContext *ctx); static void js_free_shape(JSRuntime *rt, JSShape *sh); static void js_free_shape_null(JSRuntime *rt, JSShape *sh); @@ -1250,13 +1268,14 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type); static void remove_gc_object(JSGCObjectHeader *h); -static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s); static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag); +static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_map); static const JSClassExoticMethods js_arguments_exotic_methods; static const JSClassExoticMethods js_string_exotic_methods; @@ -1318,14 +1337,12 @@ void *js_mallocz_rt(JSRuntime *rt, size_t size) return memset(ptr, 0, size); } -#ifdef CONFIG_BIGNUM /* called by libbf */ static void *js_bf_realloc(void *opaque, void *ptr, size_t size) { JSRuntime *rt = opaque; return js_realloc_rt(rt, ptr, size); } -#endif /* CONFIG_BIGNUM */ /* Throw out of memory in case of error */ void *js_malloc(JSContext *ctx, size_t size) @@ -1476,15 +1493,13 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT16_ARRAY */ { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_INT32_ARRAY */ { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT32_ARRAY */ -#ifdef CONFIG_BIGNUM { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_INT64_ARRAY */ { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_BIG_UINT64_ARRAY */ -#endif { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT32_ARRAY */ { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_FLOAT64_ARRAY */ { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_DATAVIEW */ -#ifdef CONFIG_BIGNUM { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_INT */ +#ifdef CONFIG_BIGNUM { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */ { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */ { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */ @@ -1519,7 +1534,6 @@ static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, return 0; } -#ifdef CONFIG_BIGNUM static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx) { return JS_ThrowTypeError(ctx, "unsupported operation"); @@ -1575,8 +1589,6 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops) ops->mul_pow10 = invalid_mul_pow10; } -#endif /* CONFIG_BIGNUM */ - #if !defined(CONFIG_STACK_CHECK) /* no stack limitation */ static inline uintptr_t js_get_stack_pointer(void) @@ -1589,7 +1601,6 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) return FALSE; } #else -uintptr_t s_stack_peak = 4*1024*1024; /* Note: OS and CPU dependent */ static inline uintptr_t js_get_stack_pointer(void) { @@ -1599,18 +1610,9 @@ static inline uintptr_t js_get_stack_pointer(void) static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size) { uintptr_t sp; - uintptr_t stack = js_get_stack_pointer(); - if (stack < s_stack_peak) { - s_stack_peak = stack; - } - sp = stack - alloca_size; + sp = js_get_stack_pointer() - alloca_size; return unlikely(sp < rt->stack_limit); } - -uintptr_t JS_GetStackPeak() { - return s_stack_peak; -} - #endif JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) @@ -1634,9 +1636,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) rt->malloc_state = ms; rt->malloc_gc_threshold = 256 * 1024; -#ifdef CONFIG_BIGNUM bf_context_init(&rt->bf_ctx, js_bf_realloc, rt); set_dummy_numeric_ops(&rt->bigint_ops); +#ifdef CONFIG_BIGNUM set_dummy_numeric_ops(&rt->bigfloat_ops); set_dummy_numeric_ops(&rt->bigdecimal_ops); #endif @@ -1691,9 +1693,20 @@ void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque) } /* default memory allocation functions with memory limitation */ -static inline size_t js_def_malloc_usable_size(void *ptr) +static size_t js_def_malloc_usable_size(const void *ptr) { +#if defined(__APPLE__) + return malloc_size(ptr); +#elif defined(_WIN32) + return _msize((void *)ptr); +#elif defined(EMSCRIPTEN) return 0; +#elif defined(__linux__) + return malloc_usable_size((void *)ptr); +#else + /* change this to `return 0;` if compilation fails */ + return malloc_usable_size((void *)ptr); +#endif } static void *js_def_malloc(JSMallocState *s, size_t size) @@ -1756,18 +1769,7 @@ static const JSMallocFunctions def_malloc_funcs = { js_def_malloc, js_def_free, js_def_realloc, -#if defined(__APPLE__) - malloc_size, -#elif defined(_WIN32) - (size_t (*)(const void *))_msize, -#elif defined(EMSCRIPTEN) - NULL, -#elif defined(__linux__) - (size_t (*)(const void *))malloc_usable_size, -#else - /* change this to `NULL,` if compilation fails */ - NULL, -#endif + js_def_malloc_usable_size, }; JSRuntime *JS_NewRuntime(void) @@ -1997,9 +1999,7 @@ void JS_FreeRuntime(JSRuntime *rt) } js_free_rt(rt, rt->class_array); -#ifdef CONFIG_BIGNUM bf_context_end(&rt->bf_ctx); -#endif #ifdef DUMP_LEAKS /* only the atoms defined in JS_InitAtoms() should be left */ @@ -2137,8 +2137,8 @@ JSContext *JS_NewContextRaw(JSRuntime *rt) } ctx->rt = rt; list_add_tail(&ctx->link, &rt->context_list); -#ifdef CONFIG_BIGNUM ctx->bf_ctx = &rt->bf_ctx; +#ifdef CONFIG_BIGNUM ctx->fp_env.prec = 113; ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL; #endif @@ -2171,9 +2171,7 @@ JSContext *JS_NewContext(JSRuntime *rt) JS_AddIntrinsicMapSet(ctx); JS_AddIntrinsicTypedArrays(ctx); JS_AddIntrinsicPromise(ctx); -#ifdef CONFIG_BIGNUM JS_AddIntrinsicBigInt(ctx); -#endif return ctx; } @@ -2214,7 +2212,6 @@ JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id) typedef enum JSFreeModuleEnum { JS_FREE_MODULE_ALL, JS_FREE_MODULE_NOT_RESOLVED, - JS_FREE_MODULE_NOT_EVALUATED, } JSFreeModuleEnum; /* XXX: would be more efficient with separate module lists */ @@ -2224,8 +2221,7 @@ static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag) list_for_each_safe(el, el1, &ctx->loaded_modules) { JSModuleDef *m = list_entry(el, JSModuleDef, link); if (flag == JS_FREE_MODULE_ALL || - (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) || - (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) { + (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) { js_free_module_def(ctx, m); } } @@ -2381,6 +2377,11 @@ static inline BOOL is_math_mode(JSContext *ctx) JSStackFrame *sf = ctx->rt->current_stack_frame; return (sf && (sf->js_mode & JS_MODE_MATH)); } +#else +static inline BOOL is_math_mode(JSContext *ctx) +{ + return FALSE; +} #endif /* JSAtom support */ @@ -3375,16 +3376,25 @@ static inline BOOL JS_IsEmptyString(JSValueConst v) /* JSClass support */ +#ifdef CONFIG_ATOMICS +static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + /* a new class ID is allocated if *pclass_id != 0 */ JSClassID JS_NewClassID(JSClassID *pclass_id) { JSClassID class_id; - /* XXX: make it thread safe */ +#ifdef CONFIG_ATOMICS + pthread_mutex_lock(&js_class_id_mutex); +#endif class_id = *pclass_id; if (class_id == 0) { class_id = js_class_id_alloc++; *pclass_id = class_id; } +#ifdef CONFIG_ATOMICS + pthread_mutex_unlock(&js_class_id_mutex); +#endif return class_id; } @@ -4080,7 +4090,7 @@ void JS_FreeCString(JSContext *ctx, const char *ptr) if (!ptr) return; /* purposely removing constness */ - p = (JSString *)(void *)(ptr - offsetof(JSString, u)); + p = container_of(ptr, JSString, u); JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p)); } @@ -4459,6 +4469,7 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, JSShapeProperty *pr; void *sh_alloc; intptr_t h; + JSShape *old_sh; sh = *psh; new_size = max_int(count, sh->prop_size * 3 / 2); @@ -4474,19 +4485,21 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, new_hash_size = sh->prop_hash_mask + 1; while (new_hash_size < new_size) new_hash_size = 2 * new_hash_size; + /* resize the property shapes. Using js_realloc() is not possible in + case the GC runs during the allocation */ + old_sh = sh; + sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); + if (!sh_alloc) + return -1; + sh = get_shape_from_alloc(sh_alloc, new_hash_size); + list_del(&old_sh->header.link); + /* copy all the shape properties */ + memcpy(sh, old_sh, + sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); + list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + if (new_hash_size != (sh->prop_hash_mask + 1)) { - JSShape *old_sh; /* resize the hash table and the properties */ - old_sh = sh; - sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size)); - if (!sh_alloc) - return -1; - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_del(&old_sh->header.link); - /* copy all the fields and the properties */ - memcpy(sh, old_sh, - sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); new_hash_mask = new_hash_size - 1; sh->prop_hash_mask = new_hash_mask; memset(prop_hash_end(sh) - new_hash_size, 0, @@ -4498,20 +4511,12 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, prop_hash_end(sh)[-h - 1] = i + 1; } } - js_free(ctx, get_alloc_from_shape(old_sh)); } else { - /* only resize the properties */ - list_del(&sh->header.link); - sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh), - get_shape_size(new_hash_size, new_size)); - if (unlikely(!sh_alloc)) { - /* insert again in the GC list */ - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); - return -1; - } - sh = get_shape_from_alloc(sh_alloc, new_hash_size); - list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); + /* just copy the previous hash table */ + memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size, + sizeof(prop_hash_end(sh)[0]) * new_hash_size); } + js_free(ctx, get_alloc_from_shape(old_sh)); *psh = sh; sh->prop_size = new_size; return 0; @@ -4788,10 +4793,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: p->is_exotic = 1; @@ -4808,8 +4811,8 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -4871,8 +4874,8 @@ static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj) case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -4895,8 +4898,8 @@ static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val) case JS_CLASS_BOOLEAN: case JS_CLASS_SYMBOL: case JS_CLASS_DATE: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -5243,10 +5246,12 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref) if (--var_ref->header.ref_count == 0) { if (var_ref->is_detached) { JS_FreeValueRT(rt, var_ref->value); - remove_gc_object(&var_ref->header); } else { - list_del(&var_ref->header.link); /* still on the stack */ + list_del(&var_ref->var_ref_link); /* still on the stack */ + if (var_ref->async_func) + async_func_free(rt, var_ref->async_func); } + remove_gc_object(&var_ref->header); js_free_rt(rt, var_ref); } } @@ -5344,7 +5349,7 @@ static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val, if (var_refs) { for(i = 0; i < b->closure_var_count; i++) { JSVarRef *var_ref = var_refs[i]; - if (var_ref && var_ref->is_detached) { + if (var_ref) { mark_func(rt, &var_ref->header); } } @@ -5386,7 +5391,15 @@ static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSForInIterator *it = p->u.for_in_iterator; + int i; + JS_FreeValueRT(rt, it->obj); + if (!it->is_array) { + for(i = 0; i < it->atom_count; i++) { + JS_FreeAtomRT(rt, it->tab_atom[i].atom); + } + js_free_rt(rt, it->tab_atom); + } js_free_rt(rt, it); } @@ -5454,6 +5467,9 @@ static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp) case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: free_function_bytecode(rt, (JSFunctionBytecode *)gp); break; + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: + __async_func_free(rt, (JSAsyncFunctionState *)gp); + break; default: abort(); } @@ -5523,15 +5539,17 @@ void __JS_FreeValueRT(JSRuntime *rt, JSValue v) case JS_TAG_MODULE: abort(); /* never freed here */ break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *bf = JS_VALUE_GET_PTR(v); bf_delete(&bf->num); js_free_rt(rt, bf); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *bf = JS_VALUE_GET_PTR(v); @@ -5610,11 +5628,9 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, if (pr->u.getset.setter) mark_func(rt, &pr->u.getset.setter->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { - if (pr->u.var_ref->is_detached) { - /* Note: the tag does not matter - provided it is a GC object */ - mark_func(rt, &pr->u.var_ref->header); - } + /* Note: the tag does not matter + provided it is a GC object */ + mark_func(rt, &pr->u.var_ref->header); } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) { js_autoinit_mark(rt, pr, mark_func); } @@ -5648,16 +5664,32 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_VAR_REF: { JSVarRef *var_ref = (JSVarRef *)gp; - /* only detached variable referenced are taken into account */ - assert(var_ref->is_detached); - JS_MarkValue(rt, *var_ref->pvalue, mark_func); + if (var_ref->is_detached) { + JS_MarkValue(rt, *var_ref->pvalue, mark_func); + } else if (var_ref->async_func) { + mark_func(rt, &var_ref->async_func->header); + } } break; case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: { - JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp; - if (s->is_active) - async_func_mark(rt, &s->func_state, mark_func); + JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp; + JSStackFrame *sf = &s->frame; + JSValue *sp; + + if (!s->is_completed) { + JS_MarkValue(rt, sf->cur_func, mark_func); + JS_MarkValue(rt, s->this_val, mark_func); + /* sf->cur_sp = NULL if the function is running */ + if (sf->cur_sp) { + /* if the function is running, cur_sp is not known so we + cannot mark the stack. Marking the variables is not needed + because a running function cannot be part of a removable + cycle */ + for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) + JS_MarkValue(rt, *sp, mark_func); + } + } JS_MarkValue(rt, s->resolving_funcs[0], mark_func); JS_MarkValue(rt, s->resolving_funcs[1], mark_func); } @@ -5765,12 +5797,13 @@ static void gc_free_cycles(JSRuntime *rt) if (el == &rt->tmp_obj_list) break; p = list_entry(el, JSGCObjectHeader, link); - /* Only need to free the GC object associated with JS - values. The rest will be automatically removed because they - must be referenced by them. */ + /* Only need to free the GC object associated with JS values + or async functions. The rest will be automatically removed + because they must be referenced by them. */ switch(p->gc_obj_type) { case JS_GC_OBJ_TYPE_JS_OBJECT: case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: + case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: #ifdef DUMP_GC_FREE if (!header_done) { printf("Freeing cycles:\n"); @@ -5792,7 +5825,8 @@ static void gc_free_cycles(JSRuntime *rt) list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) { p = list_entry(el, JSGCObjectHeader, link); assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || - p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); + p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE || + p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION); js_free_rt(rt, p); } @@ -5894,13 +5928,13 @@ static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp) case JS_TAG_STRING: compute_jsstring_size(JS_VALUE_GET_STRING(val), hp); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: case JS_TAG_BIG_DECIMAL: +#endif /* should track JSBigFloat usage */ break; -#endif } } @@ -6024,8 +6058,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_BOOLEAN: /* u.object_data */ case JS_CLASS_SYMBOL: /* u.object_data */ case JS_CLASS_DATE: /* u.object_data */ -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: /* u.object_data */ +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: /* u.object_data */ case JS_CLASS_BIG_DECIMAL: /* u.object_data */ #endif @@ -6117,10 +6151,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) case JS_CLASS_UINT16_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_INT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_UINT32_ARRAY: /* u.typed_array / u.array */ -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_BIG_UINT64_ARRAY: /* u.typed_array / u.array */ -#endif case JS_CLASS_FLOAT32_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_FLOAT64_ARRAY: /* u.typed_array / u.array */ case JS_CLASS_DATAVIEW: /* u.typed_array */ @@ -6247,10 +6279,10 @@ void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt) if (obj_classes[0]) fprintf(fp, " %5d %2.0d %s\n", obj_classes[0], 0, "none"); for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) { - if (obj_classes[class_id]) { + if (obj_classes[class_id] && class_id < rt->class_count) { char buf[ATOM_GET_STR_BUF_SIZE]; fprintf(fp, " %5d %2.0d %s\n", obj_classes[class_id], class_id, - JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name)); + JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name)); } } if (obj_classes[JS_CLASS_INIT_COUNT]) @@ -6881,10 +6913,10 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val) { switch(JS_VALUE_GET_NORM_TAG(val)) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: val = ctx->class_proto[JS_CLASS_BIG_INT]; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: val = ctx->class_proto[JS_CLASS_BIG_FLOAT]; break; @@ -7319,6 +7351,8 @@ static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj, return 0; } +/* add a private brand field to 'home_obj' if not already present and + if obj is != null add a private brand to it */ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) { JSObject *p, *p1; @@ -7334,10 +7368,10 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) p = JS_VALUE_GET_OBJ(home_obj); prs = find_own_property(&pr, p, JS_ATOM_Private_brand); if (!prs) { + /* if the brand is not present, add it */ brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE); if (JS_IsException(brand)) return -1; - /* if the brand is not present, add it */ pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E); if (!pr) { JS_FreeValue(ctx, brand); @@ -7349,20 +7383,27 @@ static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj) } brand_atom = js_symbol_to_atom(ctx, brand); - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { - JS_ThrowTypeErrorNotAnObject(ctx); + if (JS_IsObject(obj)) { + p1 = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p1, brand_atom); + if (unlikely(prs)) { + JS_FreeAtom(ctx, brand_atom); + JS_ThrowTypeError(ctx, "private method is already present"); + return -1; + } + pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); + JS_FreeAtom(ctx, brand_atom); + if (!pr) + return -1; + pr->u.value = JS_UNDEFINED; + } else { JS_FreeAtom(ctx, brand_atom); - return -1; } - p1 = JS_VALUE_GET_OBJ(obj); - pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E); - JS_FreeAtom(ctx, brand_atom); - if (!pr) - return -1; - pr->u.value = JS_UNDEFINED; return 0; } +/* return a boolean telling if the brand of the home object of 'func' + is present on 'obj' or -1 in case of exception */ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) { JSObject *p, *p1, *home_obj; @@ -7371,11 +7412,8 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) JSValueConst brand; /* get the home object of 'func' */ - if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) { - not_obj: - JS_ThrowTypeErrorNotAnObject(ctx); - return -1; - } + if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) + goto not_obj; p1 = JS_VALUE_GET_OBJ(func); if (!js_class_has_bytecode(p1->class_id)) goto not_obj; @@ -7393,15 +7431,14 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func) goto not_obj; /* get the brand array of 'obj' */ - if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) - goto not_obj; - p = JS_VALUE_GET_OBJ(obj); - prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand)); - if (!prs) { - JS_ThrowTypeError(ctx, "invalid brand on object"); + if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) { + not_obj: + JS_ThrowTypeErrorNotAnObject(ctx); return -1; } - return 0; + p = JS_VALUE_GET_OBJ(obj); + prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand)); + return (prs != NULL); } static uint32_t js_string_obj_get_length(JSContext *ctx, @@ -7858,39 +7895,45 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj, if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { JSObject *p; - uint32_t idx, len; + uint32_t idx; /* fast path for array access */ p = JS_VALUE_GET_OBJ(this_obj); idx = JS_VALUE_GET_INT(prop); - len = (uint32_t)p->u.array.count; - if (unlikely(idx >= len)) - goto slow_path; switch(p->class_id) { case JS_CLASS_ARRAY: case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_DupValue(ctx, p->u.array.u.values[idx]); case JS_CLASS_INT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]); case JS_CLASS_UINT8C_ARRAY: case JS_CLASS_UINT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]); case JS_CLASS_INT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]); case JS_CLASS_UINT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]); case JS_CLASS_INT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]); case JS_CLASS_UINT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]); -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); case JS_CLASS_BIG_UINT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); -#endif case JS_CLASS_FLOAT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]); case JS_CLASS_FLOAT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) goto slow_path; return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]); default: goto slow_path; @@ -8308,126 +8351,45 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p, return TRUE; } -static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) +/* Allocate a new fast array. Its 'length' property is set to zero. It + maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit + integer. WARNING: the content of the array is not initialized. */ +static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len) { - JS_FreeValue(ctx, desc->getter); - JS_FreeValue(ctx, desc->setter); - JS_FreeValue(ctx, desc->value); -} - -/* generic (and slower) version of JS_SetProperty() for - * Reflect.set(). 'obj' must be an object. */ -static int JS_SetPropertyGeneric(JSContext *ctx, - JSValueConst obj, JSAtom prop, - JSValue val, JSValueConst this_obj, - int flags) -{ - int ret; - JSPropertyDescriptor desc; - JSValue obj1; + JSValue arr; JSObject *p; - obj1 = JS_DupValue(ctx, obj); - for(;;) { - p = JS_VALUE_GET_OBJ(obj1); - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->set_property) { - ret = em->set_property(ctx, obj1, prop, - val, this_obj, flags); - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } - } - - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JSObject *setter; - if (JS_IsUndefined(desc.setter)) - setter = NULL; - else - setter = JS_VALUE_GET_OBJ(desc.setter); - ret = call_setter(ctx, setter, this_obj, val, flags); - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, obj1); - return ret; - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE)) { - JS_FreeValue(ctx, obj1); - goto read_only_error; - } - } - break; - } - /* Note: at this point 'obj1' cannot be a proxy. XXX: may have - to check recursion */ - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - } - JS_FreeValue(ctx, obj1); - - if (!JS_IsObject(this_obj)) { - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object"); - } - - p = JS_VALUE_GET_OBJ(this_obj); - - /* modify the property in this_obj if it already exists */ - ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); - if (ret < 0) { - JS_FreeValue(ctx, val); - return ret; - } - if (ret) { - if (desc.flags & JS_PROP_GETSET) { - JS_FreeValue(ctx, desc.getter); - JS_FreeValue(ctx, desc.setter); - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); - } else { - JS_FreeValue(ctx, desc.value); - if (!(desc.flags & JS_PROP_WRITABLE) || - p->class_id == JS_CLASS_MODULE_NS) { - read_only_error: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); - } + if (len > INT32_MAX) + return JS_ThrowRangeError(ctx, "invalid array length"); + arr = JS_NewArray(ctx); + if (JS_IsException(arr)) + return arr; + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + if (expand_fast_array(ctx, p, len) < 0) { + JS_FreeValue(ctx, arr); + return JS_EXCEPTION; } - ret = JS_DefineProperty(ctx, this_obj, prop, val, - JS_UNDEFINED, JS_UNDEFINED, - JS_PROP_HAS_VALUE); - JS_FreeValue(ctx, val); - return ret; + p->u.array.count = len; } + return arr; +} - ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, - flags | - JS_PROP_HAS_VALUE | - JS_PROP_HAS_ENUMERABLE | - JS_PROP_HAS_WRITABLE | - JS_PROP_HAS_CONFIGURABLE | - JS_PROP_C_W_E); - JS_FreeValue(ctx, val); - return ret; +static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc) +{ + JS_FreeValue(ctx, desc->getter); + JS_FreeValue(ctx, desc->setter); + JS_FreeValue(ctx, desc->value); } /* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, - the new property is not added and an error is raised. */ -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags) + the new property is not added and an error is raised. 'this_obj' is + the receiver. If obj != this_obj, then obj must be an object + (Reflect.set case). */ +int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValue val, JSValueConst this_obj, int flags) { JSObject *p, *p1; JSShapeProperty *prs; @@ -8440,25 +8402,37 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, #endif tag = JS_VALUE_GET_TAG(this_obj); if (unlikely(tag != JS_TAG_OBJECT)) { - switch(tag) { - case JS_TAG_NULL: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); - return -1; - case JS_TAG_UNDEFINED: - JS_FreeValue(ctx, val); - JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); - return -1; - default: - /* even on a primitive type we can have setters on the prototype */ + if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { p = NULL; - p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj)); + p1 = JS_VALUE_GET_OBJ(obj); goto prototype_lookup; + } else { + switch(tag) { + case JS_TAG_NULL: + JS_FreeValue(ctx, val); + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop); + return -1; + case JS_TAG_UNDEFINED: + JS_FreeValue(ctx, val); + JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop); + return -1; + default: + /* even on a primitive type we can have setters on the prototype */ + p = NULL; + p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj)); + goto prototype_lookup; + } } + } else { + p = JS_VALUE_GET_OBJ(this_obj); + p1 = JS_VALUE_GET_OBJ(obj); + if (unlikely(p != p1)) + goto retry2; } - p = JS_VALUE_GET_OBJ(this_obj); -retry: - prs = find_own_property(&pr, p, prop); + + /* fast path if obj == this_obj */ + retry: + prs = find_own_property(&pr, p1, prop); if (prs) { if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { @@ -8490,8 +8464,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, goto read_only_prop; } } - - p1 = p; + for(;;) { if (p1->is_exotic) { if (p1->fast_array) { @@ -8515,11 +8488,19 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return -1; } typed_array_oob: - val = JS_ToNumberFree(ctx, val); - JS_FreeValue(ctx, val); - if (JS_IsException(val)) - return -1; - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + /* must convert the argument even if out of bound access */ + if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY || + p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) { + int64_t v; + if (JS_ToBigInt64Free(ctx, &v, val)) + return -1; + } else { + val = JS_ToNumberFree(ctx, val); + JS_FreeValue(ctx, val); + if (JS_IsException(val)) + return -1; + } + return TRUE; } } } else { @@ -8591,9 +8572,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return -1; goto retry2; } else if (!(prs->flags & JS_PROP_WRITABLE)) { - read_only_prop: - JS_FreeValue(ctx, val); - return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + goto read_only_prop; } } } @@ -8614,16 +8593,56 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible"); } - if (p->is_exotic) { - if (p->class_id == JS_CLASS_ARRAY && p->fast_array && - __JS_AtomIsTaggedInt(prop)) { - uint32_t idx = __JS_AtomToUInt32(prop); - if (idx == p->u.array.count) { - /* fast case */ - return add_fast_array_element(ctx, p, val, flags); + if (likely(p == JS_VALUE_GET_OBJ(obj))) { + if (p->is_exotic) { + if (p->class_id == JS_CLASS_ARRAY && p->fast_array && + __JS_AtomIsTaggedInt(prop)) { + uint32_t idx = __JS_AtomToUInt32(prop); + if (idx == p->u.array.count) { + /* fast case */ + return add_fast_array_element(ctx, p, val, flags); + } else { + goto generic_create_prop; + } } else { goto generic_create_prop; } + } else { + pr = add_property(ctx, p, prop, JS_PROP_C_W_E); + if (unlikely(!pr)) { + JS_FreeValue(ctx, val); + return -1; + } + pr->u.value = val; + return TRUE; + } + } else { + /* generic case: modify the property in this_obj if it already exists */ + ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop); + if (ret < 0) { + JS_FreeValue(ctx, val); + return ret; + } + if (ret) { + if (desc.flags & JS_PROP_GETSET) { + JS_FreeValue(ctx, desc.getter); + JS_FreeValue(ctx, desc.setter); + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden"); + } else { + JS_FreeValue(ctx, desc.value); + if (!(desc.flags & JS_PROP_WRITABLE) || + p->class_id == JS_CLASS_MODULE_NS) { + read_only_prop: + JS_FreeValue(ctx, val); + return JS_ThrowTypeErrorReadOnly(ctx, flags, prop); + } + } + ret = JS_DefineProperty(ctx, this_obj, prop, val, + JS_UNDEFINED, JS_UNDEFINED, + JS_PROP_HAS_VALUE); + JS_FreeValue(ctx, val); + return ret; } else { generic_create_prop: ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, @@ -8637,14 +8656,6 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return ret; } } - - pr = add_property(ctx, p, prop, JS_PROP_C_W_E); - if (unlikely(!pr)) { - JS_FreeValue(ctx, val); - return -1; - } - pr->u.value = val; - return TRUE; } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ @@ -8729,7 +8740,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, goto ta_out_of_bound; p->u.array.u.uint32_ptr[idx] = v; break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: /* XXX: need specific conversion function */ @@ -8742,7 +8752,6 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, p->u.array.u.uint64_ptr[idx] = v; } break; -#endif case JS_CLASS_FLOAT32_ARRAY: if (JS_ToFloat64Free(ctx, &d, val)) return -1; @@ -8755,7 +8764,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, return -1; if (unlikely(idx >= (uint32_t)p->u.array.count)) { ta_out_of_bound: - return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index"); + return TRUE; } p->u.array.u.double_ptr[idx] = d; break; @@ -8773,7 +8782,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); return -1; } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags); JS_FreeAtom(ctx, atom); return ret; } @@ -8813,7 +8822,7 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW); JS_FreeAtom(ctx, atom); return ret; } @@ -9153,15 +9162,19 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, spaces. */ if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue)) goto not_configurable; + } else { + /* update the reference */ + set_value(ctx, pr->u.var_ref->pvalue, + JS_DupValue(ctx, val)); } - /* update the reference */ - set_value(ctx, pr->u.var_ref->pvalue, - JS_DupValue(ctx, val)); } /* if writable is set to false, no longer a reference (for mapped arguments) */ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) { JSValue val1; + if (p->class_id == JS_CLASS_MODULE_NS) { + return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false"); + } if (js_shape_prepare_update(ctx, p, &prs)) return -1; val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue); @@ -9270,7 +9283,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, } idx = __JS_AtomToUInt32(prop); /* if the typed array is detached, p->u.array.count = 0 */ - if (idx >= typed_array_get_length(ctx, p)) { + if (idx >= p->u.array.count) { typed_array_oob: return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array"); } @@ -9664,7 +9677,7 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, flags = JS_PROP_THROW_STRICT; if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags); } /* return -1, FALSE or TRUE. return FALSE if not configurable or @@ -9941,9 +9954,10 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) JS_FreeValue(ctx, val); return ret; } -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); BOOL ret; @@ -9951,6 +9965,7 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) JS_FreeValue(ctx, val); return ret; } +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: { JSBigDecimal *p = JS_VALUE_GET_PTR(val); @@ -10020,12 +10035,13 @@ static inline int to_digit(int c) } /* XXX: remove */ -static double js_strtod(const char *p, int radix, BOOL is_float) +static double js_strtod(const char *str, int radix, BOOL is_float) { double d; int c; if (!is_float || radix != 10) { + const char *p = str; uint64_t n_max, n; int int_exp, is_neg; @@ -10052,6 +10068,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float) if (n <= n_max) { n = n * radix + c; } else { + if (radix == 10) + goto strtod_case; int_exp++; } p++; @@ -10063,7 +10081,8 @@ static double js_strtod(const char *p, int radix, BOOL is_float) if (is_neg) d = -d; } else { - d = strtod(p, NULL); + strtod_case: + d = strtod(str, NULL); } return d; } @@ -10081,15 +10100,16 @@ static double js_strtod(const char *p, int radix, BOOL is_float) #define ATOD_TYPE_MASK (3 << 7) #define ATOD_TYPE_FLOAT64 (0 << 7) #define ATOD_TYPE_BIG_INT (1 << 7) +#ifdef CONFIG_BIGNUM #define ATOD_TYPE_BIG_FLOAT (2 << 7) #define ATOD_TYPE_BIG_DECIMAL (3 << 7) /* assume bigint mode: floats are parsed as integers if no decimal point nor exponent */ #define ATOD_MODE_BIGINT (1 << 9) +#endif /* accept -0x1 */ #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10) -#ifdef CONFIG_BIGNUM static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { @@ -10105,10 +10125,15 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf, JS_FreeValue(ctx, val); return JS_ThrowOutOfMemory(ctx); } +#ifdef CONFIG_BIGNUM val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0); +#else + val = JS_CompactBigInt1(ctx, val, FALSE); +#endif return val; } +#ifdef CONFIG_BIGNUM static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf, int radix, int flags, slimb_t *pexponent) { @@ -10154,7 +10179,6 @@ static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf, } return val; } - #endif /* return an exception in case of memory error. Return JS_NAN if @@ -10229,8 +10253,11 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, } else { no_radix_prefix: if (!(flags & ATOD_INT_ONLY) && - (atod_type == ATOD_TYPE_FLOAT64 || - atod_type == ATOD_TYPE_BIG_FLOAT) && + (atod_type == ATOD_TYPE_FLOAT64 +#ifdef CONFIG_BIGNUM + || atod_type == ATOD_TYPE_BIG_FLOAT +#endif + ) && strstart(p, "Infinity", &p)) { #ifdef CONFIG_BIGNUM if (atod_type == ATOD_TYPE_BIG_FLOAT) { @@ -10310,36 +10337,40 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, } buf[j] = '\0'; -#ifdef CONFIG_BIGNUM if (flags & ATOD_ACCEPT_SUFFIX) { if (*p == 'n') { p++; atod_type = ATOD_TYPE_BIG_INT; - } else if (*p == 'l') { + } else +#ifdef CONFIG_BIGNUM + if (*p == 'l') { p++; atod_type = ATOD_TYPE_BIG_FLOAT; } else if (*p == 'm') { p++; atod_type = ATOD_TYPE_BIG_DECIMAL; - } else { - if (flags & ATOD_MODE_BIGINT) { - if (!is_float) - atod_type = ATOD_TYPE_BIG_INT; - if (has_legacy_octal) - goto fail; - } else { - if (is_float && radix != 10) - goto fail; - } + } else if (flags & ATOD_MODE_BIGINT) { + if (!is_float) + atod_type = ATOD_TYPE_BIG_INT; + if (has_legacy_octal) + goto fail; + } else +#endif + { + if (is_float && radix != 10) + goto fail; } } else { if (atod_type == ATOD_TYPE_FLOAT64) { +#ifdef CONFIG_BIGNUM if (flags & ATOD_MODE_BIGINT) { if (!is_float) atod_type = ATOD_TYPE_BIG_INT; if (has_legacy_octal) goto fail; - } else { + } else +#endif + { if (is_float && radix != 10) goto fail; } @@ -10360,6 +10391,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, goto fail; val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL); break; +#ifdef CONFIG_BIGNUM case ATOD_TYPE_BIG_FLOAT: if (has_legacy_octal) goto fail; @@ -10371,19 +10403,10 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, goto fail; val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL); break; +#endif default: abort(); } -#else - { - double d; - (void)has_legacy_octal; - if (is_float && radix != 10) - goto fail; - d = js_strtod(buf, radix, is_float); - val = JS_NewFloat64(ctx, d); - } -#endif done: if (buf_allocated) @@ -10421,18 +10444,18 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val, redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { -#ifdef CONFIG_BIGNUM - case JS_TAG_BIG_DECIMAL: + case JS_TAG_BIG_INT: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); + return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); } ret = val; break; - case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_DECIMAL: if (flag != TON_FLAG_NUMERIC) { JS_FreeValue(ctx, val); - return JS_ThrowTypeError(ctx, "cannot convert bigint to number"); + return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number"); } ret = val; break; @@ -10534,9 +10557,10 @@ static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, case JS_TAG_FLOAT64: d = JS_VALUE_GET_FLOAT64(val); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* XXX: there can be a double rounding issue with some @@ -10546,7 +10570,6 @@ static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres, JS_FreeValue(ctx, val); } break; -#endif default: abort(); } @@ -10614,6 +10637,10 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val) BOOL is_nan; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } if (!bf_is_finite(a)) { is_nan = bf_is_nan(a); if (is_nan) @@ -11014,9 +11041,10 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, len = v; } break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); bf_t a; @@ -11031,7 +11059,6 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen, goto fail; } break; -#endif default: if (JS_TAG_IS_FLOAT64(tag)) { double d; @@ -11135,13 +11162,13 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) u.d = JS_VALUE_GET_FLOAT64(val); return (u.u64 >> 63); } -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); /* Note: integer zeros are not necessarily positive */ return p->num.sign && !bf_is_zero(&p->num); } +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11160,8 +11187,6 @@ static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val) } } -#ifdef CONFIG_BIGNUM - static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix) { JSValue ret; @@ -11191,6 +11216,8 @@ static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val) return js_bigint_to_string1(ctx, val, 10); } +#ifdef CONFIG_BIGNUM + static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, limb_t prec, bf_flags_t flags) { @@ -11203,6 +11230,10 @@ static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix, if (JS_IsException(val)) return val; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; @@ -11259,6 +11290,8 @@ static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val, int saved_sign; a = JS_ToBigDecimal(ctx, val); + if (!a) + return JS_EXCEPTION; saved_sign = a->sign; if (a->expn == BF_EXP_ZERO) a->sign = 0; @@ -11591,9 +11624,9 @@ JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToProperty case JS_TAG_FLOAT64: return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, JS_DTOA_VAR_FORMAT); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: return ctx->rt->bigint_ops.to_string(ctx, val); +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: return ctx->rt->bigfloat_ops.to_string(ctx, val); case JS_TAG_BIG_DECIMAL: @@ -11754,10 +11787,8 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) case JS_CLASS_UINT16_ARRAY: case JS_CLASS_INT32_ARRAY: case JS_CLASS_UINT32_ARRAY: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT32_ARRAY: case JS_CLASS_FLOAT64_ARRAY: { @@ -11884,7 +11915,6 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, case JS_TAG_FLOAT64: printf("%.14g", JS_VALUE_GET_FLOAT64(val)); break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11895,6 +11925,7 @@ static __maybe_unused void JS_DumpValueShort(JSRuntime *rt, bf_realloc(&rt->bf_ctx, str, 0); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p = JS_VALUE_GET_PTR(val); @@ -11996,8 +12027,6 @@ static double js_pow(double a, double b) } } -#ifdef CONFIG_BIGNUM - JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v) { JSValue val; @@ -12042,70 +12071,6 @@ JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) return val; } -/* if the returned bigfloat is allocated it is equal to - 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return - NULL in case of error. */ -static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) -{ - uint32_t tag; - bf_t *r; - JSBigFloat *p; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_BOOL: - case JS_TAG_NULL: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_si(r, JS_VALUE_GET_INT(val))) - goto fail; - break; - case JS_TAG_FLOAT64: - r = buf; - bf_init(ctx->bf_ctx, r); - if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { - fail: - bf_delete(r); - return NULL; - } - break; - case JS_TAG_BIG_INT: - case JS_TAG_BIG_FLOAT: - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - case JS_TAG_UNDEFINED: - default: - r = buf; - bf_init(ctx->bf_ctx, r); - bf_set_nan(r); - break; - } - return r; -} - -/* return NULL if invalid type */ -static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) -{ - uint32_t tag; - JSBigDecimal *p; - bfdec_t *r; - - tag = JS_VALUE_GET_NORM_TAG(val); - switch(tag) { - case JS_TAG_BIG_DECIMAL: - p = JS_VALUE_GET_PTR(val); - r = &p->num; - break; - default: - JS_ThrowTypeError(ctx, "bigdecimal expected"); - r = NULL; - break; - } - return r; -} - /* return NaN if bad bigint literal */ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) { @@ -12123,8 +12088,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val) val = JS_NewBigInt64(ctx, 0); } else { flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT; +#ifdef CONFIG_BIGNUM if (is_math_mode(ctx)) flags |= ATOD_MODE_BIGINT; +#endif val = js_atof(ctx, p, &p, 0, flags); p += skip_spaces(p); if (!JS_IsException(val)) { @@ -12185,6 +12152,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) p = JS_VALUE_GET_PTR(val); r = &p->num; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (!is_math_mode(ctx)) goto fail; @@ -12197,6 +12165,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val) bf_rint(r, BF_RNDZ); JS_FreeValue(ctx, val); break; +#endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); if (JS_IsException(val)) @@ -12257,7 +12226,7 @@ static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf) } else { JSBigFloat *p = (JSBigFloat *)((uint8_t *)a - offsetof(JSBigFloat, num)); - JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p)); + JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_INT, p)); } } @@ -12292,6 +12261,129 @@ static JSBigFloat *js_new_bf(JSContext *ctx) return p; } +static JSValue JS_NewBigInt(JSContext *ctx) +{ + JSBigFloat *p; + p = js_malloc(ctx, sizeof(*p)); + if (!p) + return JS_EXCEPTION; + p->header.ref_count = 1; + bf_init(ctx->bf_ctx, &p->num); + return JS_MKPTR(JS_TAG_BIG_INT, p); +} + +static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, + BOOL convert_to_safe_integer) +{ + int64_t v; + bf_t *a; + + if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) + return val; /* fail safe */ + a = JS_GetBigInt(val); + if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && + v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { + JS_FreeValue(ctx, val); + return JS_NewInt64(ctx, v); + } else if (a->expn == BF_EXP_ZERO && a->sign) { + JSBigFloat *p = JS_VALUE_GET_PTR(val); + assert(p->header.ref_count == 1); + a->sign = 0; + } + return val; +} + +/* Convert the big int to a safe integer if in math mode. normalize + the zero representation. Could also be used to convert the bigint + to a short bigint value. The reference count of the value must be + 1. Cannot fail */ +static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) +{ + return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); +} + +static JSValue throw_bf_exception(JSContext *ctx, int status) +{ + const char *str; + if (status & BF_ST_MEM_ERROR) + return JS_ThrowOutOfMemory(ctx); + if (status & BF_ST_DIVIDE_ZERO) { + str = "division by zero"; + } else if (status & BF_ST_INVALID_OP) { + str = "invalid operation"; + } else { + str = "integer overflow"; + } + return JS_ThrowRangeError(ctx, "%s", str); +} + +/* if the returned bigfloat is allocated it is equal to + 'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return + NULL in case of error. */ +static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val) +{ + uint32_t tag; + bf_t *r; + JSBigFloat *p; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_INT: + case JS_TAG_BOOL: + case JS_TAG_NULL: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_si(r, JS_VALUE_GET_INT(val))) + goto fail; + break; + case JS_TAG_FLOAT64: + r = buf; + bf_init(ctx->bf_ctx, r); + if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) { + fail: + bf_delete(r); + return NULL; + } + break; + case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM + case JS_TAG_BIG_FLOAT: +#endif + p = JS_VALUE_GET_PTR(val); + r = &p->num; + break; + case JS_TAG_UNDEFINED: + default: + r = buf; + bf_init(ctx->bf_ctx, r); + bf_set_nan(r); + break; + } + return r; +} + +#ifdef CONFIG_BIGNUM +/* return NULL if invalid type */ +static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val) +{ + uint32_t tag; + JSBigDecimal *p; + bfdec_t *r; + + tag = JS_VALUE_GET_NORM_TAG(val); + switch(tag) { + case JS_TAG_BIG_DECIMAL: + p = JS_VALUE_GET_PTR(val); + r = &p->num; + break; + default: + JS_ThrowTypeError(ctx, "bigdecimal expected"); + r = NULL; + break; + } + return r; +} + static JSValue JS_NewBigFloat(JSContext *ctx) { JSBigFloat *p; @@ -12314,47 +12406,6 @@ static JSValue JS_NewBigDecimal(JSContext *ctx) return JS_MKPTR(JS_TAG_BIG_DECIMAL, p); } -static JSValue JS_NewBigInt(JSContext *ctx) -{ - JSBigFloat *p; - p = js_malloc(ctx, sizeof(*p)); - if (!p) - return JS_EXCEPTION; - p->header.ref_count = 1; - bf_init(ctx->bf_ctx, &p->num); - return JS_MKPTR(JS_TAG_BIG_INT, p); -} - -static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val, - BOOL convert_to_safe_integer) -{ - int64_t v; - bf_t *a; - - if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT) - return val; /* fail safe */ - a = JS_GetBigInt(val); - if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 && - v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) { - JS_FreeValue(ctx, val); - return JS_NewInt64(ctx, v); - } else if (a->expn == BF_EXP_ZERO && a->sign) { - JSBigFloat *p = JS_VALUE_GET_PTR(val); - assert(p->header.ref_count == 1); - a->sign = 0; - } - return val; -} - -/* Convert the big int to a safe integer if in math mode. normalize - the zero representation. Could also be used to convert the bigint - to a short bigint value. The reference count of the value must be - 1. Cannot fail */ -static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val) -{ - return JS_CompactBigInt1(ctx, val, is_math_mode(ctx)); -} - /* must be kept in sync with JSOverloadableOperatorEnum */ /* XXX: use atoms ? */ static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = { @@ -12678,46 +12729,37 @@ static __exception int js_call_unary_op_fallback(JSContext *ctx, return -1; } -static JSValue throw_bf_exception(JSContext *ctx, int status) -{ - const char *str; - if (status & BF_ST_MEM_ERROR) - return JS_ThrowOutOfMemory(ctx); - if (status & BF_ST_DIVIDE_ZERO) { - str = "division by zero"; - } else if (status & BF_ST_INVALID_OP) { - str = "invalid operation"; - } else { - str = "integer overflow"; - } - return JS_ThrowRangeError(ctx, "%s", str); -} - -static int js_unary_arith_bigint(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +static int js_unary_arith_bigfloat(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigint argument with unary +"); + JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - res = JS_NewBigInt(ctx); + + res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigInt(res); - a = JS_ToBigInt(ctx, &a_s, op1); + r = JS_GetBigFloat(res); + a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); + ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); break; case OP_plus: ret = bf_set(r, a); @@ -12726,66 +12768,65 @@ static int js_unary_arith_bigint(JSContext *ctx, ret = bf_set(r, a); bf_neg(r); break; - case OP_not: - ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ); - bf_neg(r); - break; default: abort(); } - JS_FreeBigInt(ctx, a, &a_s); + if (a == &a_s) + bf_delete(a); JS_FreeValue(ctx, op1); - if (unlikely(ret)) { + if (unlikely(ret & BF_ST_MEM_ERROR)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } - res = JS_CompactBigInt(ctx, res); *pres = res; return 0; } -static int js_unary_arith_bigfloat(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +static int js_unary_arith_bigdecimal(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { - bf_t a_s, *r, *a; + bfdec_t *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigfloat argument with unary +"); + JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - res = JS_NewBigFloat(ctx); + res = JS_NewBigDecimal(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); + r = JS_GetBigDecimal(res); + a = JS_ToBigDecimal(ctx, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags); + ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: - ret = bf_set(r, a); + ret = bfdec_set(r, a); break; case OP_neg: - ret = bf_set(r, a); - bf_neg(r); + ret = bfdec_set(r, a); + bfdec_neg(r); break; default: abort(); } - if (a == &a_s) - bf_delete(a); JS_FreeValue(ctx, op1); - if (unlikely(ret & BF_ST_MEM_ERROR)) { + if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; @@ -12794,49 +12835,61 @@ static int js_unary_arith_bigfloat(JSContext *ctx, return 0; } -static int js_unary_arith_bigdecimal(JSContext *ctx, - JSValue *pres, OPCodeEnum op, JSValue op1) +#endif /* CONFIG_BIGNUM */ + +static int js_unary_arith_bigint(JSContext *ctx, + JSValue *pres, OPCodeEnum op, JSValue op1) { - bfdec_t *r, *a; + bf_t a_s, *r, *a; int ret, v; JSValue res; if (op == OP_plus && !is_math_mode(ctx)) { - JS_ThrowTypeError(ctx, "bigdecimal argument with unary +"); + JS_ThrowTypeError(ctx, "bigint argument with unary +"); JS_FreeValue(ctx, op1); return -1; } - - res = JS_NewBigDecimal(ctx); + res = JS_NewBigInt(ctx); if (JS_IsException(res)) { JS_FreeValue(ctx, op1); return -1; } - r = JS_GetBigDecimal(res); - a = JS_ToBigDecimal(ctx, op1); + r = JS_GetBigInt(res); + a = JS_ToBigInt(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + JS_FreeValue(ctx, op1); + return -1; + } ret = 0; switch(op) { case OP_inc: case OP_dec: v = 2 * (op - OP_dec) - 1; - ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); + ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ); break; case OP_plus: - ret = bfdec_set(r, a); + ret = bf_set(r, a); break; case OP_neg: - ret = bfdec_set(r, a); - bfdec_neg(r); + ret = bf_set(r, a); + bf_neg(r); + break; + case OP_not: + ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ); + bf_neg(r); break; default: abort(); } + JS_FreeBigInt(ctx, a, &a_s); JS_FreeValue(ctx, op1); if (unlikely(ret)) { JS_FreeValue(ctx, res); throw_bf_exception(ctx, ret); return -1; } + res = JS_CompactBigInt(ctx, res); *pres = res; return 0; } @@ -12845,16 +12898,18 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, val; - int v, ret; + JSValue op1; + int v; uint32_t tag; op1 = sp[-1]; /* fast path for float64 */ if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) goto handle_float64; +#ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { - ret = js_call_unary_op_fallback(ctx, &val, op1, op); + JSValue val; + int ret = js_call_unary_op_fallback(ctx, &val, op1, op); if (ret < 0) return -1; if (ret) { @@ -12863,7 +12918,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, return 0; } } - +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; @@ -12900,6 +12955,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; @@ -12908,6 +12964,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx, if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1)) goto exception; break; +#endif default: handle_float64: { @@ -12958,12 +13015,13 @@ static __exception int js_post_inc_slow(JSContext *ctx, static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) { - JSValue op1, val; - int ret; + JSValue op1; op1 = sp[-1]; +#ifdef CONFIG_BIGNUM if (JS_IsObject(op1)) { - ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); + JSValue val; + int ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not); if (ret < 0) return -1; if (ret) { @@ -12972,7 +13030,7 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) return 0; } } - +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) goto exception; @@ -12991,67 +13049,6 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) return -1; } -static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, - JSValue *pres, JSValue op1, JSValue op2) -{ - bf_t a_s, b_s, *r, *a, *b; - int ret; - JSValue res; - - res = JS_NewBigFloat(ctx); - if (JS_IsException(res)) { - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - return -1; - } - r = JS_GetBigFloat(res); - a = JS_ToBigFloat(ctx, &a_s, op1); - b = JS_ToBigFloat(ctx, &b_s, op2); - bf_init(ctx->bf_ctx, r); - switch(op) { - case OP_add: - ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_sub: - ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_mul: - ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_div: - ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); - break; - case OP_math_mod: - /* Euclidian remainder */ - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_DIVREM_EUCLIDIAN); - break; - case OP_mod: - ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, - BF_RNDZ); - break; - case OP_pow: - ret = bf_pow(r, a, b, ctx->fp_env.prec, - ctx->fp_env.flags | BF_POW_JS_QUIRKS); - break; - default: - abort(); - } - if (a == &a_s) - bf_delete(a); - if (b == &b_s) - bf_delete(b); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - if (unlikely(ret & BF_ST_MEM_ERROR)) { - JS_FreeValue(ctx, res); - throw_bf_exception(ctx, ret); - return -1; - } - *pres = res; - return 0; -} - static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, JSValue *pres, JSValue op1, JSValue op2) { @@ -13093,11 +13090,13 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, goto math_mode_div_pow; } break; +#ifdef CONFIG_BIGNUM case OP_math_mod: /* Euclidian remainder */ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP; break; +#endif case OP_mod: ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ) & BF_ST_INVALID_OP; @@ -13108,6 +13107,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, ret = BF_ST_INVALID_OP; } else { math_mode_div_pow: +#ifdef CONFIG_BIGNUM JS_FreeValue(ctx, res); ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op); if (ret != 0) { @@ -13148,6 +13148,9 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, } *pres = res; return 0; +#else + abort(); +#endif } } else { ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS); @@ -13207,6 +13210,79 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op, return -1; } +#ifdef CONFIG_BIGNUM +static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op, + JSValue *pres, JSValue op1, JSValue op2) +{ + bf_t a_s, b_s, *r, *a, *b; + int ret; + JSValue res; + + res = JS_NewBigFloat(ctx); + if (JS_IsException(res)) + goto fail; + r = JS_GetBigFloat(res); + a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, res); + goto fail; + } + b = JS_ToBigFloat(ctx, &b_s, op2); + if (!b) { + if (a == &a_s) + bf_delete(a); + JS_FreeValue(ctx, res); + goto fail; + } + bf_init(ctx->bf_ctx, r); + switch(op) { + case OP_add: + ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_sub: + ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_mul: + ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_div: + ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags); + break; + case OP_math_mod: + /* Euclidian remainder */ + ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, + BF_DIVREM_EUCLIDIAN); + break; + case OP_mod: + ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags, + BF_RNDZ); + break; + case OP_pow: + ret = bf_pow(r, a, b, ctx->fp_env.prec, + ctx->fp_env.flags | BF_POW_JS_QUIRKS); + break; + default: + abort(); + } + if (a == &a_s) + bf_delete(a); + if (b == &b_s) + bf_delete(b); + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + if (unlikely(ret & BF_ST_MEM_ERROR)) { + JS_FreeValue(ctx, res); + throw_bf_exception(ctx, ret); + return -1; + } + *pres = res; + return 0; + fail: + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + return -1; +} + /* b must be a positive integer */ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b) { @@ -13293,13 +13369,13 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op2); return -1; } +#endif /* CONFIG_BIGNUM */ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, res; + JSValue op1, op2; uint32_t tag1, tag2; - int ret; double d1, d2; op1 = sp[-2]; @@ -13313,12 +13389,14 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s goto handle_float64; } +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13330,6 +13408,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s } } } +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { @@ -13368,6 +13447,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s goto handle_bigint; sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2); return 0; +#ifdef CONFIG_BIGNUM case OP_math_mod: if (unlikely(v2 == 0)) { throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO); @@ -13381,6 +13461,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s v += v2; } break; +#endif case OP_mod: if (v1 < 0 || v2 <= 0) { sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2)); @@ -13401,13 +13482,17 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s abort(); } sp[-2] = JS_NewInt64(ctx, v); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2)) goto exception; @@ -13436,6 +13521,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s case OP_mod: dr = fmod(d1, d2); break; +#ifdef CONFIG_BIGNUM case OP_math_mod: d2 = fabs(d2); dr = fmod(d1, d2); @@ -13443,6 +13529,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s if (dr < 0) dr += d2; break; +#endif case OP_pow: dr = js_pow(d1, d2); break; @@ -13460,9 +13547,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) { - JSValue op1, op2, res; + JSValue op1, op2; uint32_t tag1, tag2; - int ret; op1 = sp[-2]; op2 = sp[-1]; @@ -13479,6 +13565,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) } if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) { +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED && @@ -13486,8 +13573,9 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED && tag1 != JS_TAG_STRING))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, - FALSE, HINT_NONE); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add, + FALSE, HINT_NONE); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13499,7 +13587,7 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) } } } - +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13542,13 +13630,17 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) v2 = JS_VALUE_GET_INT(op2); v = (int64_t)v1 + (int64_t)v2; sp[-2] = JS_NewInt64(ctx, v); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { handle_bigint: if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2)) goto exception; @@ -13576,8 +13668,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, res; - int ret; + JSValue op1, op2; uint32_t tag1, tag2; uint32_t v1, v2, r; @@ -13586,12 +13677,14 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { - ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); + JSValue res; + int ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0); if (ret != 0) { JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); @@ -13603,6 +13696,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx, } } } +#endif op1 = JS_ToNumericFree(ctx, op1); if (JS_IsException(op1)) { @@ -13713,6 +13807,7 @@ static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op, return res; } +#ifdef CONFIG_BIGNUM static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JSValue op1, JSValue op2) { @@ -13732,8 +13827,8 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op1); return -1; } - a = JS_ToBigDecimal(ctx, op1); - b = JS_ToBigDecimal(ctx, op2); + a = JS_ToBigDecimal(ctx, op1); /* cannot fail */ + b = JS_ToBigDecimal(ctx, op2); /* cannot fail */ switch(op) { case OP_lt: @@ -13758,11 +13853,12 @@ static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op, JS_FreeValue(ctx, op2); return res; } +#endif /* !CONFIG_BIGNUM */ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, OPCodeEnum op) { - JSValue op1, op2, ret; + JSValue op1, op2; int res; uint32_t tag1, tag2; @@ -13770,11 +13866,13 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, op2 = sp[-1]; tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM /* try to call an overloaded operator */ if ((tag1 == JS_TAG_OBJECT && (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) || (tag2 == JS_TAG_OBJECT && (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) { + JSValue ret; res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op, FALSE, HINT_NUMBER); if (res != 0) { @@ -13788,6 +13886,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, } } } +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -13862,6 +13961,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, tag1 = JS_VALUE_GET_NORM_TAG(op1); tag2 = JS_VALUE_GET_NORM_TAG(op2); +#ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2); if (res < 0) @@ -13870,7 +13970,9 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; - } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { + } else +#endif + if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); if (res < 0) goto exception; @@ -13918,14 +14020,20 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, static BOOL tag_is_number(uint32_t tag) { return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT || - tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT || - tag == JS_TAG_BIG_DECIMAL); + tag == JS_TAG_FLOAT64 +#ifdef CONFIG_BIGNUM + || tag == JS_TAG_BIG_FLOAT || tag == JS_TAG_BIG_DECIMAL +#endif + ); } static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, BOOL is_neq) { - JSValue op1, op2, ret; + JSValue op1, op2; +#ifdef CONFIG_BIGNUM + JSValue ret; +#endif int res; uint32_t tag1, tag2; @@ -13953,7 +14061,9 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, d2 = JS_VALUE_GET_INT(op2); } res = (d1 == d2); - } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { + } else +#ifdef CONFIG_BIGNUM + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; @@ -13961,12 +14071,15 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; - } else { + } else +#endif + { res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2); if (res < 0) goto exception; } } else if (tag1 == tag2) { +#ifdef CONFIG_BIGNUM if (tag1 == JS_TAG_OBJECT) { /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, @@ -13983,6 +14096,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, } } } +#endif res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT); } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { @@ -14030,7 +14144,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) || (tag2 == JS_TAG_OBJECT && (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) { - +#ifdef CONFIG_BIGNUM /* try the fallback operator */ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, is_neq ? OP_neq : OP_eq, @@ -14045,7 +14159,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, return 0; } } - +#endif op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); if (JS_IsException(op1)) { JS_FreeValue(ctx, op2); @@ -14117,6 +14231,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) return -1; } +#ifdef CONFIG_BIGNUM static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a, int64_t exponent) { @@ -14151,8 +14266,10 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) op1 = sp[-2]; op2 = sp[-1]; a = JS_ToBigFloat(ctx, &a_s, op1); - if (!a) + if (!a) { + JS_FreeValue(ctx, res); return -1; + } if (JS_IsBigInt(ctx, op2)) { ret = JS_ToBigInt64(ctx, &e, op2); } else { @@ -14173,395 +14290,7 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp) sp[-2] = res; return 0; } - -#else /* !CONFIG_BIGNUM */ - -static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx) -{ - return JS_ThrowTypeError(ctx, "bigint is not supported"); -} - -JSValue JS_NewBigInt64(JSContext *ctx, int64_t v) -{ - return JS_ThrowUnsupportedBigint(ctx); -} - -JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v) -{ - return JS_ThrowUnsupportedBigint(ctx); -} - -int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val) -{ - JS_ThrowUnsupportedBigint(ctx); - *pres = 0; - return -1; -} - -static no_inline __exception int js_unary_arith_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1; - double d; - - op1 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - switch(op) { - case OP_inc: - d++; - break; - case OP_dec: - d--; - break; - case OP_plus: - break; - case OP_neg: - d = -d; - break; - default: - abort(); - } - sp[-1] = JS_NewFloat64(ctx, d); - return 0; -} - -/* specific case necessary for correct return value semantics */ -static __exception int js_post_inc_slow(JSContext *ctx, - JSValue *sp, OPCodeEnum op) -{ - JSValue op1; - double d, r; - - op1 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - r = d + 2 * (op - OP_post_dec) - 1; - sp[0] = JS_NewFloat64(ctx, r); - sp[-1] = JS_NewFloat64(ctx, d); - return 0; -} - -static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - double d1, d2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) { - goto exception; - } - switch(op) { - case OP_sub: - r = d1 - d2; - break; - case OP_mul: - r = d1 * d2; - break; - case OP_div: - r = d1 / d2; - break; - case OP_mod: - r = fmod(d1, d2); - break; - case OP_pow: - r = js_pow(d1, d2); - break; - default: - abort(); - } - sp[-2] = JS_NewFloat64(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t tag1, tag2; - - op1 = sp[-2]; - op2 = sp[-1]; - tag1 = JS_VALUE_GET_TAG(op1); - tag2 = JS_VALUE_GET_TAG(op2); - if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) && - (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) { - goto add_numbers; - } else { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - tag1 = JS_VALUE_GET_TAG(op1); - tag2 = JS_VALUE_GET_TAG(op2); - if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) { - sp[-2] = JS_ConcatString(ctx, op1, op2); - if (JS_IsException(sp[-2])) - goto exception; - } else { - double d1, d2; - add_numbers: - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - sp[-2] = JS_NewFloat64(ctx, d1 + d2); - } - } - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_binary_logic_slow(JSContext *ctx, - JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2))) - goto exception; - switch(op) { - case OP_shl: - r = v1 << (v2 & 0x1f); - break; - case OP_sar: - r = (int)v1 >> (v2 & 0x1f); - break; - case OP_and: - r = v1 & v2; - break; - case OP_or: - r = v1 | v2; - break; - case OP_xor: - r = v1 ^ v2; - break; - default: - abort(); - } - sp[-2] = JS_NewInt32(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline int js_not_slow(JSContext *ctx, JSValue *sp) -{ - int32_t v1; - - if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) { - sp[-1] = JS_UNDEFINED; - return -1; - } - sp[-1] = JS_NewInt32(ctx, ~v1); - return 0; -} - -static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, - OPCodeEnum op) -{ - JSValue op1, op2; - int res; - - op1 = sp[-2]; - op2 = sp[-1]; - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING && - JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) { - JSString *p1, *p2; - p1 = JS_VALUE_GET_STRING(op1); - p2 = JS_VALUE_GET_STRING(op2); - res = js_string_compare(ctx, p1, p2); - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - switch(op) { - case OP_lt: - res = (res < 0); - break; - case OP_lte: - res = (res <= 0); - break; - case OP_gt: - res = (res > 0); - break; - default: - case OP_gte: - res = (res >= 0); - break; - } - } else { - double d1, d2; - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - switch(op) { - case OP_lt: - res = (d1 < d2); /* if NaN return false */ - break; - case OP_lte: - res = (d1 <= d2); /* if NaN return false */ - break; - case OP_gt: - res = (d1 > d2); /* if NaN return false */ - break; - default: - case OP_gte: - res = (d1 >= d2); /* if NaN return false */ - break; - } - } - sp[-2] = JS_NewBool(ctx, res); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, - BOOL is_neq) -{ - JSValue op1, op2; - int tag1, tag2; - BOOL res; - - op1 = sp[-2]; - op2 = sp[-1]; - redo: - tag1 = JS_VALUE_GET_NORM_TAG(op1); - tag2 = JS_VALUE_GET_NORM_TAG(op2); - if (tag1 == tag2 || - (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) || - (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) { - res = js_strict_eq(ctx, op1, op2); - } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) || - (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) { - res = TRUE; - } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT || - tag2 == JS_TAG_FLOAT64)) || - (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT || - tag1 == JS_TAG_FLOAT64))) { - double d1; - double d2; - if (JS_ToFloat64Free(ctx, &d1, op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (JS_ToFloat64Free(ctx, &d2, op2)) - goto exception; - res = (d1 == d2); - } else if (tag1 == JS_TAG_BOOL) { - op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1)); - goto redo; - } else if (tag2 == JS_TAG_BOOL) { - op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2)); - goto redo; - } else if (tag1 == JS_TAG_OBJECT && - (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) { - op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); - if (JS_IsException(op1)) { - JS_FreeValue(ctx, op2); - goto exception; - } - goto redo; - } else if (tag2 == JS_TAG_OBJECT && - (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) { - op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE); - if (JS_IsException(op2)) { - JS_FreeValue(ctx, op1); - goto exception; - } - goto redo; - } else { - /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ - if ((JS_IsHTMLDDA(ctx, op1) && - (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || - (JS_IsHTMLDDA(ctx, op2) && - (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { - res = TRUE; - } else { - res = FALSE; - } - JS_FreeValue(ctx, op1); - JS_FreeValue(ctx, op2); - } - sp[-2] = JS_NewBool(ctx, res ^ is_neq); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp) -{ - JSValue op1, op2; - uint32_t v1, v2, r; - - op1 = sp[-2]; - op2 = sp[-1]; - if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) { - JS_FreeValue(ctx, op2); - goto exception; - } - if (unlikely(JS_ToUint32Free(ctx, &v2, op2))) - goto exception; - r = v1 >> (v2 & 0x1f); - sp[-2] = JS_NewUint32(ctx, r); - return 0; - exception: - sp[-2] = JS_UNDEFINED; - sp[-1] = JS_UNDEFINED; - return -1; -} - -#endif /* !CONFIG_BIGNUM */ +#endif /* XXX: Should take JSValueConst arguments */ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, @@ -14655,7 +14384,6 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, res = (d1 == d2); /* if NaN return false and +0 == -0 */ } goto done_no_free; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: { bf_t a_s, *a, b_s, *b; @@ -14663,8 +14391,8 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, res = FALSE; break; } - a = JS_ToBigFloat(ctx, &a_s, op1); - b = JS_ToBigFloat(ctx, &b_s, op2); + a = JS_ToBigFloat(ctx, &a_s, op1); /* cannot fail */ + b = JS_ToBigFloat(ctx, &b_s, op2); /* cannot fail */ res = bf_cmp_eq(a, b); if (a == &a_s) bf_delete(a); @@ -14672,6 +14400,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2, bf_delete(b); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: { JSBigFloat *p1, *p2; @@ -14776,6 +14505,43 @@ static __exception int js_operator_in(JSContext *ctx, JSValue *sp) return 0; } +static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp) +{ + JSValue op1, op2; + int ret; + + op1 = sp[-2]; /* object */ + op2 = sp[-1]; /* field name or method function */ + + if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) { + JS_ThrowTypeError(ctx, "invalid 'in' operand"); + return -1; + } + if (JS_IsObject(op2)) { + /* method: use the brand */ + ret = JS_CheckBrand(ctx, op1, op2); + if (ret < 0) + return -1; + } else { + JSAtom atom; + JSObject *p; + JSShapeProperty *prs; + JSProperty *pr; + /* field */ + atom = JS_ValueToAtom(ctx, op2); + if (unlikely(atom == JS_ATOM_NULL)) + return -1; + p = JS_VALUE_GET_OBJ(op1); + prs = find_own_property(&pr, p, atom); + JS_FreeAtom(ctx, atom); + ret = (prs != NULL); + } + JS_FreeValue(ctx, op1); + JS_FreeValue(ctx, op2); + sp[-2] = JS_NewBool(ctx, ret); + return 0; +} + static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj, JSAtom atom) { @@ -14817,10 +14583,10 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) tag = JS_VALUE_GET_NORM_TAG(op1); switch(tag) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: atom = JS_ATOM_bigint; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: atom = JS_ATOM_bigfloat; break; @@ -15074,10 +14840,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst * static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) { - JSObject *p; + JSObject *p, *p1; JSPropertyEnum *tab_atom; int i; - JSValue enum_obj, obj1; + JSValue enum_obj; JSForInIterator *it; uint32_t tag, tab_atom_count; @@ -15100,14 +14866,65 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) it->is_array = FALSE; it->obj = obj; it->idx = 0; - p = JS_VALUE_GET_OBJ(enum_obj); - p->u.for_in_iterator = it; + it->tab_atom = NULL; + it->atom_count = 0; + it->in_prototype_chain = FALSE; + p1 = JS_VALUE_GET_OBJ(enum_obj); + p1->u.for_in_iterator = it; if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) return enum_obj; - /* fast path: assume no enumerable properties in the prototype chain */ - obj1 = JS_DupValue(ctx, obj); + p = JS_VALUE_GET_OBJ(obj); + if (p->fast_array) { + JSShape *sh; + JSShapeProperty *prs; + /* check that there are no enumerable normal fields */ + sh = p->shape; + for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { + if (prs->flags & JS_PROP_ENUMERABLE) + goto normal_case; + } + /* for fast arrays, we only store the number of elements */ + it->is_array = TRUE; + it->atom_count = p->u.array.count; + } else { + normal_case: + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + JS_FreeValue(ctx, enum_obj); + return JS_EXCEPTION; + } + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + } + return enum_obj; +} + +/* obj -> enum_obj */ +static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) +{ + sp[-1] = build_for_in_iterator(ctx, sp[-1]); + if (JS_IsException(sp[-1])) + return -1; + return 0; +} + +/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */ +static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, + JSValueConst enum_obj) +{ + JSObject *p; + JSForInIterator *it; + JSPropertyEnum *tab_atom; + uint32_t tab_atom_count, i; + JSValue obj1; + + p = JS_VALUE_GET_OBJ(enum_obj); + it = p->u.for_in_iterator; + + /* check if there are enumerable properties in the prototype chain (fast path) */ + obj1 = JS_DupValue(ctx, it->obj); for(;;) { obj1 = JS_GetPrototypeFree(ctx, obj1); if (JS_IsNull(obj1)) @@ -15131,75 +14948,29 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) goto fail; } } - - p = JS_VALUE_GET_OBJ(obj); - - if (p->fast_array) { - JSShape *sh; - JSShapeProperty *prs; - /* check that there are no enumerable normal fields */ - sh = p->shape; - for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) { - if (prs->flags & JS_PROP_ENUMERABLE) - goto normal_case; - } - /* for fast arrays, we only store the number of elements */ - it->is_array = TRUE; - it->array_length = p->u.array.count; - } else { - normal_case: - if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, - JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) - goto fail; - for(i = 0; i < tab_atom_count; i++) { - JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - } - return enum_obj; + JS_FreeValue(ctx, obj1); + return 1; slow_path: - /* non enumerable properties hide the enumerables ones in the - prototype chain */ - obj1 = JS_DupValue(ctx, obj); - for(;;) { + /* add the visited properties, even if they are not enumerable */ + if (it->is_array) { if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, - JS_VALUE_GET_OBJ(obj1), + JS_VALUE_GET_OBJ(it->obj), JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { - JS_FreeValue(ctx, obj1); goto fail; } - for(i = 0; i < tab_atom_count; i++) { - JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL, - (tab_atom[i].is_enumerable ? - JS_PROP_ENUMERABLE : 0)); - } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); - obj1 = JS_GetPrototypeFree(ctx, obj1); - if (JS_IsNull(obj1)) - break; - if (JS_IsException(obj1)) - goto fail; - /* must check for timeout to avoid infinite loop */ - if (js_poll_interrupts(ctx)) { - JS_FreeValue(ctx, obj1); + it->is_array = FALSE; + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + } + + for(i = 0; i < it->atom_count; i++) { + if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0) goto fail; - } } - return enum_obj; - - fail: - JS_FreeValue(ctx, enum_obj); - return JS_EXCEPTION; -} - -/* obj -> enum_obj */ -static __exception int js_for_in_start(JSContext *ctx, JSValue *sp) -{ - sp[-1] = build_for_in_iterator(ctx, sp[-1]); - if (JS_IsException(sp[-1])) - return -1; return 0; + fail: + return -1; } /* enum_obj -> enum_obj value done */ @@ -15209,6 +14980,8 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) JSObject *p; JSAtom prop; JSForInIterator *it; + JSPropertyEnum *tab_atom; + uint32_t tab_atom_count; int ret; enum_obj = sp[-1]; @@ -15221,28 +14994,68 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) it = p->u.for_in_iterator; for(;;) { - if (it->is_array) { - if (it->idx >= it->array_length) - goto done; - prop = __JS_AtomFromUInt32(it->idx); - it->idx++; + if (it->idx >= it->atom_count) { + if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj)) + goto done; /* not an object */ + /* no more property in the current object: look in the prototype */ + if (!it->in_prototype_chain) { + ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj); + if (ret < 0) + return -1; + if (ret) + goto done; + it->in_prototype_chain = TRUE; + } + it->obj = JS_GetPrototypeFree(ctx, it->obj); + if (JS_IsException(it->obj)) + return -1; + if (JS_IsNull(it->obj)) + goto done; /* no more prototype */ + + /* must check for timeout to avoid infinite loop */ + if (js_poll_interrupts(ctx)) + return -1; + + if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, + JS_VALUE_GET_OBJ(it->obj), + JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { + return -1; + } + js_free_prop_enum(ctx, it->tab_atom, it->atom_count); + it->tab_atom = tab_atom; + it->atom_count = tab_atom_count; + it->idx = 0; } else { - JSShape *sh = p->shape; - JSShapeProperty *prs; - if (it->idx >= sh->prop_count) - goto done; - prs = get_shape_prop(sh) + it->idx; - prop = prs->atom; - it->idx++; - if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE)) - continue; + if (it->is_array) { + prop = __JS_AtomFromUInt32(it->idx); + it->idx++; + } else { + BOOL is_enumerable; + prop = it->tab_atom[it->idx].atom; + is_enumerable = it->tab_atom[it->idx].is_enumerable; + it->idx++; + if (it->in_prototype_chain) { + /* slow case: we are in the prototype chain */ + ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop); + if (ret < 0) + return ret; + if (ret) + continue; /* already visited */ + /* add to the visited property list */ + if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL, + JS_PROP_ENUMERABLE) < 0) + return -1; + } + if (!is_enumerable) + continue; + } + /* check if the property was deleted */ + ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop); + if (ret < 0) + return ret; + if (ret) + break; } - /* check if the property was deleted */ - ret = JS_HasProperty(ctx, it->obj, prop); - if (ret < 0) - return ret; - if (ret) - break; } /* return the property */ sp[0] = JS_AtomToValue(ctx, prop); @@ -15728,7 +15541,7 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, struct list_head *el; list_for_each(el, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) { var_ref->header.ref_count++; return var_ref; @@ -15739,15 +15552,29 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, if (!var_ref) return NULL; var_ref->header.ref_count = 1; + add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); var_ref->is_detached = FALSE; var_ref->is_arg = is_arg; var_ref->var_idx = var_idx; - list_add_tail(&var_ref->header.link, &sf->var_ref_list); + list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list); + if (sf->js_mode & JS_MODE_ASYNC) { + /* The stack frame is detached and may be destroyed at any + time so its reference count must be increased. Calling + close_var_refs() when destroying the stack frame is not + possible because it would change the graph between the GC + objects. Another solution could be to temporarily detach + the JSVarRef of async functions during the GC. It would + have the advantage of allowing the release of unused stack + frames in a cycle. */ + var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame); + var_ref->async_func->header.ref_count++; + } else { + var_ref->async_func = NULL; + } if (is_arg) var_ref->pvalue = &sf->arg_buf[var_idx]; else var_ref->pvalue = &sf->var_buf[var_idx]; - var_ref->value = JS_UNDEFINED; return var_ref; } @@ -15978,7 +15805,10 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) int var_idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); + /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */ + if (var_ref->async_func) + async_func_free(rt, var_ref->async_func); var_idx = var_ref->var_idx; if (var_ref->is_arg) var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]); @@ -15987,7 +15817,6 @@ static void close_var_refs(JSRuntime *rt, JSStackFrame *sf) var_ref->pvalue = &var_ref->value; /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; - add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } @@ -15998,14 +15827,15 @@ static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_ int var_idx = idx; list_for_each_safe(el, el1, &sf->var_ref_list) { - var_ref = list_entry(el, JSVarRef, header.link); + var_ref = list_entry(el, JSVarRef, var_ref_link); if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) { + list_del(&var_ref->var_ref_link); + if (var_ref->async_func) + async_func_free(ctx->rt, var_ref->async_func); var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]); var_ref->pvalue = &var_ref->value; - list_del(&var_ref->header.link); /* the reference is no longer to a local variable */ var_ref->is_detached = TRUE; - add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF); } } } @@ -16196,9 +16026,10 @@ typedef enum { OP_SPECIAL_OBJECT_IMPORT_META, } OPSpecialObjectEnum; -#define FUNC_RET_AWAIT 0 -#define FUNC_RET_YIELD 1 -#define FUNC_RET_YIELD_STAR 2 +#define FUNC_RET_AWAIT 0 +#define FUNC_RET_YIELD 1 +#define FUNC_RET_YIELD_STAR 2 +#define FUNC_RET_INITIAL_YIELD 3 /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, @@ -16760,8 +16591,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; CASE(OP_check_brand): - if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0) - goto exception; + { + int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]); + if (ret < 0) + goto exception; + if (!ret) { + JS_ThrowTypeError(ctx, "invalid brand on object"); + goto exception; + } + } BREAK; CASE(OP_add_brand): if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) @@ -17183,6 +17021,19 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sp++; } BREAK; + CASE(OP_get_loc_checkthis): + { + int idx; + idx = get_u16(pc); + pc += 2; + if (unlikely(JS_IsUninitialized(var_buf[idx]))) { + JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE); + goto exception; + } + sp[0] = JS_DupValue(ctx, var_buf[idx]); + sp++; + } + BREAK; CASE(OP_put_loc_check): { int idx; @@ -17452,26 +17303,21 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, } sp--; BREAK; - CASE(OP_iterator_close_return): + CASE(OP_nip_catch): { JSValue ret_val; - /* iter_obj next catch_offset ... ret_val -> - ret_eval iter_obj next catch_offset */ + /* catch_offset ... ret_val -> ret_eval */ ret_val = *--sp; while (sp > stack_buf && JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) { JS_FreeValue(ctx, *--sp); } - if (unlikely(sp < stack_buf + 3)) { - JS_ThrowInternalError(ctx, "iterator_close_return"); + if (unlikely(sp == stack_buf)) { + JS_ThrowInternalError(ctx, "nip_catch"); JS_FreeValue(ctx, ret_val); goto exception; } - sp[0] = sp[-1]; - sp[-1] = sp[-2]; - sp[-2] = sp[-3]; - sp[-3] = ret_val; - sp++; + sp[-1] = ret_val; } BREAK; @@ -17572,7 +17418,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = get_u32(pc); pc += 4; - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], + ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-2]); sp -= 2; @@ -17871,8 +17717,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-2]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4], - JS_PROP_THROW_STRICT); + ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4], + JS_PROP_THROW_STRICT); JS_FreeAtom(ctx, atom); JS_FreeValue(ctx, sp[-4]); JS_FreeValue(ctx, sp[-3]); @@ -18421,6 +18267,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, goto exception; sp--; BREAK; + CASE(OP_private_in): + if (js_operator_private_in(ctx, sp)) + goto exception; + sp--; + BREAK; CASE(OP_instanceof): if (js_operator_instanceof(ctx, sp)) goto exception; @@ -18551,7 +18402,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, break; case OP_with_put_var: /* XXX: check if strict mode */ - ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], + ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj, JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); sp -= 2; @@ -18607,9 +18458,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR); goto done_generator; CASE(OP_return_async): - CASE(OP_initial_yield): ret_val = JS_UNDEFINED; goto done_generator; + CASE(OP_initial_yield): + ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD); + goto done_generator; CASE(OP_nop): BREAK; @@ -18891,26 +18744,35 @@ static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom, } /* JSAsyncFunctionState (used by generator and async functions) */ -static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, - JSValueConst func_obj, JSValueConst this_obj, - int argc, JSValueConst *argv) +static JSAsyncFunctionState *async_func_init(JSContext *ctx, + JSValueConst func_obj, JSValueConst this_obj, + int argc, JSValueConst *argv) { + JSAsyncFunctionState *s; JSObject *p; JSFunctionBytecode *b; JSStackFrame *sf; int local_count, i, arg_buf_len, n; + s = js_mallocz(ctx, sizeof(*s)); + if (!s) + return NULL; + s->header.ref_count = 1; + add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); + sf = &s->frame; init_list_head(&sf->var_ref_list); p = JS_VALUE_GET_OBJ(func_obj); b = p->u.func.function_bytecode; - sf->js_mode = b->js_mode; + sf->js_mode = b->js_mode | JS_MODE_ASYNC; sf->cur_pc = b->byte_code_buf; arg_buf_len = max_int(b->arg_count, argc); local_count = arg_buf_len + b->var_count + b->stack_size; sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1)); - if (!sf->arg_buf) - return -1; + if (!sf->arg_buf) { + js_free(ctx, s); + return NULL; + } sf->cur_func = JS_DupValue(ctx, func_obj); s->this_val = JS_DupValue(ctx, this_obj); s->argc = argc; @@ -18922,38 +18784,17 @@ static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s, n = arg_buf_len + b->var_count; for(i = argc; i < n; i++) sf->arg_buf[i] = JS_UNDEFINED; - return 0; -} - -static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s, - JS_MarkFunc *mark_func) -{ - JSStackFrame *sf; - JSValue *sp; - - sf = &s->frame; - JS_MarkValue(rt, sf->cur_func, mark_func); - JS_MarkValue(rt, s->this_val, mark_func); - if (sf->cur_sp) { - /* if the function is running, cur_sp is not known so we - cannot mark the stack. Marking the variables is not needed - because a running function cannot be part of a removable - cycle */ - for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) - JS_MarkValue(rt, *sp, mark_func); - } + s->resolving_funcs[0] = JS_UNDEFINED; + s->resolving_funcs[1] = JS_UNDEFINED; + s->is_completed = FALSE; + return s; } -static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s) { - JSStackFrame *sf; + JSStackFrame *sf = &s->frame; JSValue *sp; - sf = &s->frame; - - /* close the closure variables. */ - close_var_refs(rt, sf); - if (sf->arg_buf) { /* cannot free the function if it is running */ assert(sf->cur_sp != NULL); @@ -18961,6 +18802,7 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) JS_FreeValueRT(rt, *sp); } js_free_rt(rt, sf->arg_buf); + sf->arg_buf = NULL; } JS_FreeValueRT(rt, sf->cur_func); JS_FreeValueRT(rt, s->this_val); @@ -18968,17 +18810,66 @@ static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) { - JSValue func_obj; + JSRuntime *rt = ctx->rt; + JSStackFrame *sf = &s->frame; + JSValue func_obj, ret; - if (js_check_stack_overflow(ctx->rt, 0)) - return JS_ThrowStackOverflow(ctx); + assert(!s->is_completed); + if (js_check_stack_overflow(ctx->rt, 0)) { + ret = JS_ThrowStackOverflow(ctx); + } else { + /* the tag does not matter provided it is not an object */ + func_obj = JS_MKPTR(JS_TAG_INT, s); + ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, + s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR); + } + if (JS_IsException(ret) || JS_IsUndefined(ret)) { + if (JS_IsUndefined(ret)) { + ret = sf->cur_sp[-1]; + sf->cur_sp[-1] = JS_UNDEFINED; + } + /* end of execution */ + s->is_completed = TRUE; - /* the tag does not matter provided it is not an object */ - func_obj = JS_MKPTR(JS_TAG_INT, s); - return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED, - s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR); + /* close the closure variables. */ + close_var_refs(rt, sf); + + async_func_free_frame(rt, s); + } + return ret; +} + +static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + /* cannot close the closure variables here because it would + potentially modify the object graph */ + if (!s->is_completed) { + async_func_free_frame(rt, s); + } + + JS_FreeValueRT(rt, s->resolving_funcs[0]); + JS_FreeValueRT(rt, s->resolving_funcs[1]); + + remove_gc_object(&s->header); + if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) { + list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list); + } else { + js_free_rt(rt, s); + } } +static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s) +{ + if (--s->header.ref_count == 0) { + if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) { + list_del(&s->header.link); + list_add(&s->header.link, &rt->gc_zero_ref_count_list); + if (rt->gc_phase == JS_GC_PHASE_NONE) { + free_zero_refcount(rt); + } + } + } +} /* Generators */ @@ -18992,14 +18883,17 @@ typedef enum JSGeneratorStateEnum { typedef struct JSGeneratorData { JSGeneratorStateEnum state; - JSAsyncFunctionState func_state; + JSAsyncFunctionState *func_state; } JSGeneratorData; static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s) { if (s->state == JS_GENERATOR_STATE_COMPLETED) return; - async_func_free(rt, &s->func_state); + if (s->func_state) { + async_func_free(rt, s->func_state); + s->func_state = NULL; + } s->state = JS_GENERATOR_STATE_COMPLETED; } @@ -19024,9 +18918,9 @@ static void js_generator_mark(JSRuntime *rt, JSValueConst val, JSObject *p = JS_VALUE_GET_OBJ(val); JSGeneratorData *s = p->u.generator_data; - if (!s || s->state == JS_GENERATOR_STATE_COMPLETED) + if (!s || !s->func_state) return; - async_func_mark(rt, &s->func_state, mark_func); + mark_func(rt, &s->func_state->header); } /* XXX: use enum */ @@ -19045,7 +18939,7 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, *pdone = TRUE; if (!s) return JS_ThrowTypeError(ctx, "not a generator"); - sf = &s->func_state.frame; + sf = &s->func_state->frame; switch(s->state) { default: case JS_GENERATOR_STATE_SUSPENDED_START: @@ -19063,23 +18957,23 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, if (magic == GEN_MAGIC_THROW && s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, ret); - s->func_state.throw_flag = TRUE; + s->func_state->throw_flag = TRUE; } else { sf->cur_sp[-1] = ret; sf->cur_sp[0] = JS_NewInt32(ctx, magic); sf->cur_sp++; exec_no_arg: - s->func_state.throw_flag = FALSE; + s->func_state->throw_flag = FALSE; } s->state = JS_GENERATOR_STATE_EXECUTING; - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD; - if (JS_IsException(func_ret)) { - /* finalize the execution in case of exception */ + if (s->func_state->is_completed) { + /* finalize the execution in case of exception or normal return */ free_generator_stack(ctx, s); return func_ret; - } - if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { + } else { + assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); /* get the returned yield value at the top of the stack */ ret = sf->cur_sp[-1]; sf->cur_sp[-1] = JS_UNDEFINED; @@ -19090,12 +18984,6 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val, } else { *pdone = FALSE; } - } else { - /* end of iterator */ - ret = sf->cur_sp[-1]; - sf->cur_sp[-1] = JS_UNDEFINED; - JS_FreeValue(ctx, func_ret); - free_generator_stack(ctx, s); } break; case JS_GENERATOR_STATE_COMPLETED: @@ -19133,13 +19021,14 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, if (!s) return JS_EXCEPTION; s->state = JS_GENERATOR_STATE_SUSPENDED_START; - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { + s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); + if (!s->func_state) { s->state = JS_GENERATOR_STATE_COMPLETED; goto fail; } /* execute the function up to 'OP_initial_yield' */ - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19157,36 +19046,12 @@ static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj, /* AsyncFunction */ -static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s) -{ - if (s->is_active) { - async_func_free(rt, &s->func_state); - s->is_active = FALSE; - } -} - -static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s) -{ - js_async_function_terminate(rt, s); - JS_FreeValueRT(rt, s->resolving_funcs[0]); - JS_FreeValueRT(rt, s->resolving_funcs[1]); - remove_gc_object(&s->header); - js_free_rt(rt, s); -} - -static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s) -{ - if (--s->header.ref_count == 0) { - js_async_function_free0(rt, s); - } -} - static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; if (s) { - js_async_function_free(rt, s); + async_func_free(rt, s); } } @@ -19194,14 +19059,14 @@ static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) { JSObject *p = JS_VALUE_GET_OBJ(val); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; if (s) { mark_func(rt, &s->header); } } static int js_async_function_resolve_create(JSContext *ctx, - JSAsyncFunctionData *s, + JSAsyncFunctionState *s, JSValue *resolving_funcs) { int i; @@ -19223,60 +19088,58 @@ static int js_async_function_resolve_create(JSContext *ctx, return 0; } -static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s) +static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s) { JSValue func_ret, ret2; - func_ret = async_func_resume(ctx, &s->func_state); - if (JS_IsException(func_ret)) { - JSValue error; - fail: - error = JS_GetException(ctx); - ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, - 1, (JSValueConst *)&error); - JS_FreeValue(ctx, error); - js_async_function_terminate(ctx->rt, s); - JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - } else { - JSValue value; - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; - if (JS_IsUndefined(func_ret)) { - /* function returned */ - ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&value); + func_ret = async_func_resume(ctx, s); + if (s->is_completed) { + if (JS_IsException(func_ret)) { + JSValue error; + fail: + error = JS_GetException(ctx); + ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&error); + JS_FreeValue(ctx, error); JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, value); - js_async_function_terminate(ctx->rt, s); } else { - JSValue promise, resolving_funcs[2], resolving_funcs1[2]; - int i, res; + /* normal return */ + ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&func_ret); + JS_FreeValue(ctx, func_ret); + JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */ + } + } else { + JSValue value, promise, resolving_funcs[2], resolving_funcs1[2]; + int i, res; - /* await */ - JS_FreeValue(ctx, func_ret); /* not used */ - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - JS_FreeValue(ctx, value); - if (JS_IsException(promise)) - goto fail; - if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { - JS_FreeValue(ctx, promise); - goto fail; - } + value = s->frame.cur_sp[-1]; + s->frame.cur_sp[-1] = JS_UNDEFINED; - /* Note: no need to create 'thrownawayCapability' as in - the spec */ - for(i = 0; i < 2; i++) - resolving_funcs1[i] = JS_UNDEFINED; - res = perform_promise_then(ctx, promise, - (JSValueConst *)resolving_funcs, - (JSValueConst *)resolving_funcs1); + /* await */ + JS_FreeValue(ctx, func_ret); /* not used */ + promise = js_promise_resolve(ctx, ctx->promise_ctor, + 1, (JSValueConst *)&value, 0); + JS_FreeValue(ctx, value); + if (JS_IsException(promise)) + goto fail; + if (js_async_function_resolve_create(ctx, s, resolving_funcs)) { JS_FreeValue(ctx, promise); - for(i = 0; i < 2; i++) - JS_FreeValue(ctx, resolving_funcs[i]); - if (res) - goto fail; + goto fail; } + + /* Note: no need to create 'thrownawayCapability' as in + the spec */ + for(i = 0; i < 2; i++) + resolving_funcs1[i] = JS_UNDEFINED; + res = perform_promise_then(ctx, promise, + (JSValueConst *)resolving_funcs, + (JSValueConst *)resolving_funcs1); + JS_FreeValue(ctx, promise); + for(i = 0; i < 2; i++) + JS_FreeValue(ctx, resolving_funcs[i]); + if (res) + goto fail; } } @@ -19287,7 +19150,7 @@ static JSValue js_async_function_resolve_call(JSContext *ctx, int flags) { JSObject *p = JS_VALUE_GET_OBJ(func_obj); - JSAsyncFunctionData *s = p->u.async_function_data; + JSAsyncFunctionState *s = p->u.async_function_data; BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE; JSValueConst arg; @@ -19295,12 +19158,12 @@ static JSValue js_async_function_resolve_call(JSContext *ctx, arg = argv[0]; else arg = JS_UNDEFINED; - s->func_state.throw_flag = is_reject; + s->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ - s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_function_resume(ctx, s); return JS_UNDEFINED; @@ -19311,32 +19174,21 @@ static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj, int argc, JSValueConst *argv, int flags) { JSValue promise; - JSAsyncFunctionData *s; + JSAsyncFunctionState *s; - s = js_mallocz(ctx, sizeof(*s)); + s = async_func_init(ctx, func_obj, this_obj, argc, argv); if (!s) return JS_EXCEPTION; - s->header.ref_count = 1; - add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION); - s->is_active = FALSE; - s->resolving_funcs[0] = JS_UNDEFINED; - s->resolving_funcs[1] = JS_UNDEFINED; promise = JS_NewPromiseCapability(ctx, s->resolving_funcs); - if (JS_IsException(promise)) - goto fail; - - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { - fail: - JS_FreeValue(ctx, promise); - js_async_function_free(ctx->rt, s); + if (JS_IsException(promise)) { + async_func_free(ctx->rt, s); return JS_EXCEPTION; } - s->is_active = TRUE; js_async_function_resume(ctx, s); - - js_async_function_free(ctx->rt, s); + + async_func_free(ctx->rt, s); return promise; } @@ -19365,7 +19217,8 @@ typedef struct JSAsyncGeneratorRequest { typedef struct JSAsyncGeneratorData { JSObject *generator; /* back pointer to the object (const) */ JSAsyncGeneratorStateEnum state; - JSAsyncFunctionState func_state; + /* func_state is NULL is state AWAITING_RETURN and COMPLETED */ + JSAsyncFunctionState *func_state; struct list_head queue; /* list of JSAsyncGeneratorRequest.link */ } JSAsyncGeneratorData; @@ -19383,10 +19236,8 @@ static void js_async_generator_free(JSRuntime *rt, JS_FreeValueRT(rt, req->resolving_funcs[1]); js_free_rt(rt, req); } - if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && - s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { - async_func_free(rt, &s->func_state); - } + if (s->func_state) + async_func_free(rt, s->func_state); js_free_rt(rt, s); } @@ -19413,9 +19264,8 @@ static void js_async_generator_mark(JSRuntime *rt, JSValueConst val, JS_MarkValue(rt, req->resolving_funcs[0], mark_func); JS_MarkValue(rt, req->resolving_funcs[1], mark_func); } - if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED && - s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) { - async_func_mark(rt, &s->func_state, mark_func); + if (s->func_state) { + mark_func(rt, &s->func_state->header); } } } @@ -19525,7 +19375,8 @@ static void js_async_generator_complete(JSContext *ctx, { if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) { s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; - async_func_free(ctx->rt, &s->func_state); + async_func_free(ctx->rt, s->func_state); + s->func_state = NULL; } } @@ -19536,10 +19387,19 @@ static int js_async_generator_completed_return(JSContext *ctx, JSValue promise, resolving_funcs[2], resolving_funcs1[2]; int res; - promise = js_promise_resolve(ctx, ctx->promise_ctor, - 1, (JSValueConst *)&value, 0); - if (JS_IsException(promise)) - return -1; + // Can fail looking up JS_ATOM_constructor when is_reject==0. + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value, + /*is_reject*/0); + // A poisoned .constructor property is observable and the resulting + // exception should be delivered to the catch handler. + if (JS_IsException(promise)) { + JSValue err = JS_GetException(ctx); + promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err, + /*is_reject*/1); + JS_FreeValue(ctx, err); + if (JS_IsException(promise)) + return -1; + } if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator), resolving_funcs1, @@ -19587,7 +19447,6 @@ static void js_async_generator_resume_next(JSContext *ctx, } else if (next->completion_type == GEN_MAGIC_RETURN) { s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN; js_async_generator_completed_return(ctx, s, next->result); - goto done; } else { js_async_generator_reject(ctx, s, next->result); } @@ -19598,30 +19457,38 @@ static void js_async_generator_resume_next(JSContext *ctx, if (next->completion_type == GEN_MAGIC_THROW && s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) { JS_Throw(ctx, value); - s->func_state.throw_flag = TRUE; + s->func_state->throw_flag = TRUE; } else { /* 'yield' returns a value. 'yield *' also returns a value in case the 'throw' method is called */ - s->func_state.frame.cur_sp[-1] = value; - s->func_state.frame.cur_sp[0] = + s->func_state->frame.cur_sp[-1] = value; + s->func_state->frame.cur_sp[0] = JS_NewInt32(ctx, next->completion_type); - s->func_state.frame.cur_sp++; + s->func_state->frame.cur_sp++; exec_no_arg: - s->func_state.throw_flag = FALSE; + s->func_state->throw_flag = FALSE; } s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING; resume_exec: - func_ret = async_func_resume(ctx, &s->func_state); - if (JS_IsException(func_ret)) { - value = JS_GetException(ctx); - js_async_generator_complete(ctx, s); - js_async_generator_reject(ctx, s, value); - JS_FreeValue(ctx, value); - } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) { - int func_ret_code; - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; + func_ret = async_func_resume(ctx, s->func_state); + if (s->func_state->is_completed) { + if (JS_IsException(func_ret)) { + value = JS_GetException(ctx); + js_async_generator_complete(ctx, s); + js_async_generator_reject(ctx, s, value); + JS_FreeValue(ctx, value); + } else { + /* end of function */ + js_async_generator_complete(ctx, s); + js_async_generator_resolve(ctx, s, func_ret, TRUE); + JS_FreeValue(ctx, func_ret); + } + } else { + int func_ret_code, ret; + assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT); func_ret_code = JS_VALUE_GET_INT(func_ret); + value = s->func_state->frame.cur_sp[-1]; + s->func_state->frame.cur_sp[-1] = JS_UNDEFINED; switch(func_ret_code) { case FUNC_RET_YIELD: case FUNC_RET_YIELD_STAR: @@ -19633,20 +19500,17 @@ static void js_async_generator_resume_next(JSContext *ctx, JS_FreeValue(ctx, value); break; case FUNC_RET_AWAIT: - js_async_generator_await(ctx, s, value); + ret = js_async_generator_await(ctx, s, value); JS_FreeValue(ctx, value); + if (ret < 0) { + /* exception: throw it */ + s->func_state->throw_flag = TRUE; + goto resume_exec; + } goto done; default: abort(); } - } else { - assert(JS_IsUndefined(func_ret)); - /* end of function */ - value = s->func_state.frame.cur_sp[-1]; - s->func_state.frame.cur_sp[-1] = JS_UNDEFINED; - js_async_generator_complete(ctx, s); - js_async_generator_resolve(ctx, s, value, TRUE); - JS_FreeValue(ctx, value); } break; default: @@ -19680,12 +19544,12 @@ static JSValue js_async_generator_resolve_function(JSContext *ctx, } else { /* restart function execution after await() */ assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING); - s->func_state.throw_flag = is_reject; + s->func_state->throw_flag = is_reject; if (is_reject) { JS_Throw(ctx, JS_DupValue(ctx, arg)); } else { /* return value of await */ - s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg); + s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg); } js_async_generator_resume_next(ctx, s); } @@ -19749,14 +19613,12 @@ static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst fun return JS_EXCEPTION; s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START; init_list_head(&s->queue); - if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) { - s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED; + s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv); + if (!s->func_state) goto fail; - } - /* execute the function up to 'OP_initial_yield' (no yield nor await are possible) */ - func_ret = async_func_resume(ctx, &s->func_state); + func_ret = async_func_resume(ctx, s->func_state); if (JS_IsException(func_ret)) goto fail; JS_FreeValue(ctx, func_ret); @@ -19942,6 +19804,7 @@ typedef enum JSParseFunctionEnum { JS_PARSE_FUNC_GETTER, JS_PARSE_FUNC_SETTER, JS_PARSE_FUNC_METHOD, + JS_PARSE_FUNC_CLASS_STATIC_INIT, JS_PARSE_FUNC_CLASS_CONSTRUCTOR, JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR, } JSParseFunctionEnum; @@ -20061,6 +19924,7 @@ typedef struct JSFunctionDef { int source_len; JSModuleDef *module; /* != NULL when parsing a module */ + BOOL has_await; /* TRUE if await is used (used in module eval) */ } JSFunctionDef; typedef struct JSToken { @@ -20149,11 +20013,9 @@ static __exception int next_token(JSParseState *s); static void free_token(JSParseState *s, JSToken *token) { switch(token->val) { -#ifdef CONFIG_BIGNUM case TOK_NUMBER: JS_FreeValue(s->ctx, token->u.num.val); break; -#endif case TOK_STRING: case TOK_TEMPLATE: JS_FreeValue(s->ctx, token->u.str.str); @@ -20613,6 +20475,48 @@ static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize, return 0; } +/* convert a TOK_IDENT to a keyword when needed */ +static void update_token_ident(JSParseState *s) +{ + if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || + (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && + (s->cur_func->js_mode & JS_MODE_STRICT)) || + (s->token.u.ident.atom == JS_ATOM_yield && + ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || + (s->token.u.ident.atom == JS_ATOM_await && + (s->is_module || + (s->cur_func->func_kind & JS_FUNC_ASYNC) || + s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT || + (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && + !s->cur_func->in_function_body && s->cur_func->parent && + ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) || + s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) { + if (s->token.u.ident.has_escape) { + s->token.u.ident.is_reserved = TRUE; + s->token.val = TOK_IDENT; + } else { + /* The keywords atoms are pre allocated */ + s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; + } + } +} + +/* if the current token is an identifier or keyword, reparse it + according to the current function type */ +static void reparse_ident_token(JSParseState *s) +{ + if (s->token.val == TOK_IDENT || + (s->token.val >= TOK_FIRST_KEYWORD && + s->token.val <= TOK_LAST_KEYWORD)) { + s->token.val = TOK_IDENT; + s->token.u.ident.is_reserved = FALSE; + update_token_ident(s); + } +} + /* 'c' is the first character. Return JS_ATOM_NULL in case of error */ static JSAtom parse_ident(JSParseState *s, const uint8_t **pp, BOOL *pident_has_escape, int c, BOOL is_private) @@ -20819,30 +20723,8 @@ static __exception int next_token(JSParseState *s) s->token.u.ident.atom = atom; s->token.u.ident.has_escape = ident_has_escape; s->token.u.ident.is_reserved = FALSE; - if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD || - (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD && - (s->cur_func->js_mode & JS_MODE_STRICT)) || - (s->token.u.ident.atom == JS_ATOM_yield && - ((s->cur_func->func_kind & JS_FUNC_GENERATOR) || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) || - (s->token.u.ident.atom == JS_ATOM_await && - (s->is_module || - (((s->cur_func->func_kind & JS_FUNC_ASYNC) || - (s->cur_func->func_type == JS_PARSE_FUNC_ARROW && - !s->cur_func->in_function_body && s->cur_func->parent && - (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) { - if (ident_has_escape) { - s->token.u.ident.is_reserved = TRUE; - s->token.val = TOK_IDENT; - } else { - /* The keywords atoms are pre allocated */ - s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD; - } - } else { - s->token.val = TOK_IDENT; - } + s->token.val = TOK_IDENT; + update_token_ident(s); break; case '#': /* private name */ @@ -20899,8 +20781,8 @@ static __exception int next_token(JSParseState *s) int flags, radix; flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL | ATOD_ACCEPT_UNDERSCORES; -#ifdef CONFIG_BIGNUM flags |= ATOD_ACCEPT_SUFFIX; +#ifdef CONFIG_BIGNUM if (s->cur_func->js_mode & JS_MODE_MATH) { flags |= ATOD_MODE_BIGINT; if (s->cur_func->js_mode & JS_MODE_MATH) @@ -21489,6 +21371,31 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator) return simple_next_token(&p, no_line_terminator); } +static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end) +{ + const uint8_t *p = *pp; + int c; + + if (p[0] == '#' && p[1] == '!') { + p += 2; + while (p < buf_end) { + if (*p == '\n' || *p == '\r') { + break; + } else if (*p >= 0x80) { + c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); + if (c == CP_LS || c == CP_PS) { + break; + } else if (c == -1) { + p++; /* skip invalid UTF-8 */ + } + } else { + p++; + } + } + *pp = p; + } +} + /* return true if 'input' contains the source of a module (heuristic). 'input' must be a zero terminated. @@ -21499,6 +21406,8 @@ BOOL JS_DetectModule(const char *input, size_t input_len) { const uint8_t *p = (const uint8_t *)input; int tok; + + skip_shebang(&p, p + input_len); switch(simple_next_token(&p, FALSE)) { case TOK_IMPORT: tok = simple_next_token(&p, FALSE); @@ -21611,6 +21520,14 @@ static int new_label(JSParseState *s) return new_label_fd(s->cur_func, -1); } +/* don't update the last opcode and don't emit line number info */ +static void emit_label_raw(JSParseState *s, int label) +{ + emit_u8(s, OP_label); + emit_u32(s, label); + s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size; +} + /* return the label ID offset */ static int emit_label(JSParseState *s, int label) { @@ -22109,7 +22026,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name, /* add a private field variable in the current scope */ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, - JSAtom name, JSVarKindEnum var_kind) + JSAtom name, JSVarKindEnum var_kind, BOOL is_static) { JSContext *ctx = s->ctx; JSVarDef *vd; @@ -22121,6 +22038,7 @@ static int add_private_class_field(JSParseState *s, JSFunctionDef *fd, vd = &fd->vars[idx]; vd->is_lexical = 1; vd->is_const = 1; + vd->is_static_private = is_static; return idx; } @@ -22866,8 +22784,9 @@ static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name) typedef struct { JSFunctionDef *fields_init_fd; int computed_fields_count; - BOOL has_brand; + BOOL need_brand; int brand_push_pos; + BOOL is_static; } ClassFieldsDef; static __exception int emit_class_init_start(JSParseState *s, @@ -22881,48 +22800,34 @@ static __exception int emit_class_init_start(JSParseState *s, s->cur_func = cf->fields_init_fd; - /* XXX: would be better to add the code only if needed, maybe in a - later pass */ - emit_op(s, OP_push_false); /* will be patched later */ - cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; - label_add_brand = emit_goto(s, OP_if_false, -1); - - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_this); - emit_u16(s, 0); - - emit_op(s, OP_scope_get_var); - emit_atom(s, JS_ATOM_home_object); - emit_u16(s, 0); - - emit_op(s, OP_add_brand); - - emit_label(s, label_add_brand); - - s->cur_func = s->cur_func->parent; - return 0; -} - -static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf) -{ - if (!cf->has_brand) { - /* define the brand field in 'this' of the initializer */ - if (!cf->fields_init_fd) { - if (emit_class_init_start(s, cf)) - return -1; - } - /* patch the start of the function to enable the OP_add_brand code */ - cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; + if (!cf->is_static) { + /* add the brand to the newly created instance */ + /* XXX: would be better to add the code only if needed, maybe in a + later pass */ + emit_op(s, OP_push_false); /* will be patched later */ + cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos; + label_add_brand = emit_goto(s, OP_if_false, -1); - cf->has_brand = TRUE; + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_this); + emit_u16(s, 0); + + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_home_object); + emit_u16(s, 0); + + emit_op(s, OP_add_brand); + + emit_label(s, label_add_brand); } + s->cur_func = s->cur_func->parent; return 0; } static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf) { int cpool_idx; - + s->cur_func = cf->fields_init_fd; emit_op(s, OP_return_undef); s->cur_func = s->cur_func->parent; @@ -22949,7 +22854,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, const uint8_t *class_start_ptr = s->token.ptr; const uint8_t *start_ptr; ClassFieldsDef class_fields[2]; - + /* classes are parsed and executed in strict mode */ saved_js_mode = fd->js_mode; fd->js_mode |= JS_MODE_STRICT; @@ -23022,7 +22927,8 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, ClassFieldsDef *cf = &class_fields[i]; cf->fields_init_fd = NULL; cf->computed_fields_count = 0; - cf->has_brand = FALSE; + cf->need_brand = FALSE; + cf->is_static = i; } ctor_fd = NULL; @@ -23037,6 +22943,41 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (is_static) { if (next_token(s)) goto fail; + if (s->token.val == '{') { + ClassFieldsDef *cf = &class_fields[is_static]; + JSFunctionDef *init; + if (!cf->fields_init_fd) { + if (emit_class_init_start(s, cf)) + goto fail; + } + s->cur_func = cf->fields_init_fd; + /* XXX: could try to avoid creating a new function and + reuse 'fields_init_fd' with a specific 'var' + scope */ + // stack is now: + if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT, + JS_FUNC_NORMAL, JS_ATOM_NULL, + s->token.ptr, s->token.line_num, + JS_PARSE_EXPORT_NONE, &init) < 0) { + goto fail; + } + // stack is now: fclosure + push_scope(s); + emit_op(s, OP_scope_get_var); + emit_atom(s, JS_ATOM_this); + emit_u16(s, 0); + // stack is now: fclosure this + emit_op(s, OP_swap); + // stack is now: this fclosure + emit_op(s, OP_call_method); + emit_u16(s, 0); + // stack is now: returnvalue + emit_op(s, OP_drop); + // stack is now: + pop_scope(s); + s->cur_func = s->cur_func->parent; + continue; + } /* allow "static" field name */ if (s->token.val == ';' || s->token.val == '=') { is_static = FALSE; @@ -23067,24 +23008,26 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, JSFunctionDef *method_fd; if (is_private) { - int idx, var_kind; + int idx, var_kind, is_static1; idx = find_private_class_field(ctx, fd, name, fd->scope_level); if (idx >= 0) { var_kind = fd->vars[idx].var_kind; + is_static1 = fd->vars[idx].is_static_private; if (var_kind == JS_VAR_PRIVATE_FIELD || var_kind == JS_VAR_PRIVATE_METHOD || var_kind == JS_VAR_PRIVATE_GETTER_SETTER || - var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) { + var_kind == (JS_VAR_PRIVATE_GETTER + is_set) || + (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) && + is_static != is_static1)) { goto private_field_already_defined; } fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER; } else { if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_GETTER + is_set) < 0) + JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0) goto fail; } - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; + class_fields[is_static].need_brand = TRUE; } if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set, @@ -23106,7 +23049,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; emit_atom(s, setter_name); ret = add_private_class_field(s, fd, setter_name, - JS_VAR_PRIVATE_SETTER); + JS_VAR_PRIVATE_SETTER, is_static); JS_FreeAtom(ctx, setter_name); if (ret < 0) goto fail; @@ -23141,7 +23084,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto private_field_already_defined; } if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_FIELD) < 0) + JS_VAR_PRIVATE_FIELD, is_static) < 0) goto fail; emit_op(s, OP_private_symbol); emit_atom(s, name); @@ -23231,8 +23174,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR; } if (is_private) { - if (add_brand(s, &class_fields[is_static]) < 0) - goto fail; + class_fields[is_static].need_brand = TRUE; } if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd)) goto fail; @@ -23248,7 +23190,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, goto fail; } if (add_private_class_field(s, fd, name, - JS_VAR_PRIVATE_METHOD) < 0) + JS_VAR_PRIVATE_METHOD, is_static) < 0) goto fail; emit_op(s, OP_set_home_object); emit_op(s, OP_set_name); @@ -23298,12 +23240,29 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, if (next_token(s)) goto fail; - /* store the function to initialize the fields to that it can be - referenced by the constructor */ { ClassFieldsDef *cf = &class_fields[0]; int var_idx; + + if (cf->need_brand) { + /* add a private brand to the prototype */ + emit_op(s, OP_dup); + emit_op(s, OP_null); + emit_op(s, OP_swap); + emit_op(s, OP_add_brand); + + /* define the brand field in 'this' of the initializer */ + if (!cf->fields_init_fd) { + if (emit_class_init_start(s, cf)) + goto fail; + } + /* patch the start of the function to enable the + OP_add_brand_instance code */ + cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true; + } + /* store the function to initialize the fields to that it can be + referenced by the constructor */ var_idx = define_var(s, fd, JS_ATOM_class_fields_init, JS_VAR_DEF_CONST); if (var_idx < 0) @@ -23321,16 +23280,13 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, /* drop the prototype */ emit_op(s, OP_drop); - /* initialize the static fields */ - if (class_fields[1].fields_init_fd != NULL) { - ClassFieldsDef *cf = &class_fields[1]; + if (class_fields[1].need_brand) { + /* add a private brand to the class */ emit_op(s, OP_dup); - emit_class_init_end(s, cf); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_drop); + emit_op(s, OP_dup); + emit_op(s, OP_add_brand); } - + if (class_name != JS_ATOM_NULL) { /* store the class name in the scoped class name variable (it is independent from the class statement variable @@ -23340,6 +23296,17 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr, emit_atom(s, class_name); emit_u16(s, fd->scope_level); } + + /* initialize the static fields */ + if (class_fields[1].fields_init_fd != NULL) { + ClassFieldsDef *cf = &class_fields[1]; + emit_op(s, OP_dup); + emit_class_init_end(s, cf); + emit_op(s, OP_call_method); + emit_u16(s, 0); + emit_op(s, OP_drop); + } + pop_scope(s); pop_scope(s); @@ -24524,8 +24491,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return -1; } name = JS_DupAtom(s->ctx, s->token.u.ident.atom); - if (next_token(s)) /* update line number before emitting code */ + if (next_token(s)) { /* update line number before emitting code */ + JS_FreeAtom(s->ctx, name); return -1; + } do_get_var: emit_op(s, OP_scope_get_var); emit_u32(s, name); @@ -24672,6 +24641,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2; drop_count = 2; break; + case OP_get_field_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 4 + 1); + /* keep the object on the stack */ + fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2; + fd->byte_code.size = fd->last_opcode_pos + 1 + 4; + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* need an additional undefined value for the + case where the optional field does not + exists */ + emit_op(s, OP_undefined); + emit_label(s, next_label); + drop_count = 2; + opcode = OP_get_field; + } + break; case OP_scope_get_private_field: /* keep the object on the stack */ fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2; @@ -24682,6 +24670,25 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2; drop_count = 2; break; + case OP_get_array_el_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 1); + /* keep the object on the stack */ + fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2; + fd->byte_code.size = fd->last_opcode_pos + 1; + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* need an additional undefined value for the + case where the optional field does not + exists */ + emit_op(s, OP_undefined); + emit_label(s, next_label); + drop_count = 2; + opcode = OP_get_array_el; + } + break; case OP_scope_get_var: { JSAtom name; @@ -24964,8 +24971,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) break; } } - if (optional_chaining_label >= 0) - emit_label(s, optional_chaining_label); + if (optional_chaining_label >= 0) { + JSFunctionDef *fd = s->cur_func; + int opcode; + emit_label_raw(s, optional_chaining_label); + /* modify the last opcode so that it is an indicator of an + optional chain */ + opcode = get_prev_opcode(fd); + if (opcode == OP_get_field || opcode == OP_get_array_el) { + if (opcode == OP_get_field) + opcode = OP_get_field_opt_chain; + else + opcode = OP_get_array_el_opt_chain; + fd->byte_code.buf[fd->last_opcode_pos] = opcode; + } else { + fd->last_opcode_pos = -1; + } + } return 0; } @@ -24981,27 +25003,57 @@ static __exception int js_parse_delete(JSParseState *s) return -1; switch(opcode = get_prev_opcode(fd)) { case OP_get_field: + case OP_get_field_opt_chain: { JSValue val; - int ret; - + int ret, opt_chain_label, next_label; + if (opcode == OP_get_field_opt_chain) { + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 4 + 1); + } else { + opt_chain_label = -1; + } name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); fd->byte_code.size = fd->last_opcode_pos; - fd->last_opcode_pos = -1; val = JS_AtomToValue(s->ctx, name); ret = emit_push_const(s, val, 1); JS_FreeValue(s->ctx, val); JS_FreeAtom(s->ctx, name); if (ret) return ret; + emit_op(s, OP_delete); + if (opt_chain_label >= 0) { + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* if the optional chain is not taken, return 'true' */ + emit_op(s, OP_drop); + emit_op(s, OP_push_true); + emit_label(s, next_label); + } + fd->last_opcode_pos = -1; } - goto do_delete; + break; case OP_get_array_el: fd->byte_code.size = fd->last_opcode_pos; fd->last_opcode_pos = -1; - do_delete: emit_op(s, OP_delete); break; + case OP_get_array_el_opt_chain: + { + int opt_chain_label, next_label; + opt_chain_label = get_u32(fd->byte_code.buf + + fd->last_opcode_pos + 1 + 1); + fd->byte_code.size = fd->last_opcode_pos; + emit_op(s, OP_delete); + next_label = emit_goto(s, OP_goto, -1); + emit_label(s, opt_chain_label); + /* if the optional chain is not taken, return 'true' */ + emit_op(s, OP_drop); + emit_op(s, OP_push_true); + emit_label(s, next_label); + fd->last_opcode_pos = -1; + } + break; case OP_scope_get_var: /* 'delete this': this is not a reference */ name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1); @@ -25016,6 +25068,8 @@ static __exception int js_parse_delete(JSParseState *s) case OP_scope_get_private_field: return js_parse_error(s, "cannot delete a private class field"); case OP_get_super_value: + fd->byte_code.size = fd->last_opcode_pos; + fd->last_opcode_pos = -1; emit_op(s, OP_throw_error); emit_atom(s, JS_ATOM_NULL); emit_u8(s, JS_THROW_ERROR_DELETE_SUPER); @@ -25115,6 +25169,7 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) return -1; if (js_parse_unary(s, PF_POW_FORBIDDEN)) return -1; + s->cur_func->has_await = TRUE; emit_op(s, OP_await); parse_flags = 0; break; @@ -25186,9 +25241,32 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level, if (level == 0) { return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) | PF_POW_ALLOWED); + } else if (s->token.val == TOK_PRIVATE_NAME && + (parse_flags & PF_IN_ACCEPTED) && level == 4 && + peek_token(s, FALSE) == TOK_IN) { + JSAtom atom; + + atom = JS_DupAtom(s->ctx, s->token.u.ident.atom); + if (next_token(s)) + goto fail_private_in; + if (s->token.val != TOK_IN) + goto fail_private_in; + if (next_token(s)) + goto fail_private_in; + if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC)) { + fail_private_in: + JS_FreeAtom(s->ctx, atom); + return -1; + } + emit_op(s, OP_scope_in_private_field); + emit_atom(s, atom); + emit_u16(s, s->cur_func->scope_level); + JS_FreeAtom(s->ctx, atom); + return 0; + } else { + if (js_parse_expr_binary(s, level - 1, parse_flags)) + return -1; } - if (js_parse_expr_binary(s, level - 1, parse_flags)) - return -1; for(;;) { op = s->token.val; switch(level) { @@ -25488,7 +25566,6 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) /* OP_async_yield_star takes the value as parameter */ emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); - emit_op(s, OP_await); emit_op(s, OP_async_yield_star); } else { /* OP_yield_star takes (value, done) as parameter */ @@ -25782,61 +25859,61 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) static void emit_return(JSParseState *s, BOOL hasval) { BlockEnv *top; - int drop_count; - drop_count = 0; + if (s->cur_func->func_kind != JS_FUNC_NORMAL) { + if (!hasval) { + /* no value: direct return in case of async generator */ + emit_op(s, OP_undefined); + hasval = TRUE; + } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { + /* the await must be done before handling the "finally" in + case it raises an exception */ + emit_op(s, OP_await); + } + } + top = s->cur_func->top_break; while (top != NULL) { - /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not - required as all local variables will be closed upon returning - from JS_CallInternal, but not in the same order. */ - if (top->has_iterator) { - /* with 'yield', the exact number of OP_drop to emit is - unknown, so we use a specific operation to look for - the catch offset */ + if (top->has_iterator || top->label_finally != -1) { if (!hasval) { emit_op(s, OP_undefined); hasval = TRUE; } - emit_op(s, OP_iterator_close_return); - if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - int label_next, label_next2; - - emit_op(s, OP_drop); /* catch offset */ - emit_op(s, OP_drop); /* next */ - emit_op(s, OP_get_field2); - emit_atom(s, JS_ATOM_return); - /* stack: iter_obj return_func */ - emit_op(s, OP_dup); - emit_op(s, OP_is_undefined_or_null); - label_next = emit_goto(s, OP_if_true, -1); - emit_op(s, OP_call_method); - emit_u16(s, 0); - emit_op(s, OP_iterator_check_object); - emit_op(s, OP_await); - label_next2 = emit_goto(s, OP_goto, -1); - emit_label(s, label_next); - emit_op(s, OP_drop); - emit_label(s, label_next2); - emit_op(s, OP_drop); + /* Remove the stack elements up to and including the catch + offset. When 'yield' is used in an expression we have + no easy way to count them, so we use this specific + instruction instead. */ + emit_op(s, OP_nip_catch); + /* stack: iter_obj next ret_val */ + if (top->has_iterator) { + if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { + int label_next, label_next2; + emit_op(s, OP_nip); /* next */ + emit_op(s, OP_swap); + emit_op(s, OP_get_field2); + emit_atom(s, JS_ATOM_return); + /* stack: iter_obj return_func */ + emit_op(s, OP_dup); + emit_op(s, OP_is_undefined_or_null); + label_next = emit_goto(s, OP_if_true, -1); + emit_op(s, OP_call_method); + emit_u16(s, 0); + emit_op(s, OP_iterator_check_object); + emit_op(s, OP_await); + label_next2 = emit_goto(s, OP_goto, -1); + emit_label(s, label_next); + emit_op(s, OP_drop); + emit_label(s, label_next2); + emit_op(s, OP_drop); + } else { + emit_op(s, OP_rot3r); + emit_op(s, OP_undefined); /* dummy catch offset */ + emit_op(s, OP_iterator_close); + } } else { - emit_op(s, OP_iterator_close); + /* execute the "finally" block */ + emit_goto(s, OP_gosub, top->label_finally); } - drop_count = -3; - } - drop_count += top->drop_count; - if (top->label_finally != -1) { - while(drop_count) { - /* must keep the stack top if hasval */ - emit_op(s, hasval ? OP_nip : OP_drop); - drop_count--; - } - if (!hasval) { - /* must push return value to keep same stack size */ - emit_op(s, OP_undefined); - hasval = TRUE; - } - emit_goto(s, OP_gosub, top->label_finally); } top = top->prev; } @@ -25853,20 +25930,15 @@ static void emit_return(JSParseState *s, BOOL hasval) label_return = -1; } - /* XXX: if this is not initialized, should throw the - ReferenceError in the caller realm */ - emit_op(s, OP_scope_get_var); + /* The error should be raised in the caller context, so we use + a specific opcode */ + emit_op(s, OP_scope_get_var_checkthis); emit_atom(s, JS_ATOM_this); emit_u16(s, 0); emit_label(s, label_return); emit_op(s, OP_return); } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) { - if (!hasval) { - emit_op(s, OP_undefined); - } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) { - emit_op(s, OP_await); - } emit_op(s, OP_return_async); } else { emit_op(s, hasval ? OP_return : OP_return_undef); @@ -26133,6 +26205,9 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, emit_atom(s, var_name); emit_u16(s, fd->scope_level); } + } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) && + peek_token(s, FALSE) == TOK_OF) { + return js_parse_error(s, "'for of' expression cannot start with 'async'"); } else { int skip_bits; if ((s->token.val == '[' || s->token.val == '{') @@ -26349,6 +26424,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, js_parse_error(s, "return not in a function"); goto fail; } + if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) { + js_parse_error(s, "return in a static initializer block"); + goto fail; + } if (next_token(s)) goto fail; if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) { @@ -26517,6 +26596,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s, is_async = TRUE; if (next_token(s)) goto fail; + s->cur_func->has_await = TRUE; } if (js_parse_expect(s, '(')) goto fail; @@ -27047,6 +27127,9 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) m->func_obj = JS_UNDEFINED; m->eval_exception = JS_UNDEFINED; m->meta_obj = JS_UNDEFINED; + m->promise = JS_UNDEFINED; + m->resolving_funcs[0] = JS_UNDEFINED; + m->resolving_funcs[1] = JS_UNDEFINED; list_add_tail(&m->link, &ctx->loaded_modules); return m; } @@ -27068,6 +27151,9 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkValue(rt, m->func_obj, mark_func); JS_MarkValue(rt, m->eval_exception, mark_func); JS_MarkValue(rt, m->meta_obj, mark_func); + JS_MarkValue(rt, m->promise, mark_func); + JS_MarkValue(rt, m->resolving_funcs[0], mark_func); + JS_MarkValue(rt, m->resolving_funcs[1], mark_func); } static void js_free_module_def(JSContext *ctx, JSModuleDef *m) @@ -27098,11 +27184,15 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) JS_FreeAtom(ctx, mi->import_name); } js_free(ctx, m->import_entries); + js_free(ctx, m->async_parent_modules); JS_FreeValue(ctx, m->module_ns); JS_FreeValue(ctx, m->func_obj); JS_FreeValue(ctx, m->eval_exception); JS_FreeValue(ctx, m->meta_obj); + JS_FreeValue(ctx, m->promise); + JS_FreeValue(ctx, m->resolving_funcs[0]); + JS_FreeValue(ctx, m->resolving_funcs[1]); list_del(&m->link); js_free(ctx, m); } @@ -27958,7 +28048,8 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) /* Prepare a module to be executed by resolving all the imported variables. */ -static int js_link_module(JSContext *ctx, JSModuleDef *m) +static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m, + JSModuleDef **pstack_top, int index) { int i; JSImportEntry *mi; @@ -27968,21 +28059,47 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) BOOL is_c_module; JSValue ret_val; - if (m->instantiated) - return 0; - m->instantiated = TRUE; - + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + #ifdef DUMP_MODULE_RESOLVE { char buf1[ATOM_GET_STR_BUF_SIZE]; - printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); } #endif + if (m->status == JS_MODULE_STATUS_LINKING || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) + return index; + + assert(m->status == JS_MODULE_STATUS_UNLINKED); + m->status = JS_MODULE_STATUS_LINKING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; - if (js_link_module(ctx, rme->module) < 0) + m1 = rme->module; + index = js_inner_module_linking(ctx, m1, pstack_top, index); + if (index < 0) goto fail; + assert(m1->status == JS_MODULE_STATUS_LINKING || + m1->status == JS_MODULE_STATUS_LINKED || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_LINKING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } } #ifdef DUMP_MODULE_RESOLVE @@ -28108,14 +28225,59 @@ static int js_link_module(JSContext *ctx, JSModuleDef *m) JS_FreeValue(ctx, ret_val); } + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + m1->status = JS_MODULE_STATUS_LINKED; + if (m1 == m) + break; + } + } + #ifdef DUMP_MODULE_RESOLVE - printf("done instantiate\n"); + printf("js_inner_module_linking done\n"); #endif - return 0; + return index; fail: return -1; } +/* Prepare a module to be executed by resolving all the imported + variables. */ +static int js_link_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *stack_top, *m1; + +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif + assert(m->status == JS_MODULE_STATUS_UNLINKED || + m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + stack_top = NULL; + if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_LINKING); + m1->status = JS_MODULE_STATUS_UNLINKED; + stack_top = m1->stack_prev; + } + return -1; + } + assert(stack_top == NULL); + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + return 0; +} + /* return JS_ATOM_NULL if the name cannot be found. Only works with not striped bytecode functions. */ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) @@ -28124,8 +28286,8 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) JSFunctionBytecode *b; JSObject *p; /* XXX: currently we just use the filename of the englobing - function. It does not work for eval(). Need to add a - ScriptOrModule info in JSFunctionBytecode */ + function from the debug info. May need to add a ScriptOrModule + info in JSFunctionBytecode. */ sf = ctx->rt->current_stack_frame; if (!sf) return JS_ATOM_NULL; @@ -28134,15 +28296,23 @@ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) if (!sf) return JS_ATOM_NULL; } - if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) - return JS_ATOM_NULL; - p = JS_VALUE_GET_OBJ(sf->cur_func); - if (!js_class_has_bytecode(p->class_id)) - return JS_ATOM_NULL; - b = p->u.func.function_bytecode; - if (!b->has_debug) - return JS_ATOM_NULL; - return JS_DupAtom(ctx, b->debug.filename); + for(;;) { + if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) + return JS_ATOM_NULL; + p = JS_VALUE_GET_OBJ(sf->cur_func); + if (!js_class_has_bytecode(p->class_id)) + return JS_ATOM_NULL; + b = p->u.func.function_bytecode; + if (!b->is_direct_or_indirect_eval) { + if (!b->has_debug) + return JS_ATOM_NULL; + return JS_DupAtom(ctx, b->debug.filename); + } else { + sf = sf->prev_frame; + if (!sf) + return JS_ATOM_NULL; + } + } } JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) @@ -28185,29 +28355,110 @@ static JSValue js_import_meta(JSContext *ctx) return JS_GetImportMeta(ctx, m); } -/* used by os.Worker() and import() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename) +static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m) +{ + return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); +} + +static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSValueConst error; + JSValue ret; + + /* XXX: check if the test is necessary */ + if (argc >= 1) + error = argv[0]; + else + error = JS_UNDEFINED; + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret); + return JS_UNDEFINED; +} + +static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) { + JSValueConst *resolving_funcs = (JSValueConst *)func_data; + JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]); + JSValue ret, ns; + + /* return the module namespace */ + ns = js_get_module_ns(ctx, m); + if (JS_IsException(ns)) { + JSValue err = JS_GetException(ctx); + js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data); + return JS_UNDEFINED; + } + ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&ns); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, ns); + return JS_UNDEFINED; +} + +static void JS_LoadModuleInternal(JSContext *ctx, const char *basename, + const char *filename, + JSValueConst *resolving_funcs) +{ + JSValue evaluate_promise; JSModuleDef *m; - JSValue ret, func_obj; + JSValue ret, err, func_obj, evaluate_resolving_funcs[2]; + JSValueConst func_data[3]; m = js_host_resolve_imported_module(ctx, basename, filename); if (!m) - return NULL; + goto fail; if (js_resolve_module(ctx, m) < 0) { js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); - return NULL; + goto fail; } /* Evaluate the module code */ - func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); - ret = JS_EvalFunction(ctx, func_obj); - if (JS_IsException(ret)) - return NULL; + func_obj = JS_NewModuleValue(ctx, m); + evaluate_promise = JS_EvalFunction(ctx, func_obj); + if (JS_IsException(evaluate_promise)) { + fail: + err = JS_GetException(ctx); + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&err); + JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ + JS_FreeValue(ctx, err); + return; + } + + func_obj = JS_NewModuleValue(ctx, m); + func_data[0] = resolving_funcs[0]; + func_data[1] = resolving_funcs[1]; + func_data[2] = func_obj; + evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data); + evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data); + JS_FreeValue(ctx, func_obj); + ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs); JS_FreeValue(ctx, ret); - return m; + JS_FreeValue(ctx, evaluate_resolving_funcs[0]); + JS_FreeValue(ctx, evaluate_resolving_funcs[1]); + JS_FreeValue(ctx, evaluate_promise); +} + +/* Return a promise or an exception in case of memory error. Used by + os.Worker() */ +JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename) +{ + JSValue promise, resolving_funcs[2]; + + promise = JS_NewPromiseCapability(ctx, resolving_funcs); + if (JS_IsException(promise)) + return JS_EXCEPTION; + JS_LoadModuleInternal(ctx, basename, filename, + (JSValueConst *)resolving_funcs); + JS_FreeValue(ctx, resolving_funcs[0]); + JS_FreeValue(ctx, resolving_funcs[1]); + return promise; } static JSValue js_dynamic_import_job(JSContext *ctx, @@ -28216,9 +28467,8 @@ static JSValue js_dynamic_import_job(JSContext *ctx, JSValueConst *resolving_funcs = argv; JSValueConst basename_val = argv[2]; JSValueConst specifier = argv[3]; - JSModuleDef *m; const char *basename = NULL, *filename; - JSValue ret, err, ns; + JSValue ret, err; if (!JS_IsString(basename_val)) { JS_ThrowTypeError(ctx, "no function filename for import()"); @@ -28232,24 +28482,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx, if (!filename) goto exception; - m = JS_RunModule(ctx, basename, filename); + JS_LoadModuleInternal(ctx, basename, filename, + resolving_funcs); JS_FreeCString(ctx, filename); - if (!m) - goto exception; - - /* return the module namespace */ - ns = js_get_module_ns(ctx, m); - if (JS_IsException(ns)) - goto exception; - - ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, - 1, (JSValueConst *)&ns); - JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ - JS_FreeValue(ctx, ns); JS_FreeCString(ctx, basename); return JS_UNDEFINED; exception: - err = JS_GetException(ctx); ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1, (JSValueConst *)&err); @@ -28285,6 +28523,8 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) args[2] = basename_val; args[3] = specifier; + /* cannot run JS_LoadModuleInternal synchronously because it would + cause an unexpected recursion in js_evaluate_module() */ JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); JS_FreeValue(ctx, basename_val); @@ -28293,60 +28533,397 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) return promise; } -/* Run the function of the module and of all its requested - modules. */ -static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m) +{ + m->status = JS_MODULE_STATUS_EVALUATED; + if (!JS_IsUndefined(m->promise)) { + JSValue value, ret_val; + assert(m->cycle_root == m); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } +} + +typedef struct { + JSModuleDef **tab; + int count; + int size; +} ExecModuleList; + +/* XXX: slow. Could use a linked list instead of ExecModuleList */ +static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m) +{ + int i; + for(i = 0; i < exec_list->count; i++) { + if (exec_list->tab[i] == m) + return TRUE; + } + return FALSE; +} + +static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module, + ExecModuleList *exec_list) +{ + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + if (!find_in_exec_module_list(exec_list, m) && + !m->cycle_root->eval_has_exception) { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!m->eval_has_exception); + assert(m->async_evaluation); + assert(m->pending_async_dependencies > 0); + m->pending_async_dependencies--; + if (m->pending_async_dependencies == 0) { + if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) { + return -1; + } + exec_list->tab[exec_list->count++] = m; + if (!m->has_tla) { + if (gather_available_ancestors(ctx, m, exec_list)) + return -1; + } + } + } + } + return 0; +} + +static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque) +{ + JSModuleDef *m1 = *(JSModuleDef **)p1; + JSModuleDef *m2 = *(JSModuleDef **)p2; + return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) - + (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp); +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m); +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue); + +static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + JSValueConst error = argv[0]; + int i; + + if (js_check_stack_overflow(ctx->rt, 0)) + return JS_ThrowStackOverflow(ctx); + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + + module->eval_has_exception = TRUE; + module->eval_exception = JS_DupValue(ctx, error); + module->status = JS_MODULE_STATUS_EVALUATED; + + for(i = 0; i < module->async_parent_modules_count; i++) { + JSModuleDef *m = module->async_parent_modules[i]; + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + } + + if (!JS_IsUndefined(module->promise)) { + JSValue ret_val; + assert(module->cycle_root == module); + ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED, + 1, &error); + JS_FreeValue(ctx, ret_val); + } + return JS_UNDEFINED; +} + +static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int magic, JSValue *func_data) +{ + JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]); + ExecModuleList exec_list_s, *exec_list = &exec_list_s; + int i; + + if (module->status == JS_MODULE_STATUS_EVALUATED) { + assert(module->eval_has_exception); + return JS_UNDEFINED; + } + assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC); + assert(!module->eval_has_exception); + assert(module->async_evaluation); + module->async_evaluation = FALSE; + js_set_module_evaluated(ctx, module); + + exec_list->tab = NULL; + exec_list->count = 0; + exec_list->size = 0; + + if (gather_available_ancestors(ctx, module, exec_list) < 0) { + js_free(ctx, exec_list->tab); + return JS_EXCEPTION; + } + + /* sort by increasing async_evaluation timestamp */ + rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]), + exec_module_list_cmp, NULL); + + for(i = 0; i < exec_list->count; i++) { + JSModuleDef *m = exec_list->tab[i]; + if (m->status == JS_MODULE_STATUS_EVALUATED) { + assert(m->eval_has_exception); + } else if (m->has_tla) { + js_execute_async_module(ctx, m); + } else { + JSValue error; + if (js_execute_sync_module(ctx, m, &error) < 0) { + JSValue m_obj = JS_NewModuleValue(ctx, m); + js_async_module_execution_rejected(ctx, JS_UNDEFINED, + 1, (JSValueConst *)&error, 0, + &m_obj); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, error); + } else { + js_set_module_evaluated(ctx, m); + } + } + } + js_free(ctx, exec_list->tab); + return JS_UNDEFINED; +} + +static int js_execute_async_module(JSContext *ctx, JSModuleDef *m) +{ + JSValue promise, m_obj; + JSValue resolve_funcs[2], ret_val; + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + return -1; + m_obj = JS_NewModuleValue(ctx, m); + resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj); + resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj); + ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs); + JS_FreeValue(ctx, ret_val); + JS_FreeValue(ctx, m_obj); + JS_FreeValue(ctx, resolve_funcs[0]); + JS_FreeValue(ctx, resolve_funcs[1]); + JS_FreeValue(ctx, promise); + return 0; +} + +/* return < 0 in case of exception. *pvalue contains the exception. */ +static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m, + JSValue *pvalue) +{ + if (m->init_func) { + /* C module init : no asynchronous execution */ + if (m->init_func(ctx, m) < 0) + goto fail; + } else { + JSValue promise; + JSPromiseStateEnum state; + + promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0); + if (JS_IsException(promise)) + goto fail; + state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) { + JS_FreeValue(ctx, promise); + } else if (state == JS_PROMISE_REJECTED) { + *pvalue = JS_PromiseResult(ctx, promise); + JS_FreeValue(ctx, promise); + return -1; + } else { + JS_FreeValue(ctx, promise); + JS_ThrowTypeError(ctx, "promise is pending"); + fail: + *pvalue = JS_GetException(ctx); + return -1; + } + } + *pvalue = JS_UNDEFINED; + return 0; +} + +/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1, + exception) */ +static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m, + int index, JSModuleDef **pstack_top, + JSValue *pvalue) { JSModuleDef *m1; int i; - JSValue ret_val; - if (m->eval_mark) - return JS_UNDEFINED; /* avoid cycles */ + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + *pvalue = JS_GetException(ctx); + return -1; + } + +#ifdef DUMP_MODULE_RESOLVE + { + char buf1[ATOM_GET_STR_BUF_SIZE]; + printf("js_inner_module_evaluation '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name)); + } +#endif - if (m->evaluated) { - /* if the module was already evaluated, rethrow the exception - it raised */ + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { if (m->eval_has_exception) { - return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception)); + *pvalue = JS_DupValue(ctx, m->eval_exception); + return -1; } else { - return JS_UNDEFINED; + *pvalue = JS_UNDEFINED; + return index; } } + if (m->status == JS_MODULE_STATUS_EVALUATING) { + *pvalue = JS_UNDEFINED; + return index; + } + assert(m->status == JS_MODULE_STATUS_LINKED); - m->eval_mark = TRUE; - + m->status = JS_MODULE_STATUS_EVALUATING; + m->dfs_index = index; + m->dfs_ancestor_index = index; + m->pending_async_dependencies = 0; + index++; + /* push 'm' on stack */ + m->stack_prev = *pstack_top; + *pstack_top = m; + for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; m1 = rme->module; - if (!m1->eval_mark) { - ret_val = js_evaluate_module(ctx, m1); - if (JS_IsException(ret_val)) { - m->eval_mark = FALSE; - return ret_val; + index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue); + if (index < 0) + return -1; + assert(m1->status == JS_MODULE_STATUS_EVALUATING || + m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->status == JS_MODULE_STATUS_EVALUATING) { + m->dfs_ancestor_index = min_int(m->dfs_ancestor_index, + m1->dfs_ancestor_index); + } else { + m1 = m1->cycle_root; + assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m1->status == JS_MODULE_STATUS_EVALUATED); + if (m1->eval_has_exception) { + *pvalue = JS_DupValue(ctx, m1->eval_exception); + return -1; } - JS_FreeValue(ctx, ret_val); + } + if (m1->async_evaluation) { + m->pending_async_dependencies++; + if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) { + *pvalue = JS_GetException(ctx); + return -1; + } + m1->async_parent_modules[m1->async_parent_modules_count++] = m; } } - if (m->init_func) { - /* C module init */ - if (m->init_func(ctx, m) < 0) - ret_val = JS_EXCEPTION; - else - ret_val = JS_UNDEFINED; + if (m->pending_async_dependencies > 0) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + } else if (m->has_tla) { + assert(!m->async_evaluation); + m->async_evaluation = TRUE; + m->async_evaluation_timestamp = + ctx->rt->module_async_evaluation_next_timestamp++; + js_execute_async_module(ctx, m); } else { - ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL); - m->func_obj = JS_UNDEFINED; + if (js_execute_sync_module(ctx, m, pvalue) < 0) + return -1; } - if (JS_IsException(ret_val)) { - /* save the thrown exception value */ - m->eval_has_exception = TRUE; - m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception); + + assert(m->dfs_ancestor_index <= m->dfs_index); + if (m->dfs_index == m->dfs_ancestor_index) { + for(;;) { + /* pop m1 from stack */ + m1 = *pstack_top; + *pstack_top = m1->stack_prev; + if (!m1->async_evaluation) { + m1->status = JS_MODULE_STATUS_EVALUATED; + } else { + m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC; + } + /* spec bug: cycle_root must be assigned before the test */ + m1->cycle_root = m; + if (m1 == m) + break; + } } - m->eval_mark = FALSE; - m->evaluated = TRUE; - return ret_val; + *pvalue = JS_UNDEFINED; + return index; +} + +/* Run the function of the module and of all its requested + modules. Return a promise or an exception. */ +static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) +{ + JSModuleDef *m1, *stack_top; + JSValue ret_val, result; + + assert(m->status == JS_MODULE_STATUS_LINKED || + m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED) { + m = m->cycle_root; + } + /* a promise may be created only on the cycle_root of a cycle */ + if (!JS_IsUndefined(m->promise)) + return JS_DupValue(ctx, m->promise); + m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs); + if (JS_IsException(m->promise)) + return JS_EXCEPTION; + + stack_top = NULL; + if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) { + while (stack_top != NULL) { + m1 = stack_top; + assert(m1->status == JS_MODULE_STATUS_EVALUATING); + m1->status = JS_MODULE_STATUS_EVALUATED; + m1->eval_has_exception = TRUE; + m1->eval_exception = JS_DupValue(ctx, result); + m1->cycle_root = m; /* spec bug: should be present */ + stack_top = m1->stack_prev; + } + JS_FreeValue(ctx, result); + assert(m->status == JS_MODULE_STATUS_EVALUATED); + assert(m->eval_has_exception); + ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&m->eval_exception); + JS_FreeValue(ctx, ret_val); + } else { + assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC || + m->status == JS_MODULE_STATUS_EVALUATED); + assert(!m->eval_has_exception); + if (!m->async_evaluation) { + JSValue value; + assert(m->status == JS_MODULE_STATUS_EVALUATED); + value = JS_UNDEFINED; + ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED, + 1, (JSValueConst *)&value); + JS_FreeValue(ctx, ret_val); + } + assert(stack_top == NULL); + } + return JS_DupValue(ctx, m->promise); } static __exception JSAtom js_parse_from_clause(JSParseState *s) @@ -29700,6 +30277,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, case OP_scope_get_ref: dbuf_putc(bc, OP_undefined); /* fall thru */ + case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -29725,7 +30303,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s, } } else { if (s->vars[var_idx].is_lexical) { - dbuf_putc(bc, OP_get_loc_check); + if (op == OP_scope_get_var_checkthis) { + /* only used for 'this' return in derived class constructors */ + dbuf_putc(bc, OP_get_loc_checkthis); + } else { + dbuf_putc(bc, OP_get_loc_check); + } } else { dbuf_putc(bc, OP_get_loc); } @@ -30182,12 +30765,17 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s, /* obj func value */ dbuf_putc(bc, OP_call_method); dbuf_put_u16(bc, 1); + dbuf_putc(bc, OP_drop); } break; default: abort(); } break; + case OP_scope_in_private_field: + get_loc_or_ref(bc, is_ref, idx); + dbuf_putc(bc, OP_private_in); + break; default: abort(); } @@ -30306,12 +30894,13 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) is_arg_scope = (scope_idx == ARG_SCOPE_END); if (!is_arg_scope) { /* add unscoped variables */ + /* XXX: propagate is_const and var_kind too ? */ for(i = 0; i < fd->arg_count; i++) { vd = &fd->args[i]; if (vd->var_name != JS_ATOM_NULL) { get_closure_var(ctx, s, fd, - TRUE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + TRUE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } for(i = 0; i < fd->var_count; i++) { @@ -30321,8 +30910,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) vd->var_name != JS_ATOM__ret_ && vd->var_name != JS_ATOM_NULL) { get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + FALSE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } } else { @@ -30331,8 +30920,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s) /* do not close top level last result */ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) { get_closure_var(ctx, s, fd, - FALSE, i, vd->var_name, FALSE, FALSE, - JS_VAR_NORMAL); + FALSE, i, vd->var_name, FALSE, + vd->is_lexical, JS_VAR_NORMAL); } } } @@ -30864,6 +31453,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) dbuf_putc(&bc_out, op); dbuf_put_u16(&bc_out, s->scopes[scope].first + 1); break; + case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: case OP_scope_put_var: @@ -30893,6 +31483,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_scope_get_private_field: case OP_scope_get_private_field2: case OP_scope_put_private_field: + case OP_scope_in_private_field: { int ret; var_name = get_u32(bc_buf + pos + 1); @@ -31104,6 +31695,17 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) case OP_set_class_name: /* only used during parsing */ break; + + case OP_get_field_opt_chain: /* equivalent to OP_get_field */ + { + JSAtom name = get_u32(bc_buf + pos + 1); + dbuf_putc(&bc_out, OP_get_field); + dbuf_put_u32(&bc_out, name); + } + break; + case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */ + dbuf_putc(&bc_out, OP_get_array_el); + break; default: no_change: @@ -32236,6 +32838,7 @@ typedef struct StackSizeState { int bc_len; int stack_len_max; uint16_t *stack_level_tab; + int32_t *catch_pos_tab; int *pc_stack; int pc_stack_len; int pc_stack_size; @@ -32243,7 +32846,7 @@ typedef struct StackSizeState { /* 'op' is only used for error indication */ static __exception int ss_check(JSContext *ctx, StackSizeState *s, - int pos, int op, int stack_len) + int pos, int op, int stack_len, int catch_pos) { if ((unsigned)pos >= s->bc_len) { JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); @@ -32259,9 +32862,13 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s, if (s->stack_level_tab[pos] != 0xffff) { /* already explored: check that the stack size is consistent */ if (s->stack_level_tab[pos] != stack_len) { - JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)", + JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)", s->stack_level_tab[pos], stack_len, pos); return -1; + } else if (s->catch_pos_tab[pos] != catch_pos) { + JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)", + s->catch_pos_tab[pos], catch_pos, pos); + return -1; } else { return 0; } @@ -32269,7 +32876,8 @@ static __exception int ss_check(JSContext *ctx, StackSizeState *s, /* mark as explored and store the stack size */ s->stack_level_tab[pos] = stack_len; - + s->catch_pos_tab[pos] = catch_pos; + /* queue the new PC to explore */ if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]), &s->pc_stack_size, s->pc_stack_len + 1)) @@ -32283,7 +32891,7 @@ static __exception int compute_stack_size(JSContext *ctx, int *pstack_size) { StackSizeState s_s, *s = &s_s; - int i, diff, n_pop, pos_next, stack_len, pos, op; + int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level; const JSOpCode *oi; const uint8_t *bc_buf; @@ -32296,24 +32904,33 @@ static __exception int compute_stack_size(JSContext *ctx, return -1; for(i = 0; i < s->bc_len; i++) s->stack_level_tab[i] = 0xffff; - s->stack_len_max = 0; s->pc_stack = NULL; + s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) * + s->bc_len); + if (!s->catch_pos_tab) + goto fail; + + s->stack_len_max = 0; s->pc_stack_len = 0; s->pc_stack_size = 0; /* breadth-first graph exploration */ - if (ss_check(ctx, s, 0, OP_invalid, 0)) + if (ss_check(ctx, s, 0, OP_invalid, 0, -1)) goto fail; while (s->pc_stack_len > 0) { pos = s->pc_stack[--s->pc_stack_len]; stack_len = s->stack_level_tab[pos]; + catch_pos = s->catch_pos_tab[pos]; op = bc_buf[pos]; if (op == 0 || op >= OP_COUNT) { JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos); goto fail; } oi = &short_opcode_info(op); +#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64) + printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos); +#endif pos_next = pos + oi->size; if (pos_next > s->bc_len) { JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos); @@ -32369,55 +32986,104 @@ static __exception int compute_stack_size(JSContext *ctx, case OP_if_true8: case OP_if_false8: diff = (int8_t)bc_buf[pos + 1]; - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) goto fail; break; #endif case OP_if_true: case OP_if_false: - case OP_catch: diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) goto fail; break; case OP_gosub: diff = get_u32(bc_buf + pos + 1); - if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1)) + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos)) goto fail; break; case OP_with_get_var: case OP_with_delete_var: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos)) goto fail; break; case OP_with_make_ref: case OP_with_get_ref: case OP_with_get_ref_undef: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos)) goto fail; break; case OP_with_put_var: diff = get_u32(bc_buf + pos + 5); - if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1)) + if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos)) goto fail; break; - + case OP_catch: + diff = get_u32(bc_buf + pos + 1); + if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos)) + goto fail; + catch_pos = pos; + break; + case OP_for_of_start: + case OP_for_await_of_start: + catch_pos = pos; + break; + /* we assume the catch offset entry is only removed with + some op codes */ + case OP_drop: + catch_level = stack_len; + goto check_catch; + case OP_nip: + catch_level = stack_len - 1; + goto check_catch; + case OP_nip1: + catch_level = stack_len - 1; + goto check_catch; + case OP_iterator_close: + catch_level = stack_len + 2; + check_catch: + /* Note: for for_of_start/for_await_of_start we consider + the catch offset is on the first stack entry instead of + the thirst */ + if (catch_pos >= 0) { + int level; + level = s->stack_level_tab[catch_pos]; + if (bc_buf[catch_pos] != OP_catch) + level++; /* for_of_start, for_wait_of_start */ + /* catch_level = stack_level before op_catch is executed ? */ + if (catch_level == level) { + catch_pos = s->catch_pos_tab[catch_pos]; + } + } + break; + case OP_nip_catch: + if (catch_pos < 0) { + JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos); + goto fail; + } + stack_len = s->stack_level_tab[catch_pos]; + if (bc_buf[catch_pos] != OP_catch) + stack_len++; /* for_of_start, for_wait_of_start */ + stack_len++; /* no stack overflow is possible by construction */ + catch_pos = s->catch_pos_tab[catch_pos]; + break; default: break; } - if (ss_check(ctx, s, pos_next, op, stack_len)) + if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos)) goto fail; done_insn: ; } - js_free(ctx, s->stack_level_tab); js_free(ctx, s->pc_stack); + js_free(ctx, s->catch_pos_tab); + js_free(ctx, s->stack_level_tab); *pstack_size = s->stack_len_max; return 0; fail: - js_free(ctx, s->stack_level_tab); js_free(ctx, s->pc_stack); + js_free(ctx, s->catch_pos_tab); + js_free(ctx, s->stack_level_tab); *pstack_size = 0; return -1; } @@ -32662,6 +33328,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->super_allowed = fd->super_allowed; b->arguments_allowed = fd->arguments_allowed; b->backtrace_barrier = fd->backtrace_barrier; + b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT || + fd->eval_type == JS_EVAL_TYPE_INDIRECT); b->realm = JS_DupContext(ctx); add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); @@ -32944,8 +33612,9 @@ static __exception int js_parse_function_decl2(JSParseState *s, func_type == JS_PARSE_FUNC_EXPR && (func_kind & JS_FUNC_GENERATOR)) || (s->token.u.ident.atom == JS_ATOM_await && - func_type == JS_PARSE_FUNC_EXPR && - (func_kind & JS_FUNC_ASYNC))) { + ((func_type == JS_PARSE_FUNC_EXPR && + (func_kind & JS_FUNC_ASYNC)) || + func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) { return js_parse_error_reserved_identifier(s); } } @@ -33039,7 +33708,8 @@ static __exception int js_parse_function_decl2(JSParseState *s, func_type == JS_PARSE_FUNC_SETTER || func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR || func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); - fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW); + fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW && + func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT); fd->has_this_binding = fd->has_arguments_binding; fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR); if (func_type == JS_PARSE_FUNC_ARROW) { @@ -33047,6 +33717,11 @@ static __exception int js_parse_function_decl2(JSParseState *s, fd->super_call_allowed = fd->parent->super_call_allowed; fd->super_allowed = fd->parent->super_allowed; fd->arguments_allowed = fd->parent->arguments_allowed; + } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) { + fd->new_target_allowed = TRUE; // although new.target === undefined + fd->super_call_allowed = FALSE; + fd->super_allowed = TRUE; + fd->arguments_allowed = FALSE; } else { fd->new_target_allowed = TRUE; fd->super_call_allowed = fd->is_derived_class_constructor; @@ -33084,7 +33759,7 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (add_arg(ctx, fd, name) < 0) goto fail; fd->defined_arg_count = 1; - } else { + } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { if (s->token.val == '(') { int skip_bits; /* if there is an '=' inside the parameter list, we @@ -33305,8 +33980,10 @@ static __exception int js_parse_function_decl2(JSParseState *s, } } - if (js_parse_expect(s, '{')) - goto fail; + if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { + if (js_parse_expect(s, '{')) + goto fail; + } if (js_parse_directives(s)) goto fail; @@ -33336,9 +34013,15 @@ static __exception int js_parse_function_decl2(JSParseState *s, if (js_is_live_code(s)) { emit_return(s, FALSE); } -done: + done: s->cur_func = fd->parent; + /* Reparse identifiers after the function is terminated so that + the token is parsed in the englobing function. It could be done + by just using next_token() here for normal functions, but it is + necessary for arrow functions with an expression body. */ + reparse_ident_token(s); + /* create the function object */ { int idx; @@ -33493,9 +34176,9 @@ static __exception int js_parse_program(JSParseState *s) emit_op(s, OP_get_loc); emit_u16(s, fd->eval_ret_idx); - emit_op(s, OP_return); + emit_return(s, TRUE); } else { - emit_op(s, OP_return_undef); + emit_return(s, FALSE); } return 0; @@ -33538,7 +34221,6 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, ret_val = js_evaluate_module(ctx, m); if (JS_IsException(ret_val)) { fail: - js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED); return JS_EXCEPTION; } } else { @@ -33553,31 +34235,6 @@ JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj) return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL); } -static void skip_shebang(JSParseState *s) -{ - const uint8_t *p = s->buf_ptr; - int c; - - if (p[0] == '#' && p[1] == '!') { - p += 2; - while (p < s->buf_end) { - if (*p == '\n' || *p == '\r') { - break; - } else if (*p >= 0x80) { - c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); - if (c == CP_LS || c == CP_PS) { - break; - } else if (c == -1) { - p++; /* skip invalid UTF-8 */ - } - } else { - p++; - } - } - s->buf_ptr = p; - } -} - /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, const char *input, size_t input_len, @@ -33593,7 +34250,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, JSModuleDef *m; js_parse_init(ctx, s, input, input_len, filename); - skip_shebang(s); + skip_shebang(&s->buf_ptr, s->buf_end); eval_type = flags & JS_EVAL_TYPE_MASK; m = NULL; @@ -33651,6 +34308,10 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, goto fail; } fd->module = m; + if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) { + fd->in_function_body = TRUE; + fd->func_kind = JS_FUNC_ASYNC; + } s->is_module = (m != NULL); s->allow_html_comments = !s->is_module; @@ -33665,6 +34326,9 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, goto fail1; } + if (m != NULL) + m->has_tla = fd->has_await; + /* create the function object and all the enclosed functions */ fun_obj = js_create_function(ctx, fd); if (JS_IsException(fun_obj)) @@ -33674,7 +34338,7 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj, m->func_obj = fun_obj; if (js_resolve_module(ctx, m) < 0) goto fail1; - fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); + fun_obj = JS_NewModuleValue(ctx, m); } if (flags & JS_EVAL_FLAG_COMPILE_ONLY) { ret_val = fun_obj; @@ -33883,6 +34547,18 @@ typedef enum BCTagEnum { BC_TAG_OBJECT_REFERENCE, } BCTagEnum; +#ifdef CONFIG_BIGNUM +#define BC_BASE_VERSION 2 +#else +#define BC_BASE_VERSION 1 +#endif +#define BC_BE_VERSION 0x40 +#ifdef WORDS_BIGENDIAN +#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) +#else +#define BC_VERSION BC_BASE_VERSION +#endif + typedef struct BCWriterState { JSContext *ctx; DynBuf dbuf; @@ -34145,7 +34821,6 @@ static void JS_WriteString(BCWriterState *s, JSString *p) } } -#ifdef CONFIG_BIGNUM static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) { uint32_t tag, tag1; @@ -34160,12 +34835,14 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) case JS_TAG_BIG_INT: tag1 = BC_TAG_BIG_INT; break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: tag1 = BC_TAG_BIG_FLOAT; break; case JS_TAG_BIG_DECIMAL: tag1 = BC_TAG_BIG_DECIMAL; break; +#endif default: abort(); } @@ -34280,7 +34957,6 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) } return 0; } -#endif /* CONFIG_BIGNUM */ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj); @@ -34303,6 +34979,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_set_flags(&flags, &idx, b->arguments_allowed, 1); bc_set_flags(&flags, &idx, b->has_debug, 1); bc_set_flags(&flags, &idx, b->backtrace_barrier, 1); + bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1); assert(idx <= 16); bc_put_u16(s, flags); bc_put_u8(s, b->js_mode); @@ -34408,6 +35085,8 @@ static int JS_WriteModule(BCWriterState *s, JSValueConst obj) bc_put_atom(s, mi->import_name); bc_put_leb128(s, mi->req_module_idx); } + + bc_put_u8(s, m->has_tla); if (JS_WriteObjectRec(s, m->func_obj)) goto fail; @@ -34637,8 +35316,8 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) case JS_CLASS_NUMBER: case JS_CLASS_STRING: case JS_CLASS_BOOLEAN: -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_FLOAT: case JS_CLASS_BIG_DECIMAL: #endif @@ -34660,14 +35339,14 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) goto fail; } break; -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: case JS_TAG_BIG_DECIMAL: +#endif if (JS_WriteBigNum(s, obj)) goto fail; break; -#endif default: invalid_tag: JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag); @@ -35059,7 +35738,6 @@ static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b, return 0; } -#ifdef CONFIG_BIGNUM static JSValue JS_ReadBigNum(BCReaderState *s, int tag) { JSValue obj = JS_UNDEFINED; @@ -35079,12 +35757,14 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) case BC_TAG_BIG_INT: obj = JS_MKPTR(JS_TAG_BIG_INT, p); break; +#ifdef CONFIG_BIGNUM case BC_TAG_BIG_FLOAT: obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p); break; case BC_TAG_BIG_DECIMAL: obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p); break; +#endif default: abort(); } @@ -35191,7 +35871,6 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) JS_FreeValue(s->ctx, obj); return JS_EXCEPTION; } -#endif /* CONFIG_BIGNUM */ static JSValue JS_ReadObjectRec(BCReaderState *s); @@ -35241,6 +35920,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) bc.arguments_allowed = bc_get_flags(v16, &idx, 1); bc.has_debug = bc_get_flags(v16, &idx, 1); bc.backtrace_barrier = bc_get_flags(v16, &idx, 1); + bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1); bc.read_only_bytecode = s->is_rom_data; if (bc_get_u8(s, &v8)) goto fail; @@ -35419,7 +36099,7 @@ static JSValue JS_ReadModule(BCReaderState *s) m = js_new_module_def(ctx, module_name); if (!m) goto fail; - obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); + obj = JS_NewModuleValue(ctx, m); if (bc_get_leb128_int(s, &m->req_module_entries_count)) goto fail; if (m->req_module_entries_count != 0) { @@ -35492,6 +36172,10 @@ static JSValue JS_ReadModule(BCReaderState *s) } } + if (bc_get_u8(s, &v8)) + goto fail; + m->has_tla = (v8 != 0); + m->func_obj = JS_ReadObjectRec(s); if (JS_IsException(m->func_obj)) goto fail; @@ -35816,13 +36500,13 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) case BC_TAG_OBJECT_VALUE: obj = JS_ReadObjectValue(s); break; -#ifdef CONFIG_BIGNUM case BC_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case BC_TAG_BIG_FLOAT: case BC_TAG_BIG_DECIMAL: +#endif obj = JS_ReadBigNum(s, tag); break; -#endif case BC_TAG_OBJECT_REFERENCE: { uint32_t val; @@ -36254,10 +36938,10 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) case JS_TAG_OBJECT: case JS_TAG_EXCEPTION: return JS_DupValue(ctx, val); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT); goto set_value; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT); goto set_value; @@ -37449,6 +38133,7 @@ static const JSCFunctionListEntry js_object_funcs[] = { JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ), JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ), JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ), + JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ), JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ), JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ), JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ), @@ -37879,7 +38564,8 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic) { JSValue obj, msg, proto; - JSValueConst message; + JSValueConst message, options; + int arg_index; if (JS_IsUndefined(new_target)) new_target = JS_GetActiveFunction(ctx); @@ -37905,12 +38591,9 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, JS_FreeValue(ctx, proto); if (JS_IsException(obj)) return obj; - if (magic == JS_AGGREGATE_ERROR) { - message = argv[1]; - } else { - message = argv[0]; - } + arg_index = (magic == JS_AGGREGATE_ERROR); + message = argv[arg_index++]; if (!JS_IsUndefined(message)) { msg = JS_ToString(ctx, message); if (unlikely(JS_IsException(msg))) @@ -37919,6 +38602,22 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } + if (arg_index < argc) { + options = argv[arg_index]; + if (JS_IsObject(options)) { + int present = JS_HasProperty(ctx, options, JS_ATOM_cause); + if (present < 0) + goto exception; + if (present) { + JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause); + if (JS_IsException(cause)) + goto exception; + JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause, + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + } + } + } + if (magic == JS_AGGREGATE_ERROR) { JSValue error_list = iterator_to_array(ctx, argv[0]); if (JS_IsException(error_list)) @@ -38312,6 +39011,106 @@ static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj) return JS_IsArray(ctx, obj); } +static JSValue js_array_at(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue obj, ret; + int64_t len, idx; + JSValue *arrp; + uint32_t count; + + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + goto exception; + + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) { + ret = JS_UNDEFINED; + } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) { + ret = JS_DupValue(ctx, arrp[idx]); + } else { + int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret); + if (present < 0) + goto exception; + if (!present) + ret = JS_UNDEFINED; + } + JS_FreeValue(ctx, obj); + return ret; + exception: + JS_FreeValue(ctx, obj); + return JS_EXCEPTION; +} + +static JSValue js_array_with(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len, idx; + uint32_t count32; + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + goto exception; + + if (idx < 0) + idx = len + idx; + + if (idx < 0 || idx >= len) { + JS_ThrowRangeError(ctx, "out of bound"); + goto exception; + } + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + p = JS_VALUE_GET_OBJ(arr); + i = 0; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i < idx; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + *pval = JS_DupValue(ctx, argv[1]); + for (i++, pval++; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (; i < idx; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto fill_and_fail; + *pval = JS_DupValue(ctx, argv[1]); + for (i++, pval++; i < len; i++, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + fill_and_fail: + for (; i < len; i++, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -38810,13 +39609,21 @@ static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +enum { + special_find, + special_findIndex, + special_findLast, + special_findLastIndex, +}; + static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue obj, val, index_val, res; - int64_t len, k; + int64_t len, k, end; + int dir; index_val = JS_UNDEFINED; val = JS_UNDEFINED; @@ -38832,7 +39639,18 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + // TODO(bnoordhuis) add fast path for fast arrays + for(; k != end; k += dir) { index_val = JS_NewInt64(ctx, k); if (JS_IsException(index_val)) goto exception; @@ -38846,7 +39664,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); JS_FreeValue(ctx, obj); return index_val; @@ -38860,7 +39678,7 @@ static JSValue js_array_find(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, index_val); } JS_FreeValue(ctx, obj); - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -39111,6 +39929,61 @@ static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice() +// leaves holes in sparse arrays intact whereas a.toReversed() replaces them +// with undefined, thus in effect creating a dense array. +// Does not use Array[@@species], always returns a base Array. +static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len; + uint32_t count32; + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + + i = len - 1; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i >= 0; i--, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + // Query order is observable; test262 expects descending order. + for (; i >= 0; i--, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + // Exception; initialize remaining elements. + for (; i >= 0; i--, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + } + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int splice) { @@ -39218,6 +40091,92 @@ static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval, *last; + JSObject *p; + int64_t i, j, len, newlen, start, add, del; + uint32_t count32; + + pval = NULL; + last = NULL; + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + start = 0; + if (argc > 0) + if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len)) + goto exception; + + del = 0; + if (argc > 0) + del = len - start; + if (argc > 1) + if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0)) + goto exception; + + add = 0; + if (argc > 2) + add = argc - 2; + + newlen = len + add - del; + if (newlen > MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "invalid array length"); + goto exception; + } + + arr = js_allocate_fast_array(ctx, newlen); + if (JS_IsException(arr)) + goto exception; + + if (newlen <= 0) + goto done; + + p = JS_VALUE_GET_OBJ(arr); + pval = &p->u.array.u.values[0]; + last = &p->u.array.u.values[newlen]; + + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (i = 0; i < start; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (i = 0; i < start; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + for (j = 0; j < add; j++, pval++) + *pval = JS_DupValue(ctx, argv[2 + j]); + for (i += del; i < len; i++, pval++) + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) + goto exception; + } + + assert(pval == last); + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0) + goto exception; + +done: + ret = arr; + arr = JS_UNDEFINED; + +exception: + while (pval != last) + *pval++ = JS_UNDEFINED; + + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -39521,6 +40480,68 @@ static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } +// Note: a.toSorted() is a.slice().sort() with the twist that a.slice() +// leaves holes in sparse arrays intact whereas a.toSorted() replaces them +// with undefined, thus in effect creating a dense array. +// Does not use Array[@@species], always returns a base Array. +static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, obj, ret, *arrp, *pval; + JSObject *p; + int64_t i, len; + uint32_t count32; + int ok; + + ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]); + if (!ok) + return JS_ThrowTypeError(ctx, "not a function"); + + ret = JS_EXCEPTION; + arr = JS_UNDEFINED; + obj = JS_ToObject(ctx, this_val); + if (js_get_length64(ctx, &len, obj)) + goto exception; + + arr = js_allocate_fast_array(ctx, len); + if (JS_IsException(arr)) + goto exception; + + if (len > 0) { + p = JS_VALUE_GET_OBJ(arr); + i = 0; + pval = p->u.array.u.values; + if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) { + for (; i < len; i++, pval++) + *pval = JS_DupValue(ctx, arrp[i]); + } else { + for (; i < len; i++, pval++) { + if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) { + for (; i < len; i++, pval++) + *pval = JS_UNDEFINED; + goto exception; + } + } + } + + if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0) + goto exception; + } + + ret = js_array_sort(ctx, arr, argc, argv); + if (JS_IsException(ret)) + goto exception; + JS_FreeValue(ctx, ret); + + ret = arr; + arr = JS_UNDEFINED; + +exception: + JS_FreeValue(ctx, arr); + JS_FreeValue(ctx, obj); + return ret; +} + typedef struct JSArrayIteratorData { JSValue obj; JSIteratorKindEnum kind; @@ -39673,6 +40694,8 @@ static const JSCFunctionListEntry js_iterator_proto_funcs[] = { }; static const JSCFunctionListEntry js_array_proto_funcs[] = { + JS_CFUNC_DEF("at", 1, js_array_at ), + JS_CFUNC_DEF("with", 2, js_array_with ), JS_CFUNC_DEF("concat", 1, js_array_concat ), JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ), JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ), @@ -39682,8 +40705,10 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ), JS_CFUNC_DEF("fill", 1, js_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, special_findLastIndex ), JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ), JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ), JS_CFUNC_DEF("includes", 1, js_array_includes ), @@ -39695,9 +40720,12 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ), JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), JS_CFUNC_DEF("reverse", 0, js_array_reverse ), + JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ), JS_CFUNC_DEF("sort", 1, js_array_sort ), + JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), + JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ), JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ), JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ), JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ), @@ -39725,9 +40753,10 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, if (JS_IsException(val)) return val; switch(JS_VALUE_GET_TAG(val)) { -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { JSBigFloat *p = JS_VALUE_GET_PTR(val); double d; @@ -39736,6 +40765,7 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target, val = __JS_NewFloat64(ctx, d); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: val = JS_ToStringFree(ctx, val); if (JS_IsException(val)) @@ -40370,7 +41400,7 @@ static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val, } static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) + int argc, JSValueConst *argv, int is_at) { JSValue val, ret; JSString *p; @@ -40384,8 +41414,13 @@ static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, val); return JS_EXCEPTION; } + if (idx < 0 && is_at) + idx += p->len; if (idx < 0 || idx >= p->len) { - ret = js_new_string8(ctx, NULL, 0); + if (is_at) + ret = JS_UNDEFINED; + else + ret = js_new_string8(ctx, NULL, 0); } else { if (p->is_wide_char) c = p->u.str16[idx]; @@ -40498,6 +41533,84 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode) return index; } +/* return the position of the first invalid character in the string or + -1 if none */ +static int js_string_find_invalid_codepoint(JSString *p) +{ + int i, c; + if (!p->is_wide_char) + return -1; + for(i = 0; i < p->len; i++) { + c = p->u.str16[i]; + if (c >= 0xD800 && c <= 0xDFFF) { + if (c >= 0xDC00 || (i + 1) >= p->len) + return i; + c = p->u.str16[i + 1]; + if (c < 0xDC00 || c > 0xDFFF) + return i; + i++; + } + } + return -1; +} + +static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue str; + JSString *p; + BOOL ret; + + str = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(str)) + return JS_EXCEPTION; + p = JS_VALUE_GET_STRING(str); + ret = (js_string_find_invalid_codepoint(p) < 0); + JS_FreeValue(ctx, str); + return JS_NewBool(ctx, ret); +} + +static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue str, ret; + JSString *p; + int c, i; + + str = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(str)) + return JS_EXCEPTION; + + p = JS_VALUE_GET_STRING(str); + /* avoid reallocating the string if it is well-formed */ + i = js_string_find_invalid_codepoint(p); + if (i < 0) + return str; + + ret = js_new_string16(ctx, p->u.str16, p->len); + JS_FreeValue(ctx, str); + if (JS_IsException(ret)) + return JS_EXCEPTION; + + p = JS_VALUE_GET_STRING(ret); + for (; i < p->len; i++) { + c = p->u.str16[i]; + if (c >= 0xD800 && c <= 0xDFFF) { + if (c >= 0xDC00 || (i + 1) >= p->len) { + p->u.str16[i] = 0xFFFD; + } else { + c = p->u.str16[i + 1]; + if (c < 0xDC00 || c > 0xDFFF) { + p->u.str16[i] = 0xFFFD; + } else { + i++; + } + } + } + } + return ret; +} + static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int lastIndexOf) { @@ -41310,26 +42423,6 @@ static BOOL test_final_sigma(JSString *p, int sigma_pos) return !lre_is_cased(c1); } -static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue a, b; - int cmp; - - a = JS_ToStringCheckObject(ctx, this_val); - if (JS_IsException(a)) - return JS_EXCEPTION; - b = JS_ToString(ctx, argv[0]); - if (JS_IsException(b)) { - JS_FreeValue(ctx, a); - return JS_EXCEPTION; - } - cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); - JS_FreeValue(ctx, a); - JS_FreeValue(ctx, b); - return JS_NewInt32(ctx, cmp); -} - static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int to_lower) { @@ -41415,23 +42508,38 @@ static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len) return JS_EXCEPTION; } +static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf, + JSValueConst val, + UnicodeNormalizationEnum n_type) +{ + int buf_len, out_len; + uint32_t *buf, *out_buf; + + buf_len = JS_ToUTF32String(ctx, &buf, val); + if (buf_len < 0) + return -1; + out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, + ctx->rt, (DynBufReallocFunc *)js_realloc_rt); + js_free(ctx, buf); + if (out_len < 0) + return -1; + *pout_buf = out_buf; + return out_len; +} + static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { const char *form, *p; size_t form_len; - int is_compat, buf_len, out_len; + int is_compat, out_len; UnicodeNormalizationEnum n_type; JSValue val; - uint32_t *buf, *out_buf; + uint32_t *out_buf; val = JS_ToStringCheckObject(ctx, this_val); if (JS_IsException(val)) return val; - buf_len = JS_ToUTF32String(ctx, &buf, val); - JS_FreeValue(ctx, val); - if (buf_len < 0) - return JS_EXCEPTION; if (argc == 0 || JS_IsUndefined(argv[0])) { n_type = UNICODE_NFC; @@ -41457,22 +42565,96 @@ static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val, JS_FreeCString(ctx, form); JS_ThrowRangeError(ctx, "bad normalization form"); fail1: - js_free(ctx, buf); + JS_FreeValue(ctx, val); return JS_EXCEPTION; } JS_FreeCString(ctx, form); } - out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, - ctx->rt, (DynBufReallocFunc *)js_realloc_rt); - js_free(ctx, buf); + out_len = js_string_normalize1(ctx, &out_buf, val, n_type); + JS_FreeValue(ctx, val); if (out_len < 0) return JS_EXCEPTION; val = JS_NewUTF32String(ctx, out_buf, out_len); js_free(ctx, out_buf); return val; } -#endif /* CONFIG_ALL_UNICODE */ + +/* return < 0, 0 or > 0 */ +static int js_UTF32_compare(const uint32_t *buf1, int buf1_len, + const uint32_t *buf2, int buf2_len) +{ + int i, len, c, res; + len = min_int(buf1_len, buf2_len); + for(i = 0; i < len; i++) { + /* Note: range is limited so a subtraction is valid */ + c = buf1[i] - buf2[i]; + if (c != 0) + return c; + } + if (buf1_len == buf2_len) + res = 0; + else if (buf1_len < buf2_len) + res = -1; + else + res = 1; + return res; +} + +static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue a, b; + int cmp, a_len, b_len; + uint32_t *a_buf, *b_buf; + + a = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(a)) + return JS_EXCEPTION; + b = JS_ToString(ctx, argv[0]); + if (JS_IsException(b)) { + JS_FreeValue(ctx, a); + return JS_EXCEPTION; + } + a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC); + JS_FreeValue(ctx, a); + if (a_len < 0) { + JS_FreeValue(ctx, b); + return JS_EXCEPTION; + } + + b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC); + JS_FreeValue(ctx, b); + if (b_len < 0) { + js_free(ctx, a_buf); + return JS_EXCEPTION; + } + cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len); + js_free(ctx, a_buf); + js_free(ctx, b_buf); + return JS_NewInt32(ctx, cmp); +} +#else /* CONFIG_ALL_UNICODE */ +static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue a, b; + int cmp; + + a = JS_ToStringCheckObject(ctx, this_val); + if (JS_IsException(a)) + return JS_EXCEPTION; + b = JS_ToString(ctx, argv[0]); + if (JS_IsException(b)) { + JS_FreeValue(ctx, a); + return JS_EXCEPTION; + } + cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b)); + JS_FreeValue(ctx, a); + JS_FreeValue(ctx, b); + return JS_NewInt32(ctx, cmp); +} +#endif /* !CONFIG_ALL_UNICODE */ /* also used for String.prototype.valueOf */ static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val, @@ -41644,10 +42826,13 @@ static const JSCFunctionListEntry js_string_funcs[] = { static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ), + JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ), JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ), - JS_CFUNC_DEF("charAt", 1, js_string_charAt ), + JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ), JS_CFUNC_DEF("concat", 1, js_string_concat ), JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ), + JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ), + JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ), JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ), JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ), JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ), @@ -41934,30 +43119,30 @@ static const JSCFunctionListEntry js_math_funcs[] = { JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ), JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ), - // JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ), - // JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ), - // JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ), - // JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ), - // JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ), - // JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ), + JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ), + JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ), + JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ), + JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ), + JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ), + JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ), JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ), JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ), - // JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ), - // JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ), + JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ), + JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ), /* ES6 */ JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ), JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ), - // JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ), - // JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ), - // JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ), - // JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ), - // JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ), - // JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ), - // JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ), - // JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ), - // JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ), - // JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ), - // JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ), + JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ), + JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ), + JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ), + JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ), + JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ), + JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ), + JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ), + JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ), + JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ), + JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ), + JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ), JS_CFUNC_DEF("hypot", 2, js_math_hypot ), JS_CFUNC_DEF("random", 0, js_math_random ), JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ), @@ -41980,40 +43165,13 @@ static const JSCFunctionListEntry js_math_obj[] = { /* Date */ -#if 0 -/* OS dependent: return the UTC time in ms since 1970. */ -static JSValue js___date_now(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); - return JS_NewInt64(ctx, d); -} -#endif - -/* OS dependent: return the UTC time in microseconds since 1970. */ -static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - int64_t d; - struct timeval tv; - gettimeofday(&tv, NULL); - d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; - return JS_NewInt64(ctx, d); -} - /* OS dependent. d = argv[0] is in ms from 1970. Return the difference between UTC time and local time 'd' in minutes */ -static int getTimezoneOffset(int64_t time) { -#if defined(_WIN32) - /* XXX: TODO */ - return 0; -#else +static int getTimezoneOffset(int64_t time) +{ time_t ti; - struct tm tm; - + int res; + time /= 1000; /* convert to seconds */ if (sizeof(time_t) == 4) { /* on 32-bit systems, we need to clamp the time value to the @@ -42036,9 +43194,27 @@ static int getTimezoneOffset(int64_t time) { } } ti = time; - localtime_r(&ti, &tm); - return -tm.tm_gmtoff / 60; +#if defined(_WIN32) + { + struct tm *tm; + time_t gm_ti, loc_ti; + + tm = gmtime(&ti); + gm_ti = mktime(tm); + + tm = localtime(&ti); + loc_ti = mktime(tm); + + res = (gm_ti - loc_ti) / 60; + } +#else + { + struct tm tm; + localtime_r(&ti, &tm); + res = -tm.tm_gmtoff / 60; + } #endif + return res; } #if 0 @@ -42115,6 +43291,9 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */ for (i = 0; i < len; i++) { switch(str[i]) { + case 'd': + mask = LRE_FLAG_INDICES; + break; case 'g': mask = LRE_FLAG_GLOBAL; break; @@ -42458,6 +43637,11 @@ static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val) if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT) return JS_ThrowTypeErrorNotAnObject(ctx); + res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "hasIndices")); + if (res < 0) + goto exception; + if (res) + *p++ = 'd'; res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global)); if (res < 0) goto exception; @@ -42537,25 +43721,32 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, { JSRegExp *re = js_get_regexp(ctx, this_val, TRUE); JSString *str; - JSValue str_val, obj, val, groups = JS_UNDEFINED; + JSValue t, ret, str_val, obj, val, groups; + JSValue indices, indices_groups; uint8_t *re_bytecode; - int ret; uint8_t **capture, *str_buf; - int capture_count, shift, i, re_flags; + int rc, capture_count, shift, i, re_flags; int64_t last_index; const char *group_name_ptr; if (!re) return JS_EXCEPTION; + str_val = JS_ToString(ctx, argv[0]); if (JS_IsException(str_val)) - return str_val; - val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); - if (JS_IsException(val) || - JS_ToLengthFree(ctx, &last_index, val)) { - JS_FreeValue(ctx, str_val); return JS_EXCEPTION; - } + + ret = JS_EXCEPTION; + obj = JS_NULL; + groups = JS_UNDEFINED; + indices = JS_UNDEFINED; + indices_groups = JS_UNDEFINED; + capture = NULL; + + val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex); + if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val)) + goto fail; + re_bytecode = re->bytecode->u.str8; re_flags = lre_get_flags(re_bytecode); if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) { @@ -42563,27 +43754,23 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, } str = JS_VALUE_GET_STRING(str_val); capture_count = lre_get_capture_count(re_bytecode); - capture = NULL; if (capture_count > 0) { capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2); - if (!capture) { - JS_FreeValue(ctx, str_val); - return JS_EXCEPTION; - } + if (!capture) + goto fail; } shift = str->is_wide_char; str_buf = str->u.str8; if (last_index > str->len) { - ret = 2; + rc = 2; } else { - ret = lre_exec(capture, re_bytecode, - str_buf, last_index, str->len, - shift, ctx); + rc = lre_exec(capture, re_bytecode, + str_buf, last_index, str->len, + shift, ctx); } - obj = JS_NULL; - if (ret != 1) { - if (ret >= 0) { - if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { + if (rc != 1) { + if (rc >= 0) { + if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) { if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) goto fail; @@ -42592,7 +43779,6 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, JS_ThrowInternalError(ctx, "out of memory in regexp execution"); goto fail; } - JS_FreeValue(ctx, str_val); } else { int prop_flags; if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) { @@ -42610,52 +43796,124 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, if (JS_IsException(groups)) goto fail; } + if (re_flags & LRE_FLAG_INDICES) { + indices = JS_NewArray(ctx); + if (JS_IsException(indices)) + goto fail; + if (group_name_ptr) { + indices_groups = JS_NewObjectProto(ctx, JS_NULL); + if (JS_IsException(indices_groups)) + goto fail; + } + } for(i = 0; i < capture_count; i++) { - int start, end; + const char *name = NULL; + uint8_t **match = &capture[2 * i]; + int start = -1; + int end = -1; JSValue val; - if (capture[2 * i] == NULL || - capture[2 * i + 1] == NULL) { + + if (group_name_ptr && i > 0) { + if (*group_name_ptr) name = group_name_ptr; + group_name_ptr += strlen(group_name_ptr) + 1; + } + + if (match[0] && match[1]) { + start = (match[0] - str_buf) >> shift; + end = (match[1] - str_buf) >> shift; + } + + if (!JS_IsUndefined(indices)) { val = JS_UNDEFINED; - } else { - start = (capture[2 * i] - str_buf) >> shift; - end = (capture[2 * i + 1] - str_buf) >> shift; + if (start != -1) { + val = JS_NewArray(ctx); + if (JS_IsException(val)) + goto fail; + if (JS_DefinePropertyValueUint32(ctx, val, 0, + JS_NewInt32(ctx, start), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + if (JS_DefinePropertyValueUint32(ctx, val, 1, + JS_NewInt32(ctx, end), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + } + if (name && !JS_IsUndefined(indices_groups)) { + val = JS_DupValue(ctx, val); + if (JS_DefinePropertyValueStr(ctx, indices_groups, + name, val, prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; + } + } + if (JS_DefinePropertyValueUint32(ctx, indices, i, val, + prop_flags) < 0) { + goto fail; + } + } + + val = JS_UNDEFINED; + if (start != -1) { val = js_sub_string(ctx, str, start, end); if (JS_IsException(val)) goto fail; } - if (group_name_ptr && i > 0) { - if (*group_name_ptr) { - if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr, - JS_DupValue(ctx, val), - prop_flags) < 0) { - JS_FreeValue(ctx, val); - goto fail; - } + + if (name) { + if (JS_DefinePropertyValueStr(ctx, groups, name, + JS_DupValue(ctx, val), + prop_flags) < 0) { + JS_FreeValue(ctx, val); + goto fail; } - group_name_ptr += strlen(group_name_ptr) + 1; } + if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0) goto fail; } + + t = groups, groups = JS_UNDEFINED; if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups, - groups, prop_flags) < 0) + t, prop_flags) < 0) { goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, - JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0) + } + + t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift); + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0) goto fail; - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0) - goto fail1; + + t = str_val, str_val = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0) + goto fail; + + if (!JS_IsUndefined(indices)) { + t = indices_groups, indices_groups = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups, + t, prop_flags) < 0) { + goto fail; + } + t = indices, indices = JS_UNDEFINED; + if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices, + t, prop_flags) < 0) { + goto fail; + } + } } - js_free(ctx, capture); - return obj; + ret = obj; + obj = JS_UNDEFINED; fail: - JS_FreeValue(ctx, groups); + JS_FreeValue(ctx, indices_groups); + JS_FreeValue(ctx, indices); JS_FreeValue(ctx, str_val); -fail1: + JS_FreeValue(ctx, groups); JS_FreeValue(ctx, obj); js_free(ctx, capture); - return JS_EXCEPTION; + return ret; } /* delete portions of a string that match a given regex */ @@ -42807,7 +44065,7 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, { // [Symbol.match](str) JSValueConst rx = this_val; - JSValue A, S, result, matchStr; + JSValue A, S, flags, result, matchStr; int global, n, fullUnicode, isEmpty; JSString *p; @@ -42815,16 +44073,23 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, return JS_ThrowTypeErrorNotAnObject(ctx); A = JS_UNDEFINED; + flags = JS_UNDEFINED; result = JS_UNDEFINED; matchStr = JS_UNDEFINED; S = JS_ToString(ctx, argv[0]); if (JS_IsException(S)) goto exception; - global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (global < 0) + flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); + if (JS_IsException(flags)) goto exception; + flags = JS_ToStringFree(ctx, flags); + if (JS_IsException(flags)) + goto exception; + p = JS_VALUE_GET_STRING(flags); + // TODO(bnoordhuis) query 'u' flag the same way? + global = (-1 != string_indexof_char(p, 'g', 0)); if (!global) { A = JS_RegExpExec(ctx, rx, S); } else { @@ -42868,12 +44133,14 @@ static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, } } JS_FreeValue(ctx, result); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, S); return A; exception: JS_FreeValue(ctx, A); JS_FreeValue(ctx, result); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, S); return JS_EXCEPTION; } @@ -43116,8 +44383,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, // [Symbol.replace](str, rep) JSValueConst rx = this_val, rep = argv[1]; JSValueConst args[6]; - JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res; - JSString *sp, *rp; + JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res; + JSString *p, *sp, *rp; StringBuffer b_s, *b = &b_s; ValueBuffer v_b, *results = &v_b; int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode; @@ -43133,6 +44400,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, rep_val = JS_UNDEFINED; matched = JS_UNDEFINED; tab = JS_UNDEFINED; + flags = JS_UNDEFINED; rep_str = JS_UNDEFINED; namedCaptures = JS_UNDEFINED; @@ -43149,10 +44417,18 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, goto exception; rp = JS_VALUE_GET_STRING(rep_val); } - fullUnicode = 0; - is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global)); - if (is_global < 0) + + flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); + if (JS_IsException(flags)) goto exception; + flags = JS_ToStringFree(ctx, flags); + if (JS_IsException(flags)) + goto exception; + p = JS_VALUE_GET_STRING(flags); + + // TODO(bnoordhuis) query 'u' flag the same way? + fullUnicode = 0; + is_global = (-1 != string_indexof_char(p, 'g', 0)); if (is_global) { fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode)); if (fullUnicode < 0) @@ -43286,6 +44562,7 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, value_buffer_free(results); JS_FreeValue(ctx, rep_val); JS_FreeValue(ctx, matched); + JS_FreeValue(ctx, flags); JS_FreeValue(ctx, tab); JS_FreeValue(ctx, rep_str); JS_FreeValue(ctx, namedCaptures); @@ -43486,12 +44763,13 @@ static const JSCFunctionListEntry js_regexp_funcs[] = { static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ), JS_CGETSET_DEF("source", js_regexp_get_source, NULL ), - JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ), - JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ), - JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ), - JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ), - JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ), - JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ), + JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ), + JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ), + JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ), + JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ), + JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UTF16 ), + JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ), + JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ), JS_CFUNC_DEF("exec", 1, js_regexp_exec ), JS_CFUNC_DEF("compile", 2, js_regexp_compile ), JS_CFUNC_DEF("test", 1, js_regexp_test ), @@ -43828,10 +45106,8 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, JSValue v; JSValueConst args[2]; - if (JS_IsObject(val) -#ifdef CONFIG_BIGNUM - || JS_IsBigInt(ctx, val) /* XXX: probably useless */ -#endif + if (JS_IsObject(val) || + JS_IsBigInt(ctx, val) /* XXX: probably useless */ ) { JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); if (JS_IsException(f)) @@ -43869,9 +45145,7 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, #endif case JS_TAG_BOOL: case JS_TAG_NULL: -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: -#endif case JS_TAG_EXCEPTION: return val; default: @@ -43922,15 +45196,16 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, ret = string_buffer_concat_value(jsc->b, p->u.object_data); JS_FreeValue(ctx, val); return ret; - } + } else #ifdef CONFIG_BIGNUM - else if (cl == JS_CLASS_BIG_FLOAT) { + if (cl == JS_CLASS_BIG_FLOAT) { return string_buffer_concat_value_free(jsc->b, val); - } else if (cl == JS_CLASS_BIG_INT) { + } else +#endif + if (cl == JS_CLASS_BIG_INT) { JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); goto exception; } -#endif v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val); if (JS_IsException(v)) goto exception; @@ -44060,11 +45335,9 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc, case JS_TAG_NULL: concat_value: return string_buffer_concat_value_free(jsc->b, val); -#ifdef CONFIG_BIGNUM case JS_TAG_BIG_INT: JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify"); goto exception; -#endif default: JS_FreeValue(ctx, val); return 0; @@ -44354,8 +45627,8 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_SetPropertyGeneric(ctx, obj, atom, - JS_DupValue(ctx, val), receiver, 0); + ret = JS_SetPropertyInternal(ctx, obj, atom, + JS_DupValue(ctx, val), receiver, 0); JS_FreeAtom(ctx, atom); if (ret < 0) return JS_EXCEPTION; @@ -44702,9 +45975,9 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom, if (!s) return -1; if (JS_IsUndefined(method)) { - return JS_SetPropertyGeneric(ctx, s->target, atom, - JS_DupValue(ctx, value), receiver, - flags); + return JS_SetPropertyInternal(ctx, s->target, atom, + JS_DupValue(ctx, value), receiver, + flags); } atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { @@ -45237,6 +46510,10 @@ static int js_proxy_isArray(JSContext *ctx, JSValueConst obj) JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY); if (!s) return FALSE; + if (js_check_stack_overflow(ctx->rt, 0)) { + JS_ThrowStackOverflow(ctx); + return -1; + } if (s->is_revoked) { JS_ThrowTypeErrorRevokedProxy(ctx); return -1; @@ -45962,6 +47239,123 @@ static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } +static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int is_map) +{ + JSValueConst cb, args[2]; + JSValue res, iter, next, groups, key, v, prop; + JSAtom key_atom = JS_ATOM_NULL; + int64_t idx; + BOOL done; + + // "is function?" check must be observed before argv[0] is accessed + cb = argv[1]; + if (check_function(ctx, cb)) + return JS_EXCEPTION; + + iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE); + if (JS_IsException(iter)) + return JS_EXCEPTION; + + key = JS_UNDEFINED; + key_atom = JS_ATOM_NULL; + v = JS_UNDEFINED; + prop = JS_UNDEFINED; + groups = JS_UNDEFINED; + + next = JS_GetProperty(ctx, iter, JS_ATOM_next); + if (JS_IsException(next)) + goto exception; + + if (is_map) { + groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0); + } else { + groups = JS_NewObjectProto(ctx, JS_NULL); + } + if (JS_IsException(groups)) + goto exception; + + for (idx = 0; ; idx++) { + if (idx >= MAX_SAFE_INTEGER) { + JS_ThrowTypeError(ctx, "too many elements"); + goto iterator_close_exception; + } + v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done); + if (JS_IsException(v)) + goto exception; + if (done) + break; // v is JS_UNDEFINED + + args[0] = v; + args[1] = JS_NewInt64(ctx, idx); + key = JS_Call(ctx, cb, ctx->global_obj, 2, args); + if (JS_IsException(key)) + goto iterator_close_exception; + + if (is_map) { + prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0); + } else { + key_atom = JS_ValueToAtom(ctx, key); + JS_FreeValue(ctx, key); + key = JS_UNDEFINED; + if (key_atom == JS_ATOM_NULL) + goto iterator_close_exception; + prop = JS_GetProperty(ctx, groups, key_atom); + } + if (JS_IsException(prop)) + goto exception; + + if (JS_IsUndefined(prop)) { + prop = JS_NewArray(ctx); + if (JS_IsException(prop)) + goto exception; + if (is_map) { + args[0] = key; + args[1] = prop; + res = js_map_set(ctx, groups, 2, args, 0); + if (JS_IsException(res)) + goto exception; + JS_FreeValue(ctx, res); + } else { + prop = JS_DupValue(ctx, prop); + if (JS_DefinePropertyValue(ctx, groups, key_atom, prop, + JS_PROP_C_W_E) < 0) { + goto exception; + } + } + } + res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0); + if (JS_IsException(res)) + goto exception; + // res is an int64 + + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, key); + JS_FreeAtom(ctx, key_atom); + JS_FreeValue(ctx, v); + prop = JS_UNDEFINED; + key = JS_UNDEFINED; + key_atom = JS_ATOM_NULL; + v = JS_UNDEFINED; + } + + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return groups; + + iterator_close_exception: + JS_IteratorClose(ctx, iter, TRUE); + exception: + JS_FreeAtom(ctx, key_atom); + JS_FreeValue(ctx, prop); + JS_FreeValue(ctx, key); + JS_FreeValue(ctx, v); + JS_FreeValue(ctx, groups); + JS_FreeValue(ctx, iter); + JS_FreeValue(ctx, next); + return JS_EXCEPTION; +} + static void js_map_finalizer(JSRuntime *rt, JSValue val) { JSObject *p; @@ -46142,6 +47536,7 @@ static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val, } static const JSCFunctionListEntry js_map_funcs[] = { + JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ), }; @@ -46262,12 +47657,6 @@ static const JSCFunctionListEntry js_generator_proto_funcs[] = { /* Promise */ -typedef enum JSPromiseStateEnum { - JS_PROMISE_PENDING, - JS_PROMISE_FULFILLED, - JS_PROMISE_REJECTED, -} JSPromiseStateEnum; - typedef struct JSPromiseData { JSPromiseStateEnum promise_state; /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */ @@ -46292,6 +47681,22 @@ typedef struct JSPromiseReactionData { JSValue handler; } JSPromiseReactionData; +JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise) +{ + JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); + if (!s) + return -1; + return s->promise_state; +} + +JSValue JS_PromiseResult(JSContext *ctx, JSValue promise) +{ + JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE); + if (!s) + return JS_UNDEFINED; + return JS_DupValue(ctx, s->promise_result); +} + static int js_create_resolving_functions(JSContext *ctx, JSValue *args, JSValueConst promise); @@ -46737,17 +48142,14 @@ static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val, return result_promise; } -#if 0 -static JSValue js_promise___newPromiseCapability(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv) +static JSValue js_promise_withResolvers(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv) { JSValue result_promise, resolving_funcs[2], obj; - JSValueConst ctor; - ctor = argv[0]; - if (!JS_IsObject(ctor)) + if (!JS_IsObject(this_val)) return JS_ThrowTypeErrorNotAnObject(ctx); - result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor); + result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val); if (JS_IsException(result_promise)) return result_promise; obj = JS_NewObject(ctx); @@ -46762,7 +48164,6 @@ static JSValue js_promise___newPromiseCapability(JSContext *ctx, JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E); return obj; } -#endif static __exception int remainingElementsCount_add(JSContext *ctx, JSValueConst resolve_element_env, @@ -47252,7 +48653,7 @@ static const JSCFunctionListEntry js_promise_funcs[] = { JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ), JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ), JS_CFUNC_DEF("race", 1, js_promise_race ), - //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ), + JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL), }; @@ -47863,12 +49264,6 @@ static const JSCFunctionListEntry js_global_funcs[] = { JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ), JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ), JS_PROP_UNDEFINED_DEF("undefined", 0 ), - - /* for the 'Date' implementation */ - JS_CFUNC_DEF("__date_clock", 0, js___date_clock ), - //JS_CFUNC_DEF("__date_now", 0, js___date_now ), - //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ), - //JS_CFUNC_DEF("__date_create", 3, js___date_create ), }; /* Date */ @@ -48074,20 +49469,19 @@ static JSValue set_date_field(JSContext *ctx, JSValueConst this_val, res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0); if (res < 0) return JS_EXCEPTION; + + // Argument coercion is observable and must be done unconditionally. + n = min_int(argc, end_field - first_field); + for(i = 0; i < n; i++) { + if (JS_ToFloat64(ctx, &a, argv[i])) + return JS_EXCEPTION; + if (!isfinite(a)) + res = FALSE; + fields[first_field + i] = trunc(a); + } if (res && argc > 0) { - n = end_field - first_field; - if (argc < n) - n = argc; - for(i = 0; i < n; i++) { - if (JS_ToFloat64(ctx, &a, argv[i])) - return JS_EXCEPTION; - if (!isfinite(a)) - goto done; - fields[first_field + i] = trunc(a); - } d = set_date_fields(fields, is_local); } -done: return JS_SetThisTimeValue(ctx, this_val, d); } @@ -48197,7 +49591,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, break; case 3: pos += snprintf(buf + pos, sizeof(buf) - pos, - "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s, + "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s, (h < 12) ? 'A' : 'P'); break; } @@ -48209,8 +49603,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val, static int64_t date_now(void) { struct timeval tv; gettimeofday(&tv, NULL); - // return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); - return 0; + return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000); } static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target, @@ -48359,8 +49752,11 @@ static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) { p++; res = string_get_digits(sp, &p, pval); - if (res == 0 && sgn == '-') + if (res == 0 && sgn == '-') { + if (*pval == 0) + return -1; // reject negative zero *pval = -*pval; + } *pp = p; return res; } @@ -48737,59 +50133,59 @@ static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val, } static const JSCFunctionListEntry js_date_funcs[] = { - // JS_CFUNC_DEF("now", 0, js_Date_now ), - // JS_CFUNC_DEF("parse", 1, js_Date_parse ), - // JS_CFUNC_DEF("UTC", 7, js_Date_UTC ), + JS_CFUNC_DEF("now", 0, js_Date_now ), + JS_CFUNC_DEF("parse", 1, js_Date_parse ), + JS_CFUNC_DEF("UTC", 7, js_Date_UTC ), }; static const JSCFunctionListEntry js_date_proto_funcs[] = { - // JS_CFUNC_DEF("valueOf", 0, js_date_getTime ), - // JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ), - // JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ), - // JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ), - // JS_ALIAS_DEF("toGMTString", "toUTCString" ), - // JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ), - // JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ), - // JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ), - // JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ), - // JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ), - // JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ), - // JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ), - // JS_CFUNC_DEF("getTime", 0, js_date_getTime ), - // JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ), - // JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ), - // JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ), - // JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ), - // JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ), - // JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ), - // JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ), - // JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ), - // JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ), - // JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ), - // JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ), - // JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ), - // JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ), - // JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ), - // JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ), - // JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ), - // JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ), - // JS_CFUNC_DEF("setTime", 1, js_date_setTime ), - // JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ), - // JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ), - // JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ), - // JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ), - // JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ), - // JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ), - // JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ), - // JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ), - // JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ), - // JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ), - // JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ), - // JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ), - // JS_CFUNC_DEF("setYear", 1, js_date_setYear ), - // JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ), - // JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ), - // JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), + JS_CFUNC_DEF("valueOf", 0, js_date_getTime ), + JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ), + JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ), + JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ), + JS_ALIAS_DEF("toGMTString", "toUTCString" ), + JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ), + JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ), + JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ), + JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ), + JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ), + JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ), + JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ), + JS_CFUNC_DEF("getTime", 0, js_date_getTime ), + JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ), + JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ), + JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ), + JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ), + JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ), + JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ), + JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ), + JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ), + JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ), + JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ), + JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ), + JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ), + JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ), + JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ), + JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ), + JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ), + JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ), + JS_CFUNC_DEF("setTime", 1, js_date_setTime ), + JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ), + JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ), + JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ), + JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ), + JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ), + JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ), + JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ), + JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ), + JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ), + JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ), + JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ), + JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ), + JS_CFUNC_DEF("setYear", 1, js_date_setYear ), + JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ), + JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ), + JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ), }; void JS_AddIntrinsicDate(JSContext *ctx) @@ -49111,6 +50507,7 @@ void JS_AddIntrinsicOperators(JSContext *ctx) js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]); js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]); } +#endif /* CONFIG_BIGNUM */ /* BigInt */ @@ -49128,11 +50525,17 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) case JS_TAG_BIG_INT: break; case JS_TAG_FLOAT64: +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_FLOAT: +#endif { bf_t *a, a_s; a = JS_ToBigFloat(ctx, &a_s, val); + if (!a) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } if (!bf_is_finite(a)) { JS_FreeValue(ctx, val); val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint"); @@ -49162,11 +50565,13 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val) bf_delete(a); } break; +#ifdef CONFIG_BIGNUM case JS_TAG_BIG_DECIMAL: val = JS_ToStringFree(ctx, val); if (JS_IsException(val)) break; goto redo; +#endif case JS_TAG_STRING: val = JS_StringToBigIntErr(ctx, val); break; @@ -49239,6 +50644,7 @@ static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val, return js_thisBigIntValue(ctx, this_val); } +#ifdef CONFIG_BIGNUM static JSValue js_bigint_div(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) @@ -49367,6 +50773,7 @@ static JSValue js_bigint_op1(JSContext *ctx, JS_FreeBigInt(ctx, a, &a_s); return JS_NewBigInt64(ctx, res); } +#endif static JSValue js_bigint_asUintN(JSContext *ctx, JSValueConst this_val, @@ -49411,6 +50818,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx, static const JSCFunctionListEntry js_bigint_funcs[] = { JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ), JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ), +#ifdef CONFIG_BIGNUM /* QuickJS extensions */ JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ), JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ), @@ -49424,6 +50832,7 @@ static const JSCFunctionListEntry js_bigint_funcs[] = { JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ), JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ), JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ), +#endif }; static const JSCFunctionListEntry js_bigint_proto_funcs[] = { @@ -49442,7 +50851,7 @@ void JS_AddIntrinsicBigInt(JSContext *ctx) rt->bigint_ops.unary_arith = js_unary_arith_bigint; rt->bigint_ops.binary_arith = js_binary_arith_bigint; rt->bigint_ops.compare = js_compare_bigfloat; - + ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT], js_bigint_proto_funcs, @@ -49453,6 +50862,8 @@ void JS_AddIntrinsicBigInt(JSContext *ctx) countof(js_bigint_funcs)); } +#ifdef CONFIG_BIGNUM + /* BigFloat */ static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val) @@ -49926,6 +51337,10 @@ static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val, if (JS_IsException(op1)) return op1; a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) { + JS_FreeValue(ctx, op1); + return JS_EXCEPTION; + } fe = &ctx->fp_env; if (argc > 1) { fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV); @@ -50024,7 +51439,11 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, return op2; } a = JS_ToBigFloat(ctx, &a_s, op1); + if (!a) + goto fail1; b = JS_ToBigFloat(ctx, &b_s, op2); + if (!b) + goto fail2; fe = &ctx->fp_env; if (argc > 2) { fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV); @@ -50034,10 +51453,12 @@ static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val, res = JS_NewBigFloat(ctx); if (JS_IsException(res)) { fail: - if (a == &a_s) - bf_delete(a); if (b == &b_s) bf_delete(b); + fail2: + if (a == &a_s) + bf_delete(a); + fail1: JS_FreeValue(ctx, op1); JS_FreeValue(ctx, op2); return JS_EXCEPTION; @@ -50986,8 +52407,22 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) /* XXX: create auto_initializer */ { /* initialize Array.prototype[Symbol.unscopables] */ - char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0" - "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0"; + char const unscopables[] = + "copyWithin" "\0" + "entries" "\0" + "fill" "\0" + "find" "\0" + "findIndex" "\0" + "findLast" "\0" + "findLastIndex" "\0" + "flat" "\0" + "flatMap" "\0" + "includes" "\0" + "keys" "\0" + "toReversed" "\0" + "toSorted" "\0" + "toSpliced" "\0" + "values" "\0"; const char *p = unscopables; obj1 = JS_NewObjectProto(ctx, JS_NULL); for(p = unscopables; *p; p += strlen(p) + 1) { @@ -51111,9 +52546,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = { 0, 0, 0, 1, 1, 2, 2, -#ifdef CONFIG_BIGNUM 3, 3, /* BigInt64Array, BigUint64Array */ -#endif 2, 3 }; @@ -51243,11 +52676,26 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val) { JSObject *p = JS_VALUE_GET_OBJ(val); JSArrayBuffer *abuf = p->u.array_buffer; + struct list_head *el, *el1; + if (abuf) { /* The ArrayBuffer finalizer may be called before the typed array finalizers using it, so abuf->array_list is not necessarily empty. */ - // assert(list_empty(&abuf->array_list)); + list_for_each_safe(el, el1, &abuf->array_list) { + JSTypedArray *ta; + JSObject *p1; + + ta = list_entry(el, JSTypedArray, link); + ta->link.prev = NULL; + ta->link.next = NULL; + p1 = ta->obj; + /* Note: the typed array length and offset fields are not modified */ + if (p1->class_id != JS_CLASS_DATAVIEW) { + p1->u.array.count = 0; + p1->u.array.u.ptr = NULL; + } + } if (abuf->shared && rt->sab_funcs.sab_free) { rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data); } else { @@ -51674,6 +53122,69 @@ static JSValue js_typed_array_set_internal(JSContext *ctx, return JS_EXCEPTION; } +static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSObject *p; + int64_t idx, len; + + p = get_typed_array(ctx, this_val, 0); + if (!p) + return JS_EXCEPTION; + + if (typed_array_is_detached(ctx, p)) { + JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + return JS_EXCEPTION; + } + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + return JS_EXCEPTION; + + len = p->u.array.count; + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) + return JS_UNDEFINED; + return JS_GetPropertyInt64(ctx, this_val, idx); +} + +static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, val; + JSObject *p; + int64_t idx, len; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + + if (JS_ToInt64Sat(ctx, &idx, argv[0])) + return JS_EXCEPTION; + + len = p->u.array.count; + if (idx < 0) + idx = len + idx; + if (idx < 0 || idx >= len) + return JS_ThrowRangeError(ctx, "out of bound"); + + val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER); + if (JS_IsException(val)) + return JS_EXCEPTION; + + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) { + JS_FreeValue(ctx, val); + return JS_EXCEPTION; + } + if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) { + JS_FreeValue(ctx, arr); + return JS_EXCEPTION; + } + return arr; +} + static JSValue js_typed_array_set(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) @@ -51963,14 +53474,10 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, if (JS_ToUint32(ctx, &v, argv[0])) return JS_EXCEPTION; v64 = v; - } else -#ifdef CONFIG_BIGNUM - if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0])) return JS_EXCEPTION; - } else -#endif - { + } else { double d; if (JS_ToFloat64(ctx, &d, argv[0])) return JS_EXCEPTION; @@ -52032,12 +53539,13 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val, } static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int findIndex) + int argc, JSValueConst *argv, int mode) { JSValueConst func, this_arg; JSValueConst args[3]; JSValue val, index_val, res; - int len, k; + int len, k, end; + int dir; val = JS_UNDEFINED; len = js_typed_array_get_length_internal(ctx, this_val); @@ -52052,7 +53560,17 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (argc > 1) this_arg = argv[1]; - for(k = 0; k < len; k++) { + if (mode == special_findLast || mode == special_findLastIndex) { + k = len - 1; + dir = -1; + end = -1; + } else { + k = 0; + dir = 1; + end = len; + } + + for(; k != end; k += dir) { index_val = JS_NewInt32(ctx, k); val = JS_GetPropertyValue(ctx, this_val, index_val); if (JS_IsException(val)) @@ -52064,7 +53582,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, if (JS_IsException(res)) goto exception; if (JS_ToBoolFree(ctx, res)) { - if (findIndex) { + if (mode == special_findIndex || mode == special_findLastIndex) { JS_FreeValue(ctx, val); return index_val; } else { @@ -52073,7 +53591,7 @@ static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val, } JS_FreeValue(ctx, val); } - if (findIndex) + if (mode == special_findIndex || mode == special_findLastIndex) return JS_NewInt32(ctx, -1); else return JS_UNDEFINED; @@ -52157,9 +53675,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, d = JS_VALUE_GET_FLOAT64(argv[0]); v64 = d; is_int = (v64 == d); - } else -#ifdef CONFIG_BIGNUM - if (tag == JS_TAG_BIG_INT) { + } else if (tag == JS_TAG_BIG_INT) { JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]); if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) { @@ -52173,9 +53689,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } d = 0; is_bigint = 1; - } else -#endif - { + } else { goto done; } @@ -52292,7 +53806,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } } break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: if (is_bigint || (is_math_mode(ctx) && is_int && v64 >= -MAX_SAFE_INTEGER && @@ -52316,7 +53829,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val, } } break; -#endif } done: @@ -52451,6 +53963,24 @@ static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val, return JS_DupValue(ctx, this_val); } +static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, ret; + JSObject *p; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) + return JS_EXCEPTION; + ret = js_typed_array_reverse(ctx, arr, argc, argv); + JS_FreeValue(ctx, arr); + return ret; +} + static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -52597,7 +54127,6 @@ static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) { return (y < x) - (y > x); } -#ifdef CONFIG_BIGNUM static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) { int64_t x = *(const int64_t *)a; int64_t y = *(const int64_t *)b; @@ -52609,7 +54138,6 @@ static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) { uint64_t y = *(const uint64_t *)b; return (y < x) - (y > x); } -#endif static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) { return js_cmp_doubles(*(const float *)a, *(const float *)b); @@ -52643,7 +54171,6 @@ static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) { return JS_NewUint32(ctx, *(const uint32_t *)a); } -#ifdef CONFIG_BIGNUM static JSValue js_TA_get_int64(JSContext *ctx, const void *a) { return JS_NewBigInt64(ctx, *(int64_t *)a); } @@ -52651,7 +54178,6 @@ static JSValue js_TA_get_int64(JSContext *ctx, const void *a) { static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) { return JS_NewBigUint64(ctx, *(uint64_t *)a); } -#endif static JSValue js_TA_get_float32(JSContext *ctx, const void *a) { return __JS_NewFloat64(ctx, *(const float *)a); @@ -52663,7 +54189,7 @@ static JSValue js_TA_get_float64(JSContext *ctx, const void *a) { struct TA_sort_context { JSContext *ctx; - int exception; + int exception; /* 1 = exception, 2 = detached typed array */ JSValueConst arr; JSValueConst cmp; JSValue (*getfun)(JSContext *ctx, const void *a); @@ -52681,6 +54207,8 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { cmp = 0; if (!psc->exception) { + /* Note: the typed array can be detached without causing an + error */ a_idx = *(uint32_t *)a; b_idx = *(uint32_t *)b; argv[0] = psc->getfun(ctx, psc->array_ptr + @@ -52708,8 +54236,9 @@ static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) { /* make sort stable: compare array offsets */ cmp = (a_idx > b_idx) - (a_idx < b_idx); } - if (validate_typed_array(ctx, psc->arr) < 0) { - psc->exception = 1; + if (unlikely(typed_array_is_detached(ctx, + JS_VALUE_GET_PTR(psc->arr)))) { + psc->exception = 2; } done: JS_FreeValue(ctx, (JSValue)argv[0]); @@ -52733,11 +54262,11 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.arr = this_val; tsc.cmp = argv[0]; + if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp)) + return JS_EXCEPTION; len = js_typed_array_get_length_internal(ctx, this_val); if (len < 0) return JS_EXCEPTION; - if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp)) - return JS_EXCEPTION; if (len > 1) { p = JS_VALUE_GET_OBJ(this_val); @@ -52767,7 +54296,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.getfun = js_TA_get_uint32; cmpfun = js_TA_cmp_uint32; break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: tsc.getfun = js_TA_get_int64; cmpfun = js_TA_cmp_int64; @@ -52776,7 +54304,6 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.getfun = js_TA_get_uint64; cmpfun = js_TA_cmp_uint64; break; -#endif case JS_CLASS_FLOAT32_ARRAY: tsc.getfun = js_TA_get_float32; cmpfun = js_TA_cmp_float32; @@ -52805,44 +54332,48 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, tsc.elt_size = elt_size; rqsort(array_idx, len, sizeof(array_idx[0]), js_TA_cmp_generic, &tsc); - if (tsc.exception) - goto fail; - array_tmp = js_malloc(ctx, len * elt_size); - if (!array_tmp) { - fail: - js_free(ctx, array_idx); - return JS_EXCEPTION; - } - memcpy(array_tmp, array_ptr, len * elt_size); - switch(elt_size) { - case 1: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j]; - } - break; - case 2: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j]; - } - break; - case 4: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j]; + if (tsc.exception) { + if (tsc.exception == 1) + goto fail; + /* detached typed array during the sort: no error */ + } else { + array_tmp = js_malloc(ctx, len * elt_size); + if (!array_tmp) { + fail: + js_free(ctx, array_idx); + return JS_EXCEPTION; } - break; - case 8: - for(i = 0; i < len; i++) { - j = array_idx[i]; - ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j]; + memcpy(array_tmp, array_ptr, len * elt_size); + switch(elt_size) { + case 1: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j]; + } + break; + case 2: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j]; + } + break; + case 4: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j]; + } + break; + case 8: + for(i = 0; i < len; i++) { + j = array_idx[i]; + ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j]; + } + break; + default: + abort(); } - break; - default: - abort(); + js_free(ctx, array_tmp); } - js_free(ctx, array_tmp); js_free(ctx, array_idx); } else { rqsort(array_ptr, len, elt_size, cmpfun, &tsc); @@ -52853,6 +54384,24 @@ static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val, return JS_DupValue(ctx, this_val); } +static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSValue arr, ret; + JSObject *p; + + p = get_typed_array(ctx, this_val, /*is_dataview*/0); + if (!p) + return JS_EXCEPTION; + arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val, + p->class_id); + if (JS_IsException(arr)) + return JS_EXCEPTION; + ret = js_typed_array_sort(ctx, arr, argc, argv); + JS_FreeValue(ctx, arr); + return ret; +} + static const JSCFunctionListEntry js_typed_array_base_funcs[] = { JS_CFUNC_DEF("from", 1, js_typed_array_from ), JS_CFUNC_DEF("of", 0, js_typed_array_of ), @@ -52864,6 +54413,8 @@ static const JSCFunctionListEntry js_typed_array_base_funcs[] = { static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ), + JS_CFUNC_DEF("at", 1, js_typed_array_at ), + JS_CFUNC_DEF("with", 2, js_typed_array_with ), JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ), JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ), JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ), @@ -52882,12 +54433,16 @@ static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ), JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ), JS_CFUNC_DEF("fill", 1, js_typed_array_fill ), - JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ), - JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ), + JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, special_find ), + JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, special_findIndex ), + JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, special_findLast ), + JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, special_findLastIndex ), JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ), + JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ), JS_CFUNC_DEF("slice", 2, js_typed_array_slice ), JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ), JS_CFUNC_DEF("sort", 1, js_typed_array_sort ), + JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ), JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ), JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ), JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ), @@ -53034,7 +54589,7 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, { JSObject *p, *src_buffer; JSTypedArray *ta; - JSValue ctor, obj, buffer; + JSValue obj, buffer; uint32_t len, i; int size_log2; JSArrayBuffer *src_abuf, *abuf; @@ -53051,19 +54606,9 @@ static JSValue js_typed_array_constructor_ta(JSContext *ctx, len = p->u.array.count; src_buffer = ta->buffer; src_abuf = src_buffer->u.array_buffer; - if (!src_abuf->shared) { - ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer), - JS_UNDEFINED); - if (JS_IsException(ctor)) - goto fail; - } else { - /* force ArrayBuffer default constructor */ - ctor = JS_UNDEFINED; - } size_log2 = typed_array_size_log2(classid); - buffer = js_array_buffer_constructor1(ctx, ctor, + buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, (uint64_t)len << size_log2); - JS_FreeValue(ctx, ctor); if (JS_IsException(buffer)) goto fail; /* necessary because it could have been detached */ @@ -53169,7 +54714,7 @@ static void js_typed_array_finalizer(JSRuntime *rt, JSValue val) if (ta) { /* during the GC the finalizers are called in an arbitrary order so the ArrayBuffer finalizer may have been called */ - if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) { + if (ta->link.next) { list_del(&ta->link); } JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)); @@ -53301,7 +54846,6 @@ static JSValue js_dataview_getValue(JSContext *ctx, if (is_swap) v = bswap32(v); return JS_NewUint32(ctx, v); -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: { uint64_t v; @@ -53320,7 +54864,6 @@ static JSValue js_dataview_getValue(JSContext *ctx, return JS_NewBigUint64(ctx, v); } break; -#endif case JS_CLASS_FLOAT32_ARRAY: { union { @@ -53374,14 +54917,10 @@ static JSValue js_dataview_setValue(JSContext *ctx, if (class_id <= JS_CLASS_UINT32_ARRAY) { if (JS_ToUint32(ctx, &v, val)) return JS_EXCEPTION; - } else -#ifdef CONFIG_BIGNUM - if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { + } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) { if (JS_ToBigInt64(ctx, (int64_t *)&v64, val)) return JS_EXCEPTION; - } else -#endif - { + } else { double d; if (JS_ToFloat64(ctx, &d, val)) return JS_EXCEPTION; @@ -53429,10 +54968,8 @@ static JSValue js_dataview_setValue(JSContext *ctx, v = bswap32(v); put_u32(ptr, v); break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: case JS_CLASS_BIG_UINT64_ARRAY: -#endif case JS_CLASS_FLOAT64_ARRAY: if (is_swap) v64 = bswap64(v64); @@ -53454,10 +54991,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ), JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ), -#ifdef CONFIG_BIGNUM JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ), -#endif JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ), @@ -53466,10 +55001,8 @@ static const JSCFunctionListEntry js_dataview_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ), JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ), -#ifdef CONFIG_BIGNUM JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ), JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ), -#endif JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ), JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ), @@ -53506,20 +55039,12 @@ static void *js_atomics_get_ptr(JSContext *ctx, if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) goto fail; p = JS_VALUE_GET_OBJ(obj); -#ifdef CONFIG_BIGNUM if (is_waitable) err = (p->class_id != JS_CLASS_INT32_ARRAY && p->class_id != JS_CLASS_BIG_INT64_ARRAY); else err = !(p->class_id >= JS_CLASS_INT8_ARRAY && p->class_id <= JS_CLASS_BIG_UINT64_ARRAY); -#else - if (is_waitable) - err = (p->class_id != JS_CLASS_INT32_ARRAY); - else - err = !(p->class_id >= JS_CLASS_INT8_ARRAY && - p->class_id <= JS_CLASS_UINT32_ARRAY); -#endif if (err) { fail: JS_ThrowTypeError(ctx, "integer TypedArray expected"); @@ -53561,11 +55086,7 @@ static JSValue js_atomics_op(JSContext *ctx, int argc, JSValueConst *argv, int op) { int size_log2; -#ifdef CONFIG_BIGNUM uint64_t v, a, rep_val; -#else - uint32_t v, a, rep_val; -#endif void *ptr; JSValue ret; JSClassID class_id; @@ -53579,7 +55100,6 @@ static JSValue js_atomics_op(JSContext *ctx, if (op == ATOMICS_OP_LOAD) { v = 0; } else { -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { int64_t v64; if (JS_ToBigInt64(ctx, &v64, argv[2])) @@ -53590,9 +55110,7 @@ static JSValue js_atomics_op(JSContext *ctx, return JS_EXCEPTION; rep_val = v64; } - } else -#endif - { + } else { uint32_t v32; if (JS_ToUint32(ctx, &v32, argv[2])) return JS_EXCEPTION; @@ -53609,7 +55127,6 @@ static JSValue js_atomics_op(JSContext *ctx, switch(op | (size_log2 << 3)) { -#ifdef CONFIG_BIGNUM #define OP(op_name, func_name) \ case ATOMICS_OP_ ## op_name | (0 << 3): \ a = func_name((_Atomic(uint8_t) *)ptr, v); \ @@ -53623,18 +55140,7 @@ static JSValue js_atomics_op(JSContext *ctx, case ATOMICS_OP_ ## op_name | (3 << 3): \ a = func_name((_Atomic(uint64_t) *)ptr, v); \ break; -#else -#define OP(op_name, func_name) \ - case ATOMICS_OP_ ## op_name | (0 << 3): \ - a = func_name((_Atomic(uint8_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (1 << 3): \ - a = func_name((_Atomic(uint16_t) *)ptr, v); \ - break; \ - case ATOMICS_OP_ ## op_name | (2 << 3): \ - a = func_name((_Atomic(uint32_t) *)ptr, v); \ - break; -#endif + OP(ADD, atomic_fetch_add) OP(AND, atomic_fetch_and) OP(OR, atomic_fetch_or) @@ -53652,11 +55158,9 @@ static JSValue js_atomics_op(JSContext *ctx, case ATOMICS_OP_LOAD | (2 << 3): a = atomic_load((_Atomic(uint32_t) *)ptr); break; -#ifdef CONFIG_BIGNUM case ATOMICS_OP_LOAD | (3 << 3): a = atomic_load((_Atomic(uint64_t) *)ptr); break; -#endif case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3): { @@ -53679,7 +55183,6 @@ static JSValue js_atomics_op(JSContext *ctx, a = v1; } break; -#ifdef CONFIG_BIGNUM case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3): { uint64_t v1 = v; @@ -53687,7 +55190,6 @@ static JSValue js_atomics_op(JSContext *ctx, a = v1; } break; -#endif default: abort(); } @@ -53712,14 +55214,12 @@ static JSValue js_atomics_op(JSContext *ctx, case JS_CLASS_UINT32_ARRAY: ret = JS_NewUint32(ctx, a); break; -#ifdef CONFIG_BIGNUM case JS_CLASS_BIG_INT64_ARRAY: ret = JS_NewBigInt64(ctx, a); break; case JS_CLASS_BIG_UINT64_ARRAY: ret = JS_NewBigUint64(ctx, a); break; -#endif default: abort(); } @@ -53739,7 +55239,6 @@ static JSValue js_atomics_store(JSContext *ctx, argv[0], argv[1], 0); if (!ptr) return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { int64_t v64; ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2])); @@ -53752,9 +55251,7 @@ static JSValue js_atomics_store(JSContext *ctx, if (abuf->detached) return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); atomic_store((_Atomic(uint64_t) *)ptr, v64); - } else -#endif - { + } else { uint32_t v; /* XXX: spec, would be simpler to return the written value */ ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2])); @@ -53790,11 +55287,7 @@ static JSValue js_atomics_isLockFree(JSContext *ctx, int v, ret; if (JS_ToInt32Sat(ctx, &v, argv[0])) return JS_EXCEPTION; - ret = (v == 1 || v == 2 || v == 4 -#ifdef CONFIG_BIGNUM - || v == 8 -#endif - ); + ret = (v == 1 || v == 2 || v == 4 || v == 8); return JS_NewBool(ctx, ret); } @@ -53826,13 +55319,10 @@ static JSValue js_atomics_wait(JSContext *ctx, argv[0], argv[1], 2); if (!ptr) return JS_EXCEPTION; -#ifdef CONFIG_BIGNUM if (size_log2 == 3) { if (JS_ToBigInt64(ctx, &v, argv[2])) return JS_EXCEPTION; - } else -#endif - { + } else { if (JS_ToInt32(ctx, &v32, argv[2])) return JS_EXCEPTION; v = v32; diff --git a/quickjs/quickjs.h b/deps/quickjs/quickjs.h similarity index 98% rename from quickjs/quickjs.h rename to deps/quickjs/quickjs.h index d0e3692..700ee61 100644 --- a/quickjs/quickjs.h +++ b/deps/quickjs/quickjs.h @@ -25,10 +25,8 @@ #ifndef QUICKJS_H #define QUICKJS_H -#include #include #include -#include "my_stdint.h" #ifdef __cplusplus extern "C" { @@ -66,18 +64,6 @@ typedef uint32_t JSAtom; #define JS_NAN_BOXING #endif -#ifdef CONFIG_BIGNUM -#define BC_BASE_VERSION 2 -#else -#define BC_BASE_VERSION 1 -#endif -#define BC_BE_VERSION 0x40 -#ifdef WORDS_BIGENDIAN -#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) -#else -#define BC_VERSION BC_BASE_VERSION -#endif - enum { /* all tags with a reference count are negative */ JS_TAG_FIRST = -11, /* first negative tag */ @@ -321,6 +307,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* don't include the stack frames before this eval in the Error() backtraces */ #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) +/* allow top-level await in normal script. JS_Eval() returns a + promise. Only allowed with JS_EVAL_TYPE_GLOBAL */ +#define JS_EVAL_FLAG_ASYNC (1 << 7) typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); @@ -427,6 +416,7 @@ typedef struct JSMemoryUsage { } JSMemoryUsage; void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); +void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); /* atom support */ #define JS_ATOM_NULL 0 @@ -746,13 +736,13 @@ JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx); -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, +int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValue val, JSValueConst this_obj, int flags); static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) { - return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); + return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW); } int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val); @@ -844,7 +834,15 @@ typedef struct { void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); +typedef enum JSPromiseStateEnum { + JS_PROMISE_PENDING, + JS_PROMISE_FULFILLED, + JS_PROMISE_REJECTED, +} JSPromiseStateEnum; + JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); +JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise); +JSValue JS_PromiseResult(JSContext *ctx, JSValue promise); /* is_handled = TRUE means that the rejection is handled */ typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, @@ -915,8 +913,8 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj); /* only exported for os.Worker() */ JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); /* only exported for os.Worker() */ -JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, - const char *filename); +JSValue JS_LoadModule(JSContext *ctx, const char *basename, + const char *filename); /* C function definition */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ @@ -1051,7 +1049,6 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, JSValue val); int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, const JSCFunctionListEntry *tab, int len); -uintptr_t JS_GetStackPeak(); #undef js_unlikely #undef js_force_inline diff --git a/deps/quickjs/readme.txt b/deps/quickjs/readme.txt new file mode 100644 index 0000000..789521d --- /dev/null +++ b/deps/quickjs/readme.txt @@ -0,0 +1 @@ +The main documentation is in doc/quickjs.pdf or doc/quickjs.html. diff --git a/deps/quickjs/release.sh b/deps/quickjs/release.sh new file mode 100755 index 0000000..6b1b496 --- /dev/null +++ b/deps/quickjs/release.sh @@ -0,0 +1,180 @@ +#!/bin/sh +# Release the QuickJS source code + +set -e + +version=`cat VERSION` + +if [ "$1" = "-h" ] ; then + echo "release.sh [release_list]" + echo "" + echo "release_list: extras binary win_binary cosmo_binary quickjs" + + exit 1 +fi + +release_list="extras binary win_binary cosmo_binary quickjs" + +if [ "$1" != "" ] ; then + release_list="$1" +fi + +#################################################" +# extras + +if echo $release_list | grep -w -q extras ; then + +d="quickjs-${version}" +name="quickjs-extras-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir $outdir/unicode $outdir/tests + +cp unicode/* $outdir/unicode +cp -a tests/bench-v8 $outdir/tests + +( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} ) + +fi + +#################################################" +# Windows binary release + +if echo $release_list | grep -w -q win_binary ; then + +# win64 + +dlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin +cross_prefix="x86_64-w64-mingw32-" +d="quickjs-win-x86_64-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make CONFIG_WIN32=y qjs.exe +cp qjs.exe $outdir +${cross_prefix}strip $outdir/qjs.exe +cp $dlldir/libwinpthread-1.dll $outdir + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +make CONFIG_WIN32=y clean + +# win32 + +dlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin +cross_prefix="i686-w64-mingw32-" +d="quickjs-win-i686-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make clean +make CONFIG_WIN32=y clean + +make CONFIG_WIN32=y CONFIG_M32=y qjs.exe +cp qjs.exe $outdir +${cross_prefix}strip $outdir/qjs.exe +cp $dlldir/libwinpthread-1.dll $outdir + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +fi + +#################################################" +# Cosmopolitan binary release + +if echo $release_list | grep -w -q cosmo_binary ; then + +export PATH=$PATH:$HOME/cosmocc/bin + +d="quickjs-cosmo-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +make clean +make CONFIG_COSMO=y -j4 qjs run-test262 +cp qjs run-test262 $outdir +cp readme-cosmo.txt $outdir/readme.txt + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +fi + +#################################################" +# Linux binary release + +if echo $release_list | grep -w -q binary ; then + +make clean +make CONFIG_WIN32=y clean +make -j4 qjs run-test262 +make -j4 CONFIG_M32=y qjs32 run-test262-32 +strip qjs run-test262 qjs32 run-test262-32 + +d="quickjs-linux-x86_64-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +cp qjs run-test262 $outdir + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +d="quickjs-linux-i686-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir + +cp qjs32 $outdir/qjs +cp run-test262-32 $outdir/run-test262 + +( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . ) + +fi + +#################################################" +# quickjs + +if echo $release_list | grep -w -q quickjs ; then + +make build_doc + +d="quickjs-${version}" +outdir="/tmp/${d}" + +rm -rf $outdir +mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples + +cp Makefile VERSION TODO Changelog readme.txt LICENSE \ + release.sh unicode_download.sh \ + qjs.c qjsc.c qjscalc.js repl.js \ + quickjs.c quickjs.h quickjs-atom.h \ + quickjs-libc.c quickjs-libc.h quickjs-opcode.h \ + cutils.c cutils.h list.h \ + libregexp.c libregexp.h libregexp-opcode.h \ + libunicode.c libunicode.h libunicode-table.h \ + libbf.c libbf.h \ + unicode_gen.c unicode_gen_def.h \ + run-test262.c test262o.conf test262.conf \ + test262o_errors.txt test262_errors.txt \ + $outdir + +cp tests/*.js tests/*.patch tests/bjson.c $outdir/tests + +cp examples/*.js examples/*.c $outdir/examples + +cp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \ + doc/jsbignum.texi doc/jsbignum.html doc/jsbignum.pdf \ + $outdir/doc + +( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} ) + +fi diff --git a/deps/quickjs/repl.c b/deps/quickjs/repl.c new file mode 100644 index 0000000..c28fea6 --- /dev/null +++ b/deps/quickjs/repl.c @@ -0,0 +1,2043 @@ +/* File generated automatically by the QuickJS compiler. */ + +#include + +const uint32_t qjsc_repl_size = 16267; + +const uint8_t qjsc_repl[16267] = { + 0x02, 0xa5, 0x03, 0x0e, 0x72, 0x65, 0x70, 0x6c, + 0x2e, 0x6a, 0x73, 0x06, 0x73, 0x74, 0x64, 0x04, + 0x6f, 0x73, 0x10, 0x69, 0x73, 0x46, 0x69, 0x6e, + 0x69, 0x74, 0x65, 0x14, 0x70, 0x61, 0x72, 0x73, + 0x65, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x08, 0x6f, + 0x70, 0x65, 0x6e, 0x10, 0x46, 0x72, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x08, 0x1b, 0x5b, 0x30, + 0x6d, 0x08, 0x6e, 0x6f, 0x6e, 0x65, 0x0a, 0x1b, + 0x5b, 0x33, 0x30, 0x6d, 0x0a, 0x62, 0x6c, 0x61, + 0x63, 0x6b, 0x0a, 0x1b, 0x5b, 0x33, 0x31, 0x6d, + 0x06, 0x72, 0x65, 0x64, 0x0a, 0x1b, 0x5b, 0x33, + 0x32, 0x6d, 0x0a, 0x67, 0x72, 0x65, 0x65, 0x6e, + 0x0a, 0x1b, 0x5b, 0x33, 0x33, 0x6d, 0x0c, 0x79, + 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x0a, 0x1b, 0x5b, + 0x33, 0x34, 0x6d, 0x08, 0x62, 0x6c, 0x75, 0x65, + 0x0a, 0x1b, 0x5b, 0x33, 0x35, 0x6d, 0x0e, 0x6d, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x61, 0x0a, 0x1b, + 0x5b, 0x33, 0x36, 0x6d, 0x08, 0x63, 0x79, 0x61, + 0x6e, 0x0a, 0x1b, 0x5b, 0x33, 0x37, 0x6d, 0x0a, + 0x77, 0x68, 0x69, 0x74, 0x65, 0x0e, 0x1b, 0x5b, + 0x33, 0x30, 0x3b, 0x31, 0x6d, 0x08, 0x67, 0x72, + 0x61, 0x79, 0x08, 0x67, 0x72, 0x65, 0x79, 0x0e, + 0x1b, 0x5b, 0x33, 0x31, 0x3b, 0x31, 0x6d, 0x14, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x72, + 0x65, 0x64, 0x0e, 0x1b, 0x5b, 0x33, 0x32, 0x3b, + 0x31, 0x6d, 0x18, 0x62, 0x72, 0x69, 0x67, 0x68, + 0x74, 0x5f, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x0e, + 0x1b, 0x5b, 0x33, 0x33, 0x3b, 0x31, 0x6d, 0x1a, + 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x79, + 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x0e, 0x1b, 0x5b, + 0x33, 0x34, 0x3b, 0x31, 0x6d, 0x16, 0x62, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x5f, 0x62, 0x6c, 0x75, + 0x65, 0x0e, 0x1b, 0x5b, 0x33, 0x35, 0x3b, 0x31, + 0x6d, 0x1c, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, + 0x5f, 0x6d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x61, + 0x0e, 0x1b, 0x5b, 0x33, 0x36, 0x3b, 0x31, 0x6d, + 0x16, 0x62, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, + 0x63, 0x79, 0x61, 0x6e, 0x0e, 0x1b, 0x5b, 0x33, + 0x37, 0x3b, 0x31, 0x6d, 0x18, 0x62, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x5f, 0x77, 0x68, 0x69, 0x74, + 0x65, 0x0e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x0a, 0x72, 0x65, 0x67, 0x65, 0x78, 0x0e, + 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x08, + 0x74, 0x79, 0x70, 0x65, 0x14, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x0a, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0c, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x04, 0x3e, + 0x20, 0x0c, 0x71, 0x6a, 0x73, 0x20, 0x3e, 0x20, + 0x0c, 0x20, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x02, + 0x01, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04, 0x02, + 0x05, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08, 0x02, + 0x09, 0x02, 0x0a, 0x02, 0x0b, 0x02, 0x0d, 0x02, + 0x0e, 0x02, 0x10, 0x02, 0x11, 0x02, 0x12, 0x02, + 0x13, 0x02, 0x14, 0x02, 0x18, 0x02, 0x19, 0x06, + 0x1b, 0x4f, 0x41, 0x06, 0x1b, 0x4f, 0x42, 0x06, + 0x1b, 0x4f, 0x43, 0x06, 0x1b, 0x4f, 0x44, 0x06, + 0x1b, 0x4f, 0x46, 0x06, 0x1b, 0x4f, 0x48, 0x0c, + 0x1b, 0x5b, 0x31, 0x3b, 0x35, 0x43, 0x0c, 0x1b, + 0x5b, 0x31, 0x3b, 0x35, 0x44, 0x08, 0x1b, 0x5b, + 0x31, 0x7e, 0x08, 0x1b, 0x5b, 0x33, 0x7e, 0x08, + 0x1b, 0x5b, 0x34, 0x7e, 0x08, 0x1b, 0x5b, 0x35, + 0x7e, 0x08, 0x1b, 0x5b, 0x36, 0x7e, 0x06, 0x1b, + 0x5b, 0x41, 0x06, 0x1b, 0x5b, 0x42, 0x06, 0x1b, + 0x5b, 0x43, 0x06, 0x1b, 0x5b, 0x44, 0x06, 0x1b, + 0x5b, 0x46, 0x06, 0x1b, 0x5b, 0x48, 0x04, 0x1b, + 0x7f, 0x04, 0x1b, 0x62, 0x04, 0x1b, 0x64, 0x04, + 0x1b, 0x66, 0x04, 0x1b, 0x6b, 0x04, 0x1b, 0x6c, + 0x04, 0x1b, 0x74, 0x04, 0x1b, 0x75, 0x02, 0x7f, + 0x0e, 0x65, 0x78, 0x65, 0x63, 0x43, 0x6d, 0x64, + 0x10, 0x74, 0x65, 0x72, 0x6d, 0x49, 0x6e, 0x69, + 0x74, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x6f, + 0x0c, 0x69, 0x73, 0x61, 0x74, 0x74, 0x79, 0x1a, + 0x74, 0x74, 0x79, 0x47, 0x65, 0x74, 0x57, 0x69, + 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x74, 0x74, + 0x79, 0x53, 0x65, 0x74, 0x52, 0x61, 0x77, 0x0c, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x0c, 0x53, + 0x49, 0x47, 0x49, 0x4e, 0x54, 0x1c, 0x73, 0x65, + 0x74, 0x52, 0x65, 0x61, 0x64, 0x48, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x72, 0x1c, 0x73, 0x69, 0x67, + 0x69, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x72, 0x16, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x22, + 0x74, 0x65, 0x72, 0x6d, 0x5f, 0x72, 0x65, 0x61, + 0x64, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, + 0x72, 0x08, 0x72, 0x65, 0x61, 0x64, 0x0c, 0x62, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x10, 0x69, 0x73, + 0x5f, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x02, 0x41, + 0x02, 0x5a, 0x02, 0x61, 0x02, 0x7a, 0x10, 0x69, + 0x73, 0x5f, 0x64, 0x69, 0x67, 0x69, 0x74, 0x0e, + 0x69, 0x73, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x02, + 0x5f, 0x02, 0x24, 0x14, 0x75, 0x63, 0x73, 0x5f, + 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x14, 0x63, + 0x68, 0x61, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x41, + 0x74, 0x2a, 0x69, 0x73, 0x5f, 0x74, 0x72, 0x61, + 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x75, + 0x72, 0x72, 0x6f, 0x67, 0x61, 0x74, 0x65, 0x16, + 0x63, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x41, 0x74, 0x16, 0x69, 0x73, 0x5f, 0x62, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x04, + 0x28, 0x29, 0x04, 0x5b, 0x5d, 0x04, 0x7b, 0x7d, + 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x63, + 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x74, 0x65, 0x78, + 0x74, 0x08, 0x70, 0x75, 0x74, 0x73, 0x12, 0x73, + 0x75, 0x62, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x12, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x63, + 0x73, 0x69, 0x04, 0x1b, 0x5b, 0x16, 0x6d, 0x6f, + 0x76, 0x65, 0x5f, 0x63, 0x75, 0x72, 0x73, 0x6f, + 0x72, 0x06, 0x6d, 0x69, 0x6e, 0x02, 0x43, 0x02, + 0x44, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x04, 0x20, 0x08, 0x06, 0x1b, 0x5b, 0x4a, 0x06, + 0x6f, 0x75, 0x74, 0x0a, 0x66, 0x6c, 0x75, 0x73, + 0x68, 0x0c, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, + 0x1a, 0x71, 0x75, 0x6f, 0x74, 0x65, 0x64, 0x5f, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x14, 0x71, + 0x75, 0x6f, 0x74, 0x65, 0x5f, 0x66, 0x6c, 0x61, + 0x67, 0x0a, 0x61, 0x62, 0x6f, 0x72, 0x74, 0x06, + 0x63, 0x6d, 0x64, 0x14, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x73, 0x0a, 0x61, + 0x6c, 0x65, 0x72, 0x74, 0x22, 0x62, 0x65, 0x67, + 0x69, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6f, + 0x66, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x16, 0x65, + 0x6e, 0x64, 0x5f, 0x6f, 0x66, 0x5f, 0x6c, 0x69, + 0x6e, 0x65, 0x18, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x0c, + 0x63, 0x68, 0x61, 0x72, 0x41, 0x74, 0x1a, 0x62, + 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, + 0x63, 0x68, 0x61, 0x72, 0x22, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x66, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x24, 0x73, + 0x6b, 0x69, 0x70, 0x5f, 0x77, 0x6f, 0x72, 0x64, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, + 0x64, 0x18, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x1a, 0x62, + 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x16, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, + 0x16, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x5f, 0x61, 0x64, 0x64, 0x08, 0x70, 0x75, 0x73, + 0x68, 0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, + 0x75, 0x73, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x1a, 0x68, 0x69, 0x73, 0x74, 0x6f, + 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x0e, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x68, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x1c, 0x68, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x2e, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x5f, 0x62, 0x61, 0x63, 0x6b, + 0x77, 0x61, 0x72, 0x64, 0x2c, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x5f, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x1e, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x5f, + 0x64, 0x69, 0x72, 0x16, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x12, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, + 0x64, 0x28, 0x62, 0x61, 0x63, 0x6b, 0x77, 0x61, + 0x72, 0x64, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x1e, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, + 0x5f, 0x63, 0x68, 0x61, 0x72, 0x73, 0x1e, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x73, 0x65, + 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x16, 0x75, + 0x70, 0x63, 0x61, 0x73, 0x65, 0x5f, 0x77, 0x6f, + 0x72, 0x64, 0x16, 0x74, 0x6f, 0x55, 0x70, 0x70, + 0x65, 0x72, 0x43, 0x61, 0x73, 0x65, 0x1a, 0x64, + 0x6f, 0x77, 0x6e, 0x63, 0x61, 0x73, 0x65, 0x5f, + 0x77, 0x6f, 0x72, 0x64, 0x16, 0x74, 0x6f, 0x4c, + 0x6f, 0x77, 0x65, 0x72, 0x43, 0x61, 0x73, 0x65, + 0x16, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x72, 0x65, + 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x6b, 0x69, 0x6c, + 0x6c, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x24, 0x62, + 0x61, 0x63, 0x6b, 0x77, 0x61, 0x72, 0x64, 0x5f, + 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x6c, 0x69, 0x6e, + 0x65, 0x12, 0x6b, 0x69, 0x6c, 0x6c, 0x5f, 0x77, + 0x6f, 0x72, 0x64, 0x24, 0x62, 0x61, 0x63, 0x6b, + 0x77, 0x61, 0x72, 0x64, 0x5f, 0x6b, 0x69, 0x6c, + 0x6c, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x08, 0x79, + 0x61, 0x6e, 0x6b, 0x14, 0x63, 0x6c, 0x69, 0x70, + 0x5f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x5f, 0x63, + 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x66, 0x75, + 0x6e, 0x2a, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x08, + 0x65, 0x78, 0x69, 0x74, 0x3c, 0x0a, 0x28, 0x50, + 0x72, 0x65, 0x73, 0x73, 0x20, 0x43, 0x74, 0x72, + 0x6c, 0x2d, 0x43, 0x20, 0x61, 0x67, 0x61, 0x69, + 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x71, 0x75, 0x69, + 0x74, 0x29, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x65, + 0x74, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x77, 0x6f, + 0x72, 0x64, 0x24, 0x67, 0x65, 0x74, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x08, 0x6c, 0x69, + 0x6e, 0x65, 0x06, 0x70, 0x6f, 0x73, 0x06, 0x6f, + 0x62, 0x6a, 0x08, 0x62, 0x61, 0x73, 0x65, 0x02, + 0x63, 0x02, 0x67, 0x1c, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x6e, 0x75, 0x6d, 0x63, 0x61, + 0x6c, 0x63, 0x14, 0x68, 0x61, 0x73, 0x5f, 0x6a, + 0x73, 0x63, 0x61, 0x6c, 0x63, 0x14, 0x68, 0x61, + 0x73, 0x5f, 0x62, 0x69, 0x67, 0x6e, 0x75, 0x6d, + 0x0c, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x0c, + 0x73, 0x74, 0x79, 0x6c, 0x65, 0x73, 0x08, 0x70, + 0x72, 0x65, 0x63, 0x0e, 0x65, 0x78, 0x70, 0x42, + 0x69, 0x74, 0x73, 0x0e, 0x6c, 0x6f, 0x67, 0x32, + 0x5f, 0x31, 0x30, 0x0c, 0x70, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x0c, 0x70, 0x72, 0x6f, 0x6d, 0x70, + 0x74, 0x08, 0x70, 0x6c, 0x65, 0x6e, 0x06, 0x70, + 0x73, 0x31, 0x06, 0x70, 0x73, 0x32, 0x08, 0x75, + 0x74, 0x66, 0x38, 0x12, 0x73, 0x68, 0x6f, 0x77, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x16, 0x73, 0x68, + 0x6f, 0x77, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x73, 0x1e, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x0a, 0x6d, 0x65, 0x78, 0x70, + 0x72, 0x0a, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x10, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6d, 0x64, + 0x1e, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x73, + 0x10, 0x74, 0x68, 0x69, 0x73, 0x5f, 0x66, 0x75, + 0x6e, 0x14, 0x75, 0x74, 0x66, 0x38, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x10, 0x75, 0x74, 0x66, + 0x38, 0x5f, 0x76, 0x61, 0x6c, 0x0e, 0x74, 0x65, + 0x72, 0x6d, 0x5f, 0x66, 0x64, 0x1a, 0x74, 0x65, + 0x72, 0x6d, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, + 0x62, 0x75, 0x66, 0x14, 0x74, 0x65, 0x72, 0x6d, + 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x1a, 0x74, + 0x65, 0x72, 0x6d, 0x5f, 0x63, 0x75, 0x72, 0x73, + 0x6f, 0x72, 0x5f, 0x78, 0x1e, 0x67, 0x65, 0x74, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x14, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x10, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, + 0x0c, 0x64, 0x75, 0x70, 0x73, 0x74, 0x72, 0x1a, + 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, + 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x1c, 0x72, 0x65, + 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x16, 0x72, 0x65, 0x61, + 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x62, + 0x1c, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, + 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x16, + 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, + 0x68, 0x61, 0x72, 0x14, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x10, 0x68, + 0x65, 0x78, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x12, + 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x6d, 0x6f, 0x64, + 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x24, 0x62, 0x69, 0x67, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x69, + 0x67, 0x69, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x5f, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x0a, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x22, 0x65, 0x78, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x5f, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x68, + 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x08, + 0x68, 0x65, 0x6c, 0x70, 0x12, 0x63, 0x6d, 0x64, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x24, 0x63, + 0x6d, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, + 0x69, 0x6e, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x26, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x5f, 0x63, 0x6d, 0x64, 0x14, 0x68, 0x61, + 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x63, 0x6d, 0x64, + 0x28, 0x65, 0x76, 0x61, 0x6c, 0x5f, 0x61, 0x6e, + 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x22, 0x70, 0x72, + 0x69, 0x6e, 0x74, 0x5f, 0x65, 0x76, 0x61, 0x6c, + 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x65, 0x76, + 0x61, 0x6c, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x1c, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x5f, + 0x63, 0x6d, 0x64, 0x5f, 0x65, 0x6e, 0x64, 0x16, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x5f, 0x6a, 0x73, 0x2a, 0x20, 0x7e, 0x21, 0x25, + 0x5e, 0x26, 0x2a, 0x28, 0x2d, 0x2b, 0x3d, 0x7b, + 0x5b, 0x7c, 0x3a, 0x3b, 0x2c, 0x3c, 0x3e, 0x3f, + 0x2f, 0x0e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, + 0x66, 0x02, 0x2e, 0x02, 0x27, 0x02, 0x22, 0x02, + 0x5d, 0x02, 0x7d, 0x02, 0x2f, 0x10, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x0a, 0x69, + 0x73, 0x4e, 0x61, 0x4e, 0x26, 0x67, 0x65, 0x74, + 0x4f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, + 0x14, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x57, + 0x69, 0x74, 0x68, 0x08, 0x73, 0x6f, 0x72, 0x74, + 0x06, 0x74, 0x61, 0x62, 0x06, 0x63, 0x74, 0x78, + 0x0c, 0x73, 0x79, 0x6d, 0x63, 0x6d, 0x70, 0x02, + 0x28, 0x02, 0x29, 0x06, 0x6d, 0x61, 0x78, 0x0a, + 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x08, 0x63, 0x65, + 0x69, 0x6c, 0x0c, 0x70, 0x61, 0x64, 0x45, 0x6e, + 0x64, 0x02, 0x20, 0x0e, 0x74, 0x6f, 0x46, 0x69, + 0x78, 0x65, 0x64, 0x1a, 0x66, 0x72, 0x6f, 0x6d, + 0x43, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x69, 0x6e, + 0x74, 0x02, 0x1b, 0x02, 0x5b, 0x02, 0x4f, 0x02, + 0x3b, 0x04, 0x2d, 0x30, 0x02, 0x2d, 0x04, 0x30, + 0x78, 0x08, 0x6d, 0x61, 0x74, 0x68, 0x12, 0x42, + 0x69, 0x67, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x28, + 0x02, 0x6c, 0x02, 0x70, 0x02, 0x65, 0x04, 0x2e, + 0x30, 0x02, 0x6e, 0x12, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x5f, 0x72, 0x65, 0x63, 0x14, 0x5b, 0x63, + 0x69, 0x72, 0x63, 0x75, 0x6c, 0x61, 0x72, 0x5d, + 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, + 0x06, 0x4d, 0x6f, 0x64, 0x14, 0x50, 0x6f, 0x6c, + 0x79, 0x6e, 0x6f, 0x6d, 0x69, 0x61, 0x6c, 0x0e, + 0x50, 0x6f, 0x6c, 0x79, 0x4d, 0x6f, 0x64, 0x20, + 0x52, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x0c, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x0e, + 0x69, 0x73, 0x41, 0x72, 0x72, 0x61, 0x79, 0x04, + 0x5b, 0x20, 0x04, 0x2c, 0x20, 0x0e, 0x3c, 0x65, + 0x6d, 0x70, 0x74, 0x79, 0x3e, 0x06, 0x2e, 0x2e, + 0x2e, 0x04, 0x20, 0x5d, 0x14, 0x5f, 0x5f, 0x67, + 0x65, 0x74, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x08, + 0x6b, 0x65, 0x79, 0x73, 0x04, 0x7b, 0x20, 0x04, + 0x3a, 0x20, 0x04, 0x20, 0x7d, 0x06, 0x70, 0x6f, + 0x70, 0x0e, 0x5f, 0x5f, 0x71, 0x75, 0x6f, 0x74, + 0x65, 0x08, 0x2e, 0x2e, 0x2e, 0x22, 0x02, 0x6d, + 0x12, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x20, 0x02, 0x5c, 0x02, 0x68, 0x02, 0x3f, + 0x08, 0x6c, 0x6f, 0x61, 0x64, 0x08, 0x74, 0x72, + 0x69, 0x6d, 0x16, 0x6c, 0x61, 0x73, 0x74, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x06, 0x2e, + 0x6a, 0x73, 0x14, 0x6c, 0x6f, 0x61, 0x64, 0x53, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x02, 0x78, 0x02, + 0x64, 0x02, 0x74, 0x26, 0x42, 0x69, 0x67, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x70, 0x72, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x10, + 0x20, 0x62, 0x69, 0x74, 0x73, 0x20, 0x28, 0x7e, + 0x30, 0x20, 0x64, 0x69, 0x67, 0x69, 0x74, 0x73, + 0x29, 0x2c, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, 0x65, + 0x3d, 0x0c, 0x20, 0x62, 0x69, 0x74, 0x73, 0x0a, + 0x06, 0x66, 0x31, 0x36, 0x06, 0x66, 0x33, 0x32, + 0x06, 0x66, 0x36, 0x34, 0x08, 0x66, 0x31, 0x32, + 0x38, 0x10, 0x70, 0x61, 0x72, 0x73, 0x65, 0x49, + 0x6e, 0x74, 0x14, 0x65, 0x78, 0x70, 0x42, 0x69, + 0x74, 0x73, 0x4d, 0x61, 0x78, 0x0e, 0x70, 0x72, + 0x65, 0x63, 0x4d, 0x69, 0x6e, 0x0e, 0x70, 0x72, + 0x65, 0x63, 0x4d, 0x61, 0x78, 0x24, 0x49, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x70, 0x72, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x0a, + 0x14, 0x65, 0x78, 0x70, 0x42, 0x69, 0x74, 0x73, + 0x4d, 0x69, 0x6e, 0x2c, 0x49, 0x6e, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x69, 0x74, + 0x73, 0x0a, 0x0c, 0x64, 0x69, 0x67, 0x69, 0x74, + 0x73, 0x08, 0x6d, 0x6f, 0x64, 0x65, 0x1a, 0x52, + 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x6d, + 0x6f, 0x64, 0x65, 0x3d, 0x1a, 0x49, 0x6e, 0x76, + 0x61, 0x6c, 0x69, 0x64, 0x20, 0x6d, 0x6f, 0x64, + 0x65, 0x0a, 0x0a, 0x63, 0x6c, 0x65, 0x61, 0x72, + 0x0c, 0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x4a, 0x02, + 0x71, 0x1a, 0x61, 0x6c, 0x67, 0x65, 0x62, 0x72, + 0x61, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x26, + 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x3a, 0x20, 0x06, 0x64, 0x65, 0x63, 0x06, + 0x68, 0x65, 0x78, 0x06, 0x6e, 0x75, 0x6d, 0x06, + 0x61, 0x6c, 0x67, 0x2c, 0x5c, 0x68, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x68, 0x65, 0x6c, + 0x70, 0x0a, 0x16, 0x5c, 0x78, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x36, 0x68, + 0x65, 0x78, 0x61, 0x64, 0x65, 0x63, 0x69, 0x6d, + 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x0a, 0x16, 0x5c, 0x64, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2e, 0x64, + 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x20, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x64, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x0a, 0x16, 0x5c, + 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x2c, 0x74, 0x6f, 0x67, 0x67, 0x6c, + 0x65, 0x20, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, + 0x20, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x0a, 0x3e, 0x5c, 0x63, 0x6c, 0x65, 0x61, 0x72, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6c, + 0x65, 0x61, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, + 0x0a, 0x16, 0x5c, 0x61, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x1e, 0x61, 0x6c, + 0x67, 0x65, 0x62, 0x72, 0x61, 0x69, 0x63, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x0a, 0x16, 0x5c, 0x6e, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x1a, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, + 0x63, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x0a, 0x66, + 0x5c, 0x70, 0x20, 0x5b, 0x6d, 0x20, 0x5b, 0x65, + 0x5d, 0x5d, 0x20, 0x20, 0x73, 0x65, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x42, 0x69, 0x67, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x70, 0x72, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x27, 0x6d, 0x27, 0x20, 0x62, 0x69, + 0x74, 0x73, 0x0a, 0x84, 0x01, 0x5c, 0x64, 0x69, + 0x67, 0x69, 0x74, 0x73, 0x20, 0x6e, 0x20, 0x20, + 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x42, 0x69, 0x67, 0x46, 0x6c, 0x6f, 0x61, + 0x74, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x27, + 0x63, 0x65, 0x69, 0x6c, 0x28, 0x6e, 0x2a, 0x6c, + 0x6f, 0x67, 0x32, 0x28, 0x31, 0x30, 0x29, 0x29, + 0x27, 0x20, 0x62, 0x69, 0x74, 0x73, 0x0a, 0x68, + 0x5c, 0x6d, 0x6f, 0x64, 0x65, 0x20, 0x5b, 0x73, + 0x74, 0x64, 0x7c, 0x6d, 0x61, 0x74, 0x68, 0x5d, + 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x6e, + 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x6f, 0x64, 0x65, + 0x20, 0x28, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x20, 0x3d, 0x20, 0x04, 0x29, 0x0a, 0x22, + 0x5c, 0x71, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x65, 0x78, 0x69, 0x74, + 0x0a, 0x06, 0x73, 0x65, 0x6c, 0x3a, 0x51, 0x4a, + 0x53, 0x43, 0x61, 0x6c, 0x63, 0x20, 0x2d, 0x20, + 0x54, 0x79, 0x70, 0x65, 0x20, 0x22, 0x5c, 0x68, + 0x22, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, 0x65, + 0x6c, 0x70, 0x0a, 0x3a, 0x51, 0x75, 0x69, 0x63, + 0x6b, 0x4a, 0x53, 0x20, 0x2d, 0x20, 0x54, 0x79, + 0x70, 0x65, 0x20, 0x22, 0x5c, 0x68, 0x22, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x68, 0x65, 0x6c, 0x70, + 0x0a, 0x06, 0x6c, 0x6f, 0x67, 0x08, 0x20, 0x20, + 0x20, 0x20, 0x0e, 0x73, 0x65, 0x74, 0x50, 0x72, + 0x65, 0x63, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x26, + 0x22, 0x75, 0x73, 0x65, 0x20, 0x6d, 0x61, 0x74, + 0x68, 0x22, 0x3b, 0x20, 0x76, 0x6f, 0x69, 0x64, + 0x20, 0x30, 0x3b, 0x06, 0x6e, 0x6f, 0x77, 0x14, + 0x65, 0x76, 0x61, 0x6c, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x22, 0x62, 0x61, 0x63, 0x6b, 0x74, + 0x72, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x72, + 0x72, 0x69, 0x65, 0x72, 0x0e, 0x63, 0x6f, 0x6e, + 0x73, 0x6f, 0x6c, 0x65, 0x0e, 0x54, 0x68, 0x72, + 0x6f, 0x77, 0x3a, 0x20, 0x04, 0x67, 0x63, 0x02, + 0x7c, 0x6a, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7c, + 0x63, 0x61, 0x73, 0x65, 0x7c, 0x63, 0x61, 0x74, + 0x63, 0x68, 0x7c, 0x63, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x75, 0x65, 0x7c, 0x64, 0x65, 0x62, 0x75, + 0x67, 0x67, 0x65, 0x72, 0x7c, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x7c, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x7c, 0x64, 0x6f, 0x7c, 0x5e, + 0x65, 0x6c, 0x73, 0x65, 0x7c, 0x66, 0x69, 0x6e, + 0x61, 0x6c, 0x6c, 0x79, 0x7c, 0x66, 0x6f, 0x72, + 0x7c, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x7c, 0x69, 0x66, 0x7c, 0x69, 0x6e, 0x7c, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x6f, 0x66, 0x7c, 0x6e, 0x65, 0x77, 0x7c, 0x5e, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7c, 0x73, + 0x77, 0x69, 0x74, 0x63, 0x68, 0x7c, 0x74, 0x68, + 0x69, 0x73, 0x7c, 0x74, 0x68, 0x72, 0x6f, 0x77, + 0x7c, 0x74, 0x72, 0x79, 0x7c, 0x74, 0x79, 0x70, + 0x65, 0x6f, 0x66, 0x7c, 0x77, 0x68, 0x69, 0x6c, + 0x65, 0x7c, 0x77, 0x69, 0x74, 0x68, 0x7c, 0x5a, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x7c, 0x63, 0x6f, + 0x6e, 0x73, 0x74, 0x7c, 0x65, 0x6e, 0x75, 0x6d, + 0x7c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7c, + 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x7c, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x7c, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x7c, 0x66, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x7c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x7c, 0x6c, 0x65, 0x74, 0x7c, 0x70, + 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x7c, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x7c, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, + 0x7c, 0x28, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x7c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x7c, + 0x79, 0x69, 0x65, 0x6c, 0x64, 0x7c, 0x4e, 0x75, + 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, + 0x7c, 0x6e, 0x75, 0x6c, 0x6c, 0x7c, 0x74, 0x72, + 0x75, 0x65, 0x7c, 0x66, 0x61, 0x6c, 0x73, 0x65, + 0x7c, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x79, 0x7c, 0x4e, 0x61, 0x4e, 0x7c, 0x1e, 0x65, + 0x76, 0x61, 0x6c, 0x7c, 0x61, 0x72, 0x67, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x7c, 0x0c, 0x61, + 0x77, 0x61, 0x69, 0x74, 0x7c, 0x7a, 0x7c, 0x74, + 0x68, 0x69, 0x73, 0x7c, 0x73, 0x75, 0x70, 0x65, + 0x72, 0x7c, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x65, 0x64, 0x7c, 0x6e, 0x75, 0x6c, 0x6c, + 0x7c, 0x74, 0x72, 0x75, 0x65, 0x7c, 0x66, 0x61, + 0x6c, 0x73, 0x65, 0x7c, 0x49, 0x6e, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x79, 0x7c, 0x4e, 0x61, 0x4e, + 0x7c, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x7c, 0x14, 0x7c, 0x76, 0x6f, 0x69, + 0x64, 0x7c, 0x76, 0x61, 0x72, 0x7c, 0x02, 0x2b, + 0x02, 0x60, 0x02, 0x7b, 0x14, 0x70, 0x75, 0x73, + 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x14, + 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x70, 0x6f, 0x70, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x26, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x0a, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x02, 0x69, + 0x06, 0x73, 0x74, 0x72, 0x24, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x16, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x18, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x73, + 0x65, 0x74, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, + 0x0f, 0xc6, 0x03, 0x02, 0xc8, 0x03, 0xca, 0x03, + 0x00, 0x00, 0x02, 0x00, 0xfc, 0x01, 0x00, 0x01, + 0xfc, 0x01, 0x01, 0x00, 0x0e, 0x20, 0x02, 0x03, + 0xa2, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x01, + 0x0f, 0x00, 0xc8, 0x03, 0x00, 0x0d, 0xca, 0x03, + 0x01, 0x0d, 0x08, 0xec, 0x02, 0x29, 0xc2, 0x00, + 0x38, 0x8c, 0x00, 0x00, 0x00, 0xf1, 0x0e, 0x06, + 0x2e, 0x0e, 0x43, 0x02, 0x03, 0x00, 0x01, 0x7b, + 0x01, 0x02, 0x02, 0x4b, 0x83, 0x0a, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x01, 0x0c, 0xc2, 0x00, 0xc5, + 0x2b, 0xc2, 0x01, 0xc5, 0x2c, 0xc2, 0x02, 0xc5, + 0x2d, 0xc2, 0x03, 0xc5, 0x2e, 0xc2, 0x04, 0xc5, + 0x2f, 0xc2, 0x05, 0xc5, 0x30, 0xc2, 0x06, 0xc5, + 0x31, 0xc2, 0x07, 0xc5, 0x32, 0xc2, 0x08, 0xc5, + 0x33, 0xc2, 0x09, 0xc5, 0x34, 0xc2, 0x0a, 0xc5, + 0x35, 0xc2, 0x0b, 0xc5, 0x36, 0xc2, 0x0c, 0xc5, + 0x37, 0xc2, 0x0d, 0xc5, 0x38, 0xc2, 0x0e, 0xc5, + 0x39, 0xc2, 0x0f, 0xc5, 0x3a, 0xc2, 0x10, 0xc5, + 0x3b, 0xc2, 0x11, 0xc5, 0x3c, 0xc2, 0x12, 0xc5, + 0x3d, 0xc2, 0x13, 0xc5, 0x3e, 0xc2, 0x14, 0xc5, + 0x3f, 0xc2, 0x15, 0xc5, 0x40, 0xc2, 0x16, 0xc5, + 0x41, 0xc2, 0x17, 0xc5, 0x42, 0xc2, 0x18, 0xc5, + 0x43, 0xc2, 0x19, 0xc5, 0x44, 0xc2, 0x1a, 0xc5, + 0x45, 0xc2, 0x1b, 0xc5, 0x46, 0xc2, 0x1c, 0xc5, + 0x47, 0xc2, 0x1d, 0xc5, 0x48, 0xc2, 0x1e, 0xc5, + 0x49, 0xc2, 0x1f, 0xc5, 0x4a, 0xc2, 0x20, 0xc5, + 0x4b, 0xc2, 0x21, 0xc5, 0x4c, 0xc2, 0x22, 0xc5, + 0x4d, 0xc2, 0x23, 0xc5, 0x4e, 0xc2, 0x24, 0xc5, + 0x4f, 0xc2, 0x25, 0xc5, 0x50, 0xc2, 0x26, 0xc5, + 0x51, 0xc2, 0x27, 0xc5, 0x52, 0xc2, 0x28, 0xc5, + 0x53, 0xc2, 0x29, 0xc5, 0x54, 0xc2, 0x2a, 0xc5, + 0x55, 0xc2, 0x2b, 0xc5, 0x56, 0xc2, 0x2c, 0xc5, + 0x57, 0xc2, 0x2d, 0xc5, 0x58, 0xc2, 0x2e, 0xc5, + 0x59, 0xc2, 0x2f, 0xc5, 0x5a, 0xc2, 0x30, 0xc5, + 0x5b, 0xc2, 0x31, 0xc5, 0x5c, 0xc2, 0x32, 0xc5, + 0x5d, 0xc2, 0x33, 0xc5, 0x5e, 0xc2, 0x34, 0xc5, + 0x5f, 0xc2, 0x35, 0xc5, 0x61, 0xc2, 0x36, 0xc5, + 0x65, 0xc2, 0x37, 0xc5, 0x66, 0xc2, 0x38, 0xc5, + 0x67, 0xc2, 0x39, 0xc5, 0x68, 0xc2, 0x3a, 0xc5, + 0x6b, 0xc2, 0x3b, 0xc5, 0x6c, 0xc2, 0x3c, 0xc5, + 0x6d, 0xc2, 0x3d, 0xc5, 0x6e, 0xc2, 0x3e, 0xc5, + 0x6f, 0xc2, 0x3f, 0xc5, 0x70, 0xc2, 0x41, 0xc5, + 0x71, 0xc2, 0x42, 0xc5, 0x72, 0xc2, 0x43, 0xc5, + 0x73, 0xc2, 0x44, 0xc5, 0x74, 0xc2, 0x45, 0xc5, + 0x75, 0xc2, 0x46, 0xc5, 0x76, 0xc2, 0x47, 0xc5, + 0x77, 0xc2, 0x48, 0xc5, 0x78, 0xc2, 0x49, 0xc5, + 0x79, 0xc2, 0x4a, 0xc5, 0x7a, 0xd3, 0x66, 0x01, + 0x00, 0x43, 0xe5, 0x00, 0x00, 0x00, 0xd3, 0x66, + 0x00, 0x00, 0x43, 0xe4, 0x00, 0x00, 0x00, 0xd3, + 0x41, 0x97, 0x00, 0x00, 0x00, 0xcb, 0xd3, 0x41, + 0x9b, 0x00, 0x00, 0x00, 0xcc, 0xd3, 0x41, 0x98, + 0x00, 0x00, 0x00, 0xcd, 0xd3, 0x41, 0xa1, 0x00, + 0x00, 0x00, 0xce, 0xd3, 0x41, 0x9f, 0x00, 0x00, + 0x00, 0xc5, 0x04, 0xd3, 0x41, 0xe6, 0x00, 0x00, + 0x00, 0xc5, 0x05, 0xd3, 0x41, 0xe7, 0x00, 0x00, + 0x00, 0xc5, 0x06, 0x66, 0x01, 0x00, 0x41, 0xe8, + 0x00, 0x00, 0x00, 0xf6, 0xc5, 0x07, 0x37, 0xe9, + 0x00, 0x00, 0x00, 0xf7, 0xc5, 0x08, 0x37, 0xb5, + 0x00, 0x00, 0x00, 0xf7, 0xc5, 0x09, 0x0b, 0x04, + 0xea, 0x00, 0x00, 0x00, 0x4c, 0xeb, 0x00, 0x00, + 0x00, 0x04, 0xec, 0x00, 0x00, 0x00, 0x4c, 0xed, + 0x00, 0x00, 0x00, 0x04, 0xee, 0x00, 0x00, 0x00, + 0x4c, 0xef, 0x00, 0x00, 0x00, 0x04, 0xf0, 0x00, + 0x00, 0x00, 0x4c, 0xf1, 0x00, 0x00, 0x00, 0x04, + 0xf2, 0x00, 0x00, 0x00, 0x4c, 0xf3, 0x00, 0x00, + 0x00, 0x04, 0xf4, 0x00, 0x00, 0x00, 0x4c, 0xf5, + 0x00, 0x00, 0x00, 0x04, 0xf6, 0x00, 0x00, 0x00, + 0x4c, 0xf7, 0x00, 0x00, 0x00, 0x04, 0xf8, 0x00, + 0x00, 0x00, 0x4c, 0xf9, 0x00, 0x00, 0x00, 0x04, + 0xfa, 0x00, 0x00, 0x00, 0x4c, 0xfb, 0x00, 0x00, + 0x00, 0x04, 0xfc, 0x00, 0x00, 0x00, 0x4c, 0xfd, + 0x00, 0x00, 0x00, 0x04, 0xfc, 0x00, 0x00, 0x00, + 0x4c, 0xfe, 0x00, 0x00, 0x00, 0x04, 0xff, 0x00, + 0x00, 0x00, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x04, + 0x01, 0x01, 0x00, 0x00, 0x4c, 0x02, 0x01, 0x00, + 0x00, 0x04, 0x03, 0x01, 0x00, 0x00, 0x4c, 0x04, + 0x01, 0x00, 0x00, 0x04, 0x05, 0x01, 0x00, 0x00, + 0x4c, 0x06, 0x01, 0x00, 0x00, 0x04, 0x07, 0x01, + 0x00, 0x00, 0x4c, 0x08, 0x01, 0x00, 0x00, 0x04, + 0x09, 0x01, 0x00, 0x00, 0x4c, 0x0a, 0x01, 0x00, + 0x00, 0x04, 0x0b, 0x01, 0x00, 0x00, 0x4c, 0x0c, + 0x01, 0x00, 0x00, 0xc5, 0x0a, 0xc4, 0x07, 0xec, + 0x7e, 0x0b, 0x04, 0xed, 0x00, 0x00, 0x00, 0x4c, + 0x16, 0x00, 0x00, 0x00, 0x04, 0xfb, 0x00, 0x00, + 0x00, 0x4c, 0x0d, 0x01, 0x00, 0x00, 0x04, 0xf1, + 0x00, 0x00, 0x00, 0x4c, 0x49, 0x00, 0x00, 0x00, + 0x04, 0xf9, 0x00, 0x00, 0x00, 0x4c, 0x0e, 0x01, + 0x00, 0x00, 0x04, 0xf1, 0x00, 0x00, 0x00, 0x4c, + 0x47, 0x00, 0x00, 0x00, 0x04, 0xf5, 0x00, 0x00, + 0x00, 0x4c, 0x0f, 0x01, 0x00, 0x00, 0x04, 0xfd, + 0x00, 0x00, 0x00, 0x4c, 0x1b, 0x00, 0x00, 0x00, + 0x04, 0x08, 0x01, 0x00, 0x00, 0x4c, 0x10, 0x01, + 0x00, 0x00, 0x04, 0xf3, 0x00, 0x00, 0x00, 0x4c, + 0x11, 0x01, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x4c, 0x12, 0x01, 0x00, 0x00, 0x04, 0xed, + 0x00, 0x00, 0x00, 0x4c, 0x13, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x4c, 0x14, 0x01, + 0x00, 0x00, 0xc5, 0x0b, 0xee, 0x7c, 0x0b, 0x04, + 0x02, 0x01, 0x00, 0x00, 0x4c, 0x16, 0x00, 0x00, + 0x00, 0x04, 0xfb, 0x00, 0x00, 0x00, 0x4c, 0x0d, + 0x01, 0x00, 0x00, 0x04, 0x0a, 0x01, 0x00, 0x00, + 0x4c, 0x49, 0x00, 0x00, 0x00, 0x04, 0xf9, 0x00, + 0x00, 0x00, 0x4c, 0x0e, 0x01, 0x00, 0x00, 0x04, + 0xf1, 0x00, 0x00, 0x00, 0x4c, 0x47, 0x00, 0x00, + 0x00, 0x04, 0x0c, 0x01, 0x00, 0x00, 0x4c, 0x0f, + 0x01, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x00, + 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x08, 0x01, + 0x00, 0x00, 0x4c, 0x10, 0x01, 0x00, 0x00, 0x04, + 0x02, 0x01, 0x00, 0x00, 0x4c, 0x11, 0x01, 0x00, + 0x00, 0x04, 0xef, 0x00, 0x00, 0x00, 0x4c, 0x12, + 0x01, 0x00, 0x00, 0x04, 0x0c, 0x01, 0x00, 0x00, + 0x4c, 0x13, 0x01, 0x00, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x00, 0x4c, 0x14, 0x01, 0x00, 0x00, 0xc5, + 0x0b, 0x26, 0x00, 0x00, 0xc5, 0x0c, 0xc3, 0xc5, + 0x0d, 0xc3, 0xc5, 0x11, 0xc3, 0xc5, 0x12, 0xb7, + 0xc5, 0x13, 0xc4, 0x07, 0xec, 0x0a, 0x04, 0x15, + 0x01, 0x00, 0x00, 0xc5, 0x14, 0xee, 0x08, 0x04, + 0x16, 0x01, 0x00, 0x00, 0xc5, 0x14, 0x04, 0x17, + 0x01, 0x00, 0x00, 0xc5, 0x15, 0x0a, 0xc5, 0x16, + 0x09, 0xc5, 0x17, 0x0a, 0xc5, 0x18, 0xb7, 0xc5, + 0x1a, 0xc3, 0xc5, 0x1b, 0xb7, 0xc5, 0x1c, 0xc3, + 0xc5, 0x1d, 0xb7, 0xc5, 0x1e, 0xc3, 0xc5, 0x1f, + 0xb7, 0xc5, 0x20, 0x09, 0xc5, 0x24, 0xb7, 0xc5, + 0x25, 0xb7, 0xc5, 0x26, 0xb7, 0xc5, 0x2a, 0x0b, + 0xc4, 0x3d, 0x4c, 0x18, 0x01, 0x00, 0x00, 0xc4, + 0x40, 0x4c, 0x19, 0x01, 0x00, 0x00, 0xc4, 0x5a, + 0x4c, 0x1a, 0x01, 0x00, 0x00, 0xc4, 0x4e, 0x4c, + 0x1b, 0x01, 0x00, 0x00, 0xc4, 0x3e, 0x4c, 0x1c, + 0x01, 0x00, 0x00, 0xc4, 0x3f, 0x4c, 0x1d, 0x01, + 0x00, 0x00, 0xc4, 0x3b, 0x4c, 0x1e, 0x01, 0x00, + 0x00, 0xc4, 0x4f, 0x4c, 0x1f, 0x01, 0x00, 0x00, + 0xc4, 0x5f, 0x4c, 0x20, 0x01, 0x00, 0x00, 0xc4, + 0x45, 0x4c, 0x21, 0x01, 0x00, 0x00, 0xc4, 0x55, + 0x4c, 0x22, 0x01, 0x00, 0x00, 0xc4, 0x45, 0x4c, + 0x23, 0x01, 0x00, 0x00, 0xc4, 0x48, 0x4c, 0x24, + 0x01, 0x00, 0x00, 0xc4, 0x47, 0x4c, 0x25, 0x01, + 0x00, 0x00, 0xc4, 0x3a, 0x4c, 0x26, 0x01, 0x00, + 0x00, 0xc4, 0x3c, 0x4c, 0x27, 0x01, 0x00, 0x00, + 0xc4, 0x3c, 0x4c, 0x28, 0x01, 0x00, 0x00, 0xc4, + 0x50, 0x4c, 0x29, 0x01, 0x00, 0x00, 0xc4, 0x5b, + 0x4c, 0x2a, 0x01, 0x00, 0x00, 0xc4, 0x59, 0x4c, + 0x2b, 0x01, 0x00, 0x00, 0xc4, 0x47, 0x4c, 0x2c, + 0x01, 0x00, 0x00, 0xc4, 0x48, 0x4c, 0x2d, 0x01, + 0x00, 0x00, 0xc4, 0x3f, 0x4c, 0x2e, 0x01, 0x00, + 0x00, 0xc4, 0x40, 0x4c, 0x2f, 0x01, 0x00, 0x00, + 0xc4, 0x43, 0x4c, 0x30, 0x01, 0x00, 0x00, 0xc4, + 0x44, 0x4c, 0x31, 0x01, 0x00, 0x00, 0xc4, 0x43, + 0x4c, 0x32, 0x01, 0x00, 0x00, 0xc4, 0x44, 0x4c, + 0x33, 0x01, 0x00, 0x00, 0xc4, 0x3d, 0x4c, 0x34, + 0x01, 0x00, 0x00, 0xc4, 0x4d, 0x4c, 0x35, 0x01, + 0x00, 0x00, 0xc4, 0x3e, 0x4c, 0x36, 0x01, 0x00, + 0x00, 0xc4, 0x4a, 0x4c, 0x37, 0x01, 0x00, 0x00, + 0xc4, 0x4b, 0x4c, 0x38, 0x01, 0x00, 0x00, 0xc4, + 0x47, 0x4c, 0x39, 0x01, 0x00, 0x00, 0xc4, 0x48, + 0x4c, 0x3a, 0x01, 0x00, 0x00, 0xc4, 0x3f, 0x4c, + 0x3b, 0x01, 0x00, 0x00, 0xc4, 0x40, 0x4c, 0x3c, + 0x01, 0x00, 0x00, 0xc4, 0x3e, 0x4c, 0x3d, 0x01, + 0x00, 0x00, 0xc4, 0x3d, 0x4c, 0x3e, 0x01, 0x00, + 0x00, 0xc4, 0x58, 0x4c, 0x3f, 0x01, 0x00, 0x00, + 0xc4, 0x44, 0x4c, 0x40, 0x01, 0x00, 0x00, 0xc4, + 0x57, 0x4c, 0x41, 0x01, 0x00, 0x00, 0xc4, 0x43, + 0x4c, 0x42, 0x01, 0x00, 0x00, 0xc4, 0x56, 0x4c, + 0x43, 0x01, 0x00, 0x00, 0xc4, 0x53, 0x4c, 0x44, + 0x01, 0x00, 0x00, 0xc4, 0x51, 0x4c, 0x45, 0x01, + 0x00, 0x00, 0xc4, 0x52, 0x4c, 0x46, 0x01, 0x00, + 0x00, 0xc4, 0x4f, 0x4c, 0x47, 0x01, 0x00, 0x00, + 0xc5, 0x60, 0x09, 0xc5, 0x69, 0x04, 0xe4, 0x00, + 0x00, 0x00, 0xc5, 0x6a, 0xc4, 0x07, 0xec, 0x09, + 0xd3, 0xc2, 0x40, 0x43, 0x48, 0x01, 0x00, 0x00, + 0xc4, 0x2b, 0xf0, 0x0e, 0xc4, 0x72, 0xf0, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0x92, 0x05, 0x00, 0x01, + 0x00, 0x04, 0x07, 0x00, 0x8b, 0x01, 0x00, 0x00, + 0x27, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x29, 0x01, + 0x00, 0x01, 0x0c, 0x00, 0x2c, 0x01, 0x00, 0x28, + 0x01, 0x00, 0x2d, 0x01, 0x66, 0x01, 0x00, 0x41, + 0x0d, 0x00, 0x00, 0x00, 0x42, 0x4a, 0x01, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xe3, 0xbf, 0x50, 0xe5, + 0x66, 0x03, 0x00, 0x42, 0x4b, 0x01, 0x00, 0x00, + 0xdf, 0x24, 0x01, 0x00, 0xec, 0x35, 0x66, 0x03, + 0x00, 0x41, 0x4c, 0x01, 0x00, 0x00, 0xec, 0x14, + 0x66, 0x03, 0x00, 0x42, 0x4c, 0x01, 0x00, 0x00, + 0xdf, 0x24, 0x01, 0x00, 0xcf, 0xec, 0x05, 0xc7, + 0xb7, 0x47, 0xe5, 0x66, 0x03, 0x00, 0x41, 0x4d, + 0x01, 0x00, 0x00, 0xec, 0x0e, 0x66, 0x03, 0x00, + 0x42, 0x4d, 0x01, 0x00, 0x00, 0xdf, 0x24, 0x01, + 0x00, 0x0e, 0x66, 0x03, 0x00, 0x42, 0x4e, 0x01, + 0x00, 0x00, 0x66, 0x03, 0x00, 0x41, 0x4f, 0x01, + 0x00, 0x00, 0x5e, 0x04, 0x00, 0x24, 0x02, 0x00, + 0x0e, 0x38, 0xaa, 0x00, 0x00, 0x00, 0x11, 0xbf, + 0x40, 0x21, 0x01, 0x00, 0x5f, 0x05, 0x00, 0x66, + 0x03, 0x00, 0x42, 0x50, 0x01, 0x00, 0x00, 0xdf, + 0x5e, 0x06, 0x00, 0x24, 0x02, 0x00, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xa2, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x04, 0x00, 0xa4, 0x05, 0x2e, + 0x01, 0xdf, 0xba, 0xf1, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xa6, 0x05, 0x00, 0x02, 0x00, 0x06, 0x04, + 0x00, 0x28, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x27, + 0x01, 0x00, 0x28, 0x01, 0x00, 0x2e, 0x01, 0x66, + 0x00, 0x00, 0x42, 0x54, 0x01, 0x00, 0x00, 0xe0, + 0xe1, 0x41, 0x55, 0x01, 0x00, 0x00, 0xb7, 0xe1, + 0xeb, 0x24, 0x04, 0x00, 0xcb, 0xb7, 0xcc, 0xc8, + 0xc7, 0xa4, 0xec, 0x0b, 0xe2, 0xe1, 0xc8, 0x47, + 0xf1, 0x0e, 0x94, 0x01, 0xee, 0xf2, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xa4, 0x05, 0x01, 0x00, 0x01, + 0x04, 0x04, 0x00, 0x5f, 0x00, 0x00, 0x16, 0x01, + 0x00, 0x67, 0x01, 0x00, 0x25, 0x01, 0x00, 0x26, + 0x01, 0xdf, 0x97, 0xec, 0x06, 0xe0, 0xd3, 0xf1, + 0x0e, 0x29, 0xe1, 0xb7, 0xad, 0xec, 0x24, 0xd3, + 0xc0, 0x80, 0x00, 0xa7, 0xec, 0x1d, 0xd3, 0xc0, + 0xc0, 0x00, 0xa4, 0xec, 0x16, 0xe2, 0xbd, 0xa1, + 0xd3, 0xbf, 0x3f, 0xae, 0xb0, 0xe6, 0xe1, 0x8f, + 0xe9, 0xb7, 0xac, 0xec, 0x33, 0xe0, 0xe2, 0xf1, + 0x0e, 0x29, 0xd3, 0xc0, 0xc0, 0x00, 0xa7, 0xec, + 0x21, 0xd3, 0xc0, 0xf8, 0x00, 0xa4, 0xec, 0x1a, + 0xb8, 0xd3, 0xc0, 0xe0, 0x00, 0xa7, 0x9e, 0xd3, + 0xc0, 0xf0, 0x00, 0xa7, 0x9e, 0xe5, 0xd3, 0xb8, + 0xbd, 0xe1, 0x9f, 0xa1, 0xb8, 0x9f, 0xae, 0xe6, + 0x29, 0xb7, 0xe5, 0xe0, 0xd3, 0xf1, 0x0e, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xac, 0x05, 0x01, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x35, 0x00, 0xd3, 0x98, + 0x04, 0x49, 0x00, 0x00, 0x00, 0xac, 0x11, 0xec, + 0x2a, 0x0e, 0xd3, 0x04, 0x57, 0x01, 0x00, 0x00, + 0xa7, 0x11, 0xec, 0x09, 0x0e, 0xd3, 0x04, 0x58, + 0x01, 0x00, 0x00, 0xa5, 0x11, 0xed, 0x14, 0x0e, + 0xd3, 0x04, 0x59, 0x01, 0x00, 0x00, 0xa7, 0x11, + 0xec, 0x09, 0x0e, 0xd3, 0x04, 0x5a, 0x01, 0x00, + 0x00, 0xa5, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xb6, + 0x05, 0x01, 0x00, 0x01, 0x02, 0x00, 0x02, 0x19, + 0x00, 0xd3, 0x98, 0x04, 0x49, 0x00, 0x00, 0x00, + 0xac, 0x11, 0xec, 0x0e, 0x0e, 0xd3, 0xc1, 0x00, + 0xa7, 0x11, 0xec, 0x06, 0x0e, 0xd3, 0xc1, 0x01, + 0xa5, 0x28, 0x07, 0x02, 0x30, 0x07, 0x02, 0x39, + 0x0e, 0x43, 0x02, 0x03, 0xb8, 0x05, 0x01, 0x00, + 0x01, 0x02, 0x02, 0x00, 0x2d, 0x00, 0x00, 0x2f, + 0x01, 0x00, 0x30, 0x01, 0xd3, 0x98, 0x04, 0x49, + 0x00, 0x00, 0x00, 0xac, 0x11, 0xec, 0x22, 0x0e, + 0xdf, 0xd3, 0xf1, 0x11, 0xed, 0x1b, 0x0e, 0xe0, + 0xd3, 0xf1, 0x11, 0xed, 0x14, 0x0e, 0xd3, 0x04, + 0x5d, 0x01, 0x00, 0x00, 0xaa, 0x11, 0xed, 0x09, + 0x0e, 0xd3, 0x04, 0x5e, 0x01, 0x00, 0x00, 0xaa, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xbe, 0x05, 0x01, + 0x04, 0x01, 0x03, 0x00, 0x00, 0x32, 0x00, 0xd3, + 0xeb, 0xce, 0xb7, 0xcb, 0xb7, 0xcd, 0xc9, 0xca, + 0xa4, 0xec, 0x25, 0xd3, 0x42, 0x60, 0x01, 0x00, + 0x00, 0xc9, 0x24, 0x01, 0x00, 0xd0, 0x01, 0x00, + 0xdc, 0x00, 0x00, 0xa4, 0x11, 0xed, 0x09, 0x0e, + 0xc8, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xa7, 0xec, + 0x03, 0x94, 0x00, 0x94, 0x02, 0xee, 0xd8, 0xc7, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc2, 0x05, 0x01, + 0x01, 0x01, 0x03, 0x00, 0x00, 0x29, 0x00, 0xd3, + 0x98, 0x04, 0x49, 0x00, 0x00, 0x00, 0xad, 0xec, + 0x03, 0x09, 0x28, 0xd3, 0x42, 0x62, 0x01, 0x00, + 0x00, 0xb7, 0x24, 0x01, 0x00, 0xcf, 0x01, 0x00, + 0xdc, 0x00, 0x00, 0xa7, 0x11, 0xec, 0x09, 0x0e, + 0xc7, 0x01, 0x00, 0xe0, 0x00, 0x00, 0xa4, 0x28, + 0x0e, 0x43, 0x02, 0x03, 0xc6, 0x05, 0x02, 0x00, + 0x02, 0x03, 0x00, 0x00, 0x23, 0x00, 0xd3, 0xd4, + 0x9e, 0x11, 0x04, 0x64, 0x01, 0x00, 0x00, 0xac, + 0xed, 0x13, 0x11, 0x04, 0x65, 0x01, 0x00, 0x00, + 0xac, 0xed, 0x0a, 0x11, 0x04, 0x66, 0x01, 0x00, + 0x00, 0xac, 0xec, 0x03, 0x0a, 0x28, 0x0e, 0x09, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xce, 0x05, 0x03, + 0x03, 0x03, 0x06, 0x03, 0x00, 0x63, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x0a, 0x01, 0x00, 0x0b, 0x01, + 0xd4, 0xcc, 0xc8, 0xd3, 0xeb, 0xa4, 0xec, 0x5b, + 0xd5, 0xc8, 0xcf, 0x47, 0xcd, 0xc8, 0x90, 0xd0, + 0xd3, 0xeb, 0xa4, 0xec, 0x08, 0xd5, 0xc8, 0x47, + 0xc9, 0xaa, 0xed, 0xf2, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xe0, 0xe1, 0xc9, 0x47, + 0x11, 0xed, 0x07, 0x0e, 0x04, 0x16, 0x00, 0x00, + 0x00, 0x47, 0x24, 0x01, 0x00, 0x0e, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xd3, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xc7, 0xc8, 0x24, 0x02, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x66, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0xe0, 0x04, 0xeb, + 0x00, 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, 0x0e, + 0xee, 0xa1, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xd4, + 0x05, 0x02, 0x00, 0x02, 0x05, 0x01, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x0c, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x6b, 0x01, 0x00, + 0x00, 0xd3, 0xb8, 0xab, 0xec, 0x04, 0xd3, 0xee, + 0x02, 0xc3, 0x9e, 0xd4, 0x9e, 0x24, 0x01, 0x00, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xd8, 0x05, 0x01, + 0x02, 0x01, 0x04, 0x05, 0x00, 0xa1, 0x01, 0x00, + 0x00, 0x2a, 0x01, 0x00, 0x29, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x04, 0x01, 0x00, 0x36, 0x01, 0xd3, + 0xb7, 0xa6, 0xec, 0x4d, 0xd3, 0xb7, 0xab, 0x6a, + 0x97, 0x00, 0x00, 0x00, 0xdf, 0xe0, 0xb8, 0x9f, + 0xaa, 0xec, 0x19, 0x66, 0x02, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xb7, 0xe3, 0xd3, 0x8f, + 0xd7, 0xee, 0xda, 0xe2, 0x42, 0x6d, 0x01, 0x00, + 0x00, 0xe0, 0xb8, 0x9f, 0xdf, 0x9f, 0xd3, 0x24, + 0x02, 0x00, 0xcc, 0x5e, 0x04, 0x00, 0xc8, 0x04, + 0x6e, 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0xc8, + 0x9f, 0xd7, 0xdf, 0xc8, 0x9e, 0xe3, 0xee, 0xb5, + 0xd3, 0x8d, 0xd7, 0xd3, 0xb7, 0xab, 0xec, 0x48, + 0xdf, 0xb7, 0xaa, 0xec, 0x22, 0x5e, 0x04, 0x00, + 0xb8, 0x04, 0x57, 0x01, 0x00, 0x00, 0xf2, 0x0e, + 0x5e, 0x04, 0x00, 0xe0, 0xb8, 0x9f, 0x04, 0x6e, + 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0x8f, 0xd7, + 0xe0, 0xb8, 0x9f, 0xe3, 0xee, 0xd6, 0xe2, 0x42, + 0x6d, 0x01, 0x00, 0x00, 0xd3, 0xdf, 0x24, 0x02, + 0x00, 0xcc, 0x5e, 0x04, 0x00, 0xc8, 0x04, 0x6f, + 0x01, 0x00, 0x00, 0xf2, 0x0e, 0xd3, 0xc8, 0x9f, + 0xd7, 0xdf, 0xc8, 0x9f, 0xe3, 0xee, 0xb5, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xe0, 0x05, 0x00, 0x05, + 0x00, 0x06, 0x0d, 0x00, 0x9c, 0x02, 0x00, 0x00, + 0x1d, 0x01, 0x00, 0x1f, 0x01, 0x00, 0x18, 0x01, + 0x00, 0x20, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x37, + 0x01, 0x00, 0x32, 0x01, 0x00, 0x1b, 0x01, 0x00, + 0x7a, 0x01, 0x00, 0x35, 0x01, 0x00, 0x2a, 0x01, + 0x00, 0x29, 0x01, 0x00, 0x1e, 0x01, 0xdf, 0xe0, + 0xab, 0x6a, 0xc6, 0x00, 0x00, 0x00, 0xe1, 0x97, + 0xec, 0x32, 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb7, 0xe2, 0x24, 0x02, 0x00, 0xdf, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xb7, 0xe2, 0x24, 0x02, 0x00, + 0xaa, 0xec, 0x19, 0x66, 0x04, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0xdf, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xe2, 0x24, 0x01, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xee, 0x53, 0x5e, 0x05, 0x00, 0x5e, 0x06, + 0x00, 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb7, + 0xe2, 0x24, 0x02, 0x00, 0xf1, 0x8d, 0xf1, 0x0e, + 0xe1, 0xec, 0x2e, 0x5e, 0x07, 0x00, 0xec, 0x0e, + 0x5e, 0x07, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x9e, 0xdf, 0x9e, 0xee, 0x02, 0xdf, 0xd1, 0xeb, + 0xdf, 0xeb, 0x9f, 0xce, 0x5e, 0x08, 0x00, 0xc9, + 0xf1, 0xc5, 0x04, 0x5e, 0x09, 0x00, 0xc9, 0xca, + 0xc4, 0x04, 0xb9, 0x47, 0xf3, 0x0e, 0xee, 0x0e, + 0x66, 0x04, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0xdf, 0x24, 0x01, 0x00, 0x0e, 0x5e, 0x0a, 0x00, + 0x5e, 0x06, 0x00, 0xdf, 0xf1, 0x9e, 0x5e, 0x0b, + 0x00, 0x9d, 0x60, 0x0a, 0x00, 0xb7, 0xaa, 0xec, + 0x12, 0x66, 0x04, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x71, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x66, 0x04, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x72, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xdf, 0xe4, 0xdf, 0xeb, 0xe6, + 0x5e, 0x0c, 0x00, 0xe2, 0xa6, 0xec, 0x19, 0x5e, + 0x05, 0x00, 0x5e, 0x06, 0x00, 0xdf, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xe2, 0x5e, 0x0c, 0x00, 0x24, + 0x02, 0x00, 0xf1, 0xf1, 0x0e, 0xee, 0x1f, 0x5e, + 0x0c, 0x00, 0xe2, 0xa4, 0xec, 0x18, 0x5e, 0x05, + 0x00, 0x5e, 0x06, 0x00, 0xdf, 0x42, 0x69, 0x01, + 0x00, 0x00, 0x5e, 0x0c, 0x00, 0xe2, 0x24, 0x02, + 0x00, 0xf1, 0x8d, 0xf1, 0x0e, 0x5e, 0x0c, 0x00, + 0xe6, 0x66, 0x04, 0x00, 0x41, 0x73, 0x01, 0x00, + 0x00, 0x42, 0x74, 0x01, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xea, 0x05, + 0x01, 0x00, 0x01, 0x04, 0x02, 0x00, 0x22, 0x00, + 0x00, 0x1d, 0x01, 0x00, 0x1e, 0x01, 0xd3, 0xec, + 0x1f, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb7, + 0xe0, 0x24, 0x02, 0x00, 0xd3, 0x9e, 0xdf, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, + 0x9e, 0xe3, 0xe0, 0xd3, 0xeb, 0x9e, 0xe4, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xec, 0x05, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0xee, 0x05, + 0x24, 0x01, 0x0a, 0xe3, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xf0, 0x05, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x07, 0x00, 0xf2, 0x05, 0x1d, 0x01, 0xf4, + 0x05, 0x1e, 0x01, 0xc3, 0xe3, 0xb7, 0xe4, 0xbf, + 0xfe, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xf6, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xf8, 0x05, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0xf4, + 0x05, 0x1e, 0x01, 0xb7, 0xe3, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xfa, 0x05, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x04, 0x00, 0xf4, 0x05, 0x1e, 0x01, + 0xf2, 0x05, 0x1d, 0x01, 0xe0, 0xeb, 0xe3, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xfc, 0x05, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x1d, 0x00, 0xf4, 0x05, + 0x1e, 0x01, 0xf2, 0x05, 0x1d, 0x01, 0xc2, 0x05, + 0x33, 0x01, 0xdf, 0xe0, 0xeb, 0xa4, 0xec, 0x17, + 0xdf, 0x90, 0xe3, 0xe1, 0xe0, 0x42, 0x7f, 0x01, + 0x00, 0x00, 0xdf, 0x24, 0x01, 0x00, 0xf1, 0xec, + 0x06, 0xdf, 0x90, 0xe3, 0xee, 0xee, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0x80, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x03, 0x00, 0x1c, 0x00, 0xf4, 0x05, 0x1e, + 0x01, 0xc2, 0x05, 0x33, 0x01, 0xf2, 0x05, 0x1d, + 0x01, 0xdf, 0xb7, 0xa6, 0xec, 0x17, 0xdf, 0x8f, + 0xe3, 0xe0, 0xe1, 0x42, 0x7f, 0x01, 0x00, 0x00, + 0xdf, 0x24, 0x01, 0x00, 0xf1, 0xec, 0x06, 0xdf, + 0x8f, 0xe3, 0xee, 0xee, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0x82, 0x06, 0x01, 0x00, 0x01, 0x04, 0x02, + 0x00, 0x35, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x31, + 0x01, 0xd3, 0xdf, 0xeb, 0xa4, 0xec, 0x15, 0xe0, + 0xdf, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0xf1, 0x97, 0xec, 0x06, 0xd3, 0x90, + 0xd7, 0xee, 0xe7, 0xd3, 0xdf, 0xeb, 0xa4, 0xec, + 0x14, 0xe0, 0xdf, 0x42, 0x7f, 0x01, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0xf1, 0xec, 0x06, 0xd3, + 0x90, 0xd7, 0xee, 0xe8, 0xd3, 0x28, 0x0e, 0x43, + 0x02, 0x03, 0x84, 0x06, 0x01, 0x00, 0x01, 0x05, + 0x02, 0x00, 0x37, 0x00, 0x00, 0x31, 0x01, 0x00, + 0x1d, 0x01, 0xd3, 0xb7, 0xa6, 0xec, 0x17, 0xdf, + 0xe0, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xd3, 0xb8, + 0x9f, 0x24, 0x01, 0x00, 0xf1, 0x97, 0xec, 0x06, + 0xd3, 0x8f, 0xd7, 0xee, 0xe6, 0xd3, 0xb7, 0xa6, + 0xec, 0x16, 0xdf, 0xe0, 0x42, 0x7f, 0x01, 0x00, + 0x00, 0xd3, 0xb8, 0x9f, 0x24, 0x01, 0x00, 0xf1, + 0xec, 0x06, 0xd3, 0x8f, 0xd7, 0xee, 0xe7, 0xd3, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0x86, 0x06, 0x00, + 0x00, 0x00, 0x02, 0x02, 0x00, 0x05, 0x00, 0xf4, + 0x05, 0x1e, 0x01, 0x82, 0x06, 0x41, 0x01, 0xe0, + 0xdf, 0xf1, 0xe3, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x88, 0x06, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x05, 0x00, 0xf4, 0x05, 0x1e, 0x01, 0x84, 0x06, + 0x42, 0x01, 0xe0, 0xdf, 0xf1, 0xe3, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0x8a, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x03, 0x00, 0x17, 0x00, 0xc8, 0x03, 0x00, + 0x0c, 0x8c, 0x06, 0x46, 0x01, 0xf2, 0x05, 0x1d, + 0x01, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xe0, 0xe1, 0xf1, 0x0e, 0xb6, 0x28, + 0x0e, 0x43, 0x02, 0x03, 0x8c, 0x06, 0x01, 0x00, + 0x01, 0x03, 0x02, 0x00, 0x12, 0x00, 0x00, 0x0c, + 0x01, 0x00, 0x21, 0x01, 0xd3, 0xec, 0x0c, 0xdf, + 0x42, 0x87, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0x0e, 0xdf, 0xeb, 0xe4, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0x90, 0x06, 0x00, 0x00, 0x00, 0x03, + 0x04, 0x00, 0x20, 0x00, 0x92, 0x06, 0x21, 0x01, + 0x94, 0x06, 0x0c, 0x01, 0xf2, 0x05, 0x1d, 0x01, + 0xf4, 0x05, 0x1e, 0x01, 0xdf, 0xb7, 0xa6, 0xec, + 0x1b, 0xdf, 0xe0, 0xeb, 0xaa, 0xec, 0x0c, 0xe0, + 0x42, 0x87, 0x01, 0x00, 0x00, 0xe1, 0x24, 0x01, + 0x00, 0x0e, 0xdf, 0x8f, 0xe3, 0xe0, 0xdf, 0x47, + 0xe9, 0xeb, 0xe6, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x96, 0x06, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00, + 0x12, 0x00, 0x92, 0x06, 0x21, 0x01, 0x94, 0x06, + 0x0c, 0x01, 0xf2, 0x05, 0x1d, 0x01, 0xf4, 0x05, + 0x1e, 0x01, 0xdf, 0xe0, 0xeb, 0xb8, 0x9f, 0xa4, + 0xec, 0x0a, 0xdf, 0x90, 0xe3, 0xe0, 0xdf, 0x47, + 0xe9, 0xeb, 0xe6, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x98, 0x06, 0x01, 0x03, 0x01, 0x05, 0x04, 0x00, + 0x3d, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x0c, 0x01, + 0x00, 0x21, 0x01, 0x00, 0x1d, 0x01, 0xdf, 0xcb, + 0xb8, 0xcc, 0xc8, 0xe0, 0xeb, 0xa5, 0xec, 0x33, + 0xe0, 0xeb, 0xc8, 0xd3, 0x9b, 0x9e, 0xe1, 0x9e, + 0xe0, 0xeb, 0x9d, 0xcd, 0xe0, 0xc9, 0x47, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xb7, 0xc7, 0x24, 0x02, + 0x00, 0xe2, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb7, + 0xc7, 0x24, 0x02, 0x00, 0xaa, 0xec, 0x08, 0xc9, + 0xe5, 0xe0, 0xc9, 0x47, 0xe6, 0x29, 0x94, 0x01, + 0xee, 0xc9, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x9a, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, + 0x00, 0x98, 0x06, 0x49, 0x01, 0xdf, 0xb6, 0x23, + 0x01, 0x00, 0x0e, 0x43, 0x02, 0x03, 0x9c, 0x06, + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x05, 0x00, + 0x98, 0x06, 0x49, 0x01, 0xdf, 0xb8, 0x23, 0x01, + 0x00, 0x0e, 0x43, 0x02, 0x03, 0x9e, 0x06, 0x01, + 0x02, 0x01, 0x04, 0x05, 0x00, 0x66, 0x00, 0x00, + 0x1e, 0x01, 0x00, 0x33, 0x01, 0x00, 0x1d, 0x01, + 0x00, 0x23, 0x01, 0x00, 0x54, 0x01, 0xdf, 0xcb, + 0xd3, 0xb7, 0xa4, 0xec, 0x15, 0x93, 0x00, 0xe0, + 0xe1, 0x42, 0x7f, 0x01, 0x00, 0x00, 0xc7, 0x24, + 0x01, 0x00, 0xf1, 0xec, 0x05, 0x93, 0x00, 0xee, + 0xef, 0xc7, 0xb8, 0x9e, 0xcc, 0xe0, 0xe1, 0x42, + 0x7f, 0x01, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, + 0xf1, 0xec, 0x05, 0x94, 0x01, 0xee, 0xef, 0xc7, + 0xb7, 0xa7, 0xec, 0x30, 0xc7, 0xe1, 0xeb, 0xa4, + 0xec, 0x2a, 0xe2, 0x5e, 0x04, 0x00, 0xac, 0xec, + 0x0a, 0x5e, 0x04, 0x00, 0xc7, 0xc8, 0xd3, 0xf3, + 0x0e, 0x29, 0xe1, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb7, 0xc7, 0x24, 0x02, 0x00, 0xe1, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, 0x9e, + 0xe5, 0xc7, 0xe3, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xa0, 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, + 0x04, 0x00, 0x9e, 0x06, 0x4c, 0x01, 0xdf, 0xb8, + 0xf1, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa2, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x1f, 0x00, + 0xf2, 0x05, 0x1d, 0x01, 0xc8, 0x03, 0x00, 0x0c, + 0x9e, 0x06, 0x4c, 0x01, 0xdf, 0xeb, 0xb7, 0xaa, + 0xec, 0x15, 0x66, 0x01, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xbf, 0xfd, 0x28, 0xe1, 0xb8, + 0xf1, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa4, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x04, + 0x00, 0x9e, 0x06, 0x4c, 0x01, 0xdf, 0xb6, 0xf1, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa6, 0x06, 0x00, + 0x01, 0x00, 0x06, 0x02, 0x00, 0x51, 0x00, 0x00, + 0x1e, 0x01, 0x00, 0x1d, 0x01, 0xdf, 0xcb, 0xe0, + 0xeb, 0xb8, 0xa6, 0xec, 0x49, 0xc7, 0xb7, 0xa6, + 0xec, 0x44, 0xc7, 0xe0, 0xeb, 0xaa, 0xec, 0x03, + 0x93, 0x00, 0xe0, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb7, 0xc7, 0xb8, 0x9f, 0x24, 0x02, 0x00, 0xe0, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xc7, 0xc7, 0xb8, + 0x9e, 0x24, 0x02, 0x00, 0x9e, 0xe0, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xc7, 0xb8, 0x9f, 0xc7, 0x24, + 0x02, 0x00, 0x9e, 0xe0, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xc7, 0xb8, 0x9e, 0x24, 0x01, 0x00, 0x9e, + 0xe4, 0xc7, 0xb8, 0x9e, 0xe3, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xa8, 0x06, 0x00, 0x04, 0x00, 0x05, + 0x04, 0x00, 0x57, 0x00, 0x00, 0x42, 0x01, 0x00, + 0x1e, 0x01, 0x00, 0x41, 0x01, 0x00, 0x1d, 0x01, + 0xdf, 0xe0, 0xf1, 0xcb, 0xe1, 0xc7, 0xf1, 0xcc, + 0xe1, 0xe0, 0xf1, 0xcd, 0xdf, 0xc9, 0xf1, 0xce, + 0xc7, 0xc8, 0xa4, 0xec, 0x42, 0xc8, 0xe0, 0xa5, + 0xec, 0x3d, 0xe0, 0xca, 0xa5, 0xec, 0x38, 0xca, + 0xc9, 0xa4, 0xec, 0x33, 0xe2, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xb7, 0xc7, 0x24, 0x02, 0x00, 0xe2, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xca, 0xc9, 0x24, + 0x02, 0x00, 0x9e, 0xe2, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xc8, 0xca, 0x24, 0x02, 0x00, 0x9e, 0xe2, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xc7, 0xc8, 0x24, + 0x02, 0x00, 0x9e, 0xe6, 0xc9, 0xe4, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0xaa, 0x06, 0x00, 0x01, 0x00, + 0x05, 0x03, 0x00, 0x30, 0x00, 0x00, 0x41, 0x01, + 0x00, 0x1e, 0x01, 0x00, 0x1d, 0x01, 0xdf, 0xe0, + 0xf1, 0xcb, 0xe1, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xb7, 0xe0, 0x24, 0x02, 0x00, 0xe1, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xe0, 0xc7, 0x24, 0x02, 0x00, + 0x42, 0x96, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x9e, 0xe1, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc7, + 0x24, 0x01, 0x00, 0x9e, 0xe5, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xae, 0x06, 0x00, 0x01, 0x00, 0x05, + 0x03, 0x00, 0x30, 0x00, 0x00, 0x41, 0x01, 0x00, + 0x1e, 0x01, 0x00, 0x1d, 0x01, 0xdf, 0xe0, 0xf1, + 0xcb, 0xe1, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb7, + 0xe0, 0x24, 0x02, 0x00, 0xe1, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xe0, 0xc7, 0x24, 0x02, 0x00, 0x42, + 0x98, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9e, + 0xe1, 0x42, 0x69, 0x01, 0x00, 0x00, 0xc7, 0x24, + 0x01, 0x00, 0x9e, 0xe5, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xb2, 0x06, 0x03, 0x01, 0x03, 0x04, 0x06, + 0x00, 0x5e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x23, + 0x01, 0x00, 0x54, 0x01, 0x00, 0x0d, 0x01, 0x00, + 0x1e, 0x01, 0x00, 0x22, 0x01, 0xdf, 0x42, 0x69, + 0x01, 0x00, 0x00, 0xd3, 0xd4, 0x24, 0x02, 0x00, + 0xcb, 0xe0, 0xe1, 0xad, 0xec, 0x05, 0xc7, 0xe6, + 0xee, 0x10, 0xd5, 0xb7, 0xa4, 0xec, 0x07, 0xc7, + 0xe2, 0x9e, 0xe6, 0xee, 0x05, 0xe2, 0xc7, 0x9e, + 0xe6, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, 0xb7, + 0xd3, 0x24, 0x02, 0x00, 0xdf, 0x42, 0x69, 0x01, + 0x00, 0x00, 0xd4, 0x24, 0x01, 0x00, 0x9e, 0xe3, + 0x5e, 0x04, 0x00, 0xd4, 0xa6, 0xec, 0x0d, 0x5e, + 0x04, 0x00, 0xd4, 0xd3, 0x9f, 0x9f, 0x5f, 0x04, + 0x00, 0xee, 0x0c, 0x5e, 0x04, 0x00, 0xd3, 0xa6, + 0xec, 0x05, 0xd3, 0x5f, 0x04, 0x00, 0xe1, 0x5f, + 0x05, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xb4, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x07, + 0x00, 0xb2, 0x06, 0x54, 0x01, 0xf4, 0x05, 0x1e, + 0x01, 0xf2, 0x05, 0x1d, 0x01, 0xdf, 0xe0, 0xe1, + 0xeb, 0xb8, 0xf3, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xb6, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, + 0x06, 0x00, 0xb2, 0x06, 0x54, 0x01, 0xf4, 0x05, + 0x1e, 0x01, 0xdf, 0xb7, 0xe0, 0xb6, 0xf3, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xb8, 0x06, 0x00, 0x00, + 0x00, 0x04, 0x03, 0x00, 0x08, 0x00, 0xb2, 0x06, + 0x54, 0x01, 0xf4, 0x05, 0x1e, 0x01, 0x82, 0x06, + 0x41, 0x01, 0xdf, 0xe0, 0xe1, 0xe0, 0xf1, 0xb8, + 0xf3, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xba, 0x06, + 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x08, 0x00, + 0xb2, 0x06, 0x54, 0x01, 0x84, 0x06, 0x42, 0x01, + 0xf4, 0x05, 0x1e, 0x01, 0xdf, 0xe0, 0xe1, 0xf1, + 0xe1, 0xb6, 0xf3, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xbc, 0x06, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x04, 0x00, 0xea, 0x05, 0x39, 0x01, 0xbe, 0x06, + 0x0d, 0x01, 0xdf, 0xe0, 0xf1, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x03, + 0x04, 0x00, 0x39, 0x00, 0xc2, 0x06, 0x23, 0x01, + 0xc0, 0x06, 0x5a, 0x01, 0xc8, 0x03, 0x00, 0x0c, + 0xc4, 0x06, 0x65, 0x01, 0xdf, 0xe0, 0xac, 0xec, + 0x20, 0x66, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x66, 0x02, 0x00, 0x42, 0xa3, 0x01, + 0x00, 0x00, 0xb7, 0x24, 0x01, 0x00, 0x0e, 0x29, + 0x66, 0x02, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0xa4, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xe2, 0xf0, 0x0e, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xca, 0x06, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x05, 0x00, 0xf2, 0x05, 0x1d, 0x01, 0xf4, + 0x05, 0x1e, 0x01, 0xc3, 0xe3, 0xb7, 0xe4, 0x29, + 0x0e, 0x43, 0x02, 0x03, 0xcc, 0x06, 0x02, 0x01, + 0x02, 0x04, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x31, + 0x01, 0xc3, 0xcb, 0xd4, 0xb7, 0xa6, 0xec, 0x15, + 0xdf, 0xd3, 0xd4, 0xb8, 0x9f, 0x47, 0xf1, 0xec, + 0x0c, 0xd4, 0x8f, 0xd8, 0xd3, 0xd4, 0x47, 0xc7, + 0x9e, 0xcb, 0xee, 0xe8, 0xc7, 0x28, 0x0e, 0x43, + 0x02, 0x03, 0xce, 0x06, 0x02, 0x06, 0x02, 0x05, + 0x7e, 0x02, 0x87, 0x02, 0x08, 0xd0, 0x06, 0x00, + 0x01, 0x00, 0xd2, 0x06, 0x00, 0x01, 0x00, 0xd4, + 0x06, 0x00, 0x00, 0x00, 0xd6, 0x06, 0x00, 0x01, + 0x00, 0xd8, 0x06, 0x00, 0x02, 0x00, 0x10, 0x00, + 0x01, 0x00, 0xe4, 0x01, 0x00, 0x01, 0x00, 0x9c, + 0x01, 0x00, 0x01, 0x00, 0xda, 0x06, 0x00, 0x03, + 0xae, 0x02, 0x00, 0x01, 0xb6, 0x02, 0x01, 0x01, + 0xb0, 0x02, 0x02, 0x01, 0xc2, 0x02, 0x03, 0x01, + 0xbe, 0x02, 0x04, 0x01, 0xcc, 0x03, 0x05, 0x01, + 0xce, 0x03, 0x06, 0x01, 0xdc, 0x06, 0x07, 0x01, + 0xde, 0x06, 0x08, 0x01, 0xe0, 0x06, 0x09, 0x01, + 0xe2, 0x06, 0x0a, 0x01, 0xe4, 0x06, 0x0b, 0x01, + 0x94, 0x06, 0x0c, 0x01, 0xbe, 0x06, 0x0d, 0x01, + 0xe6, 0x06, 0x0e, 0x01, 0xe8, 0x06, 0x0f, 0x01, + 0xea, 0x06, 0x10, 0x01, 0xec, 0x06, 0x11, 0x01, + 0xee, 0x06, 0x12, 0x01, 0xf0, 0x06, 0x13, 0x01, + 0xf2, 0x06, 0x14, 0x01, 0xf4, 0x06, 0x15, 0x01, + 0xf6, 0x06, 0x16, 0x01, 0xf8, 0x06, 0x17, 0x01, + 0xfa, 0x06, 0x18, 0x01, 0xfc, 0x06, 0x19, 0x01, + 0xfe, 0x06, 0x1a, 0x01, 0x80, 0x07, 0x1b, 0x01, + 0x82, 0x07, 0x1c, 0x01, 0xf2, 0x05, 0x1d, 0x01, + 0xf4, 0x05, 0x1e, 0x01, 0x84, 0x07, 0x1f, 0x01, + 0x86, 0x07, 0x20, 0x01, 0x92, 0x06, 0x21, 0x01, + 0x88, 0x07, 0x22, 0x01, 0xc2, 0x06, 0x23, 0x01, + 0xee, 0x05, 0x24, 0x01, 0x8a, 0x07, 0x25, 0x01, + 0x8c, 0x07, 0x26, 0x01, 0x8e, 0x07, 0x27, 0x01, + 0x90, 0x07, 0x28, 0x01, 0x92, 0x07, 0x29, 0x01, + 0x94, 0x07, 0x2a, 0x01, 0x92, 0x05, 0x2b, 0x01, + 0xa2, 0x05, 0x2c, 0x01, 0xa6, 0x05, 0x2d, 0x01, + 0xa4, 0x05, 0x2e, 0x01, 0xac, 0x05, 0x2f, 0x01, + 0xb6, 0x05, 0x30, 0x01, 0xb8, 0x05, 0x31, 0x01, + 0xbe, 0x05, 0x32, 0x01, 0xc2, 0x05, 0x33, 0x01, + 0xc6, 0x05, 0x34, 0x01, 0xce, 0x05, 0x35, 0x01, + 0xd4, 0x05, 0x36, 0x01, 0xd8, 0x05, 0x37, 0x01, + 0xe0, 0x05, 0x38, 0x01, 0xea, 0x05, 0x39, 0x01, + 0xec, 0x05, 0x3a, 0x01, 0xf0, 0x05, 0x3b, 0x01, + 0xf6, 0x05, 0x3c, 0x01, 0xf8, 0x05, 0x3d, 0x01, + 0xfa, 0x05, 0x3e, 0x01, 0xfc, 0x05, 0x3f, 0x01, + 0x80, 0x06, 0x40, 0x01, 0x82, 0x06, 0x41, 0x01, + 0x84, 0x06, 0x42, 0x01, 0x86, 0x06, 0x43, 0x01, + 0x88, 0x06, 0x44, 0x01, 0x8a, 0x06, 0x45, 0x01, + 0x8c, 0x06, 0x46, 0x01, 0x90, 0x06, 0x47, 0x01, + 0x96, 0x06, 0x48, 0x01, 0x98, 0x06, 0x49, 0x01, + 0x9a, 0x06, 0x4a, 0x01, 0x9c, 0x06, 0x4b, 0x01, + 0x9e, 0x06, 0x4c, 0x01, 0xa0, 0x06, 0x4d, 0x01, + 0xa2, 0x06, 0x4e, 0x01, 0xa4, 0x06, 0x4f, 0x01, + 0xa6, 0x06, 0x50, 0x01, 0xa8, 0x06, 0x51, 0x01, + 0xaa, 0x06, 0x52, 0x01, 0xae, 0x06, 0x53, 0x01, + 0xb2, 0x06, 0x54, 0x01, 0xb4, 0x06, 0x55, 0x01, + 0xb6, 0x06, 0x56, 0x01, 0xb8, 0x06, 0x57, 0x01, + 0xba, 0x06, 0x58, 0x01, 0xbc, 0x06, 0x59, 0x01, + 0xc0, 0x06, 0x5a, 0x01, 0xca, 0x06, 0x5b, 0x01, + 0xcc, 0x06, 0x5c, 0x01, 0xce, 0x06, 0x5d, 0x01, + 0x96, 0x07, 0x5e, 0x01, 0x98, 0x07, 0x5f, 0x01, + 0x9a, 0x07, 0x60, 0x01, 0x9c, 0x07, 0x61, 0x01, + 0x9e, 0x07, 0x62, 0x01, 0xa0, 0x07, 0x63, 0x01, + 0xa2, 0x07, 0x64, 0x01, 0xc4, 0x06, 0x65, 0x01, + 0xa4, 0x07, 0x66, 0x01, 0xa6, 0x07, 0x67, 0x01, + 0xa8, 0x07, 0x68, 0x01, 0xaa, 0x07, 0x69, 0x01, + 0xac, 0x07, 0x6a, 0x01, 0xae, 0x07, 0x6b, 0x01, + 0xb0, 0x07, 0x6c, 0x01, 0xb2, 0x07, 0x6d, 0x01, + 0xb4, 0x07, 0x6e, 0x01, 0xb6, 0x07, 0x6f, 0x01, + 0xb8, 0x07, 0x70, 0x01, 0xba, 0x07, 0x71, 0x01, + 0xbc, 0x07, 0x72, 0x01, 0xbe, 0x07, 0x73, 0x01, + 0xc0, 0x07, 0x74, 0x01, 0xc2, 0x07, 0x75, 0x01, + 0xc4, 0x07, 0x76, 0x01, 0xc6, 0x07, 0x77, 0x01, + 0xc8, 0x07, 0x78, 0x01, 0xca, 0x07, 0x79, 0x01, + 0xcc, 0x07, 0x7a, 0x01, 0xc8, 0x03, 0x00, 0x0c, + 0xca, 0x03, 0x01, 0x0c, 0x0c, 0x03, 0xc5, 0x04, + 0x08, 0xce, 0x0c, 0x00, 0xc5, 0x05, 0xd4, 0xb7, + 0xa5, 0x11, 0xed, 0x16, 0x0e, 0x04, 0xe7, 0x01, + 0x00, 0x00, 0x42, 0xe8, 0x01, 0x00, 0x00, 0xd3, + 0xd4, 0xb8, 0x9f, 0x47, 0x24, 0x01, 0x00, 0xb7, + 0xa7, 0xec, 0x03, 0xdf, 0x28, 0xd4, 0xb9, 0xa7, + 0x6a, 0xd9, 0x00, 0x00, 0x00, 0xd3, 0xd4, 0xb8, + 0x9f, 0x47, 0x04, 0xe9, 0x01, 0x00, 0x00, 0xac, + 0x6a, 0xc9, 0x00, 0x00, 0x00, 0xd4, 0x8f, 0xd8, + 0x0b, 0xcb, 0xd3, 0xd4, 0xb8, 0x9f, 0x47, 0xd1, + 0x11, 0x04, 0xea, 0x01, 0x00, 0x00, 0xac, 0xed, + 0x0a, 0x11, 0x04, 0xeb, 0x01, 0x00, 0x00, 0xac, + 0xec, 0x07, 0x04, 0x59, 0x01, 0x00, 0x00, 0x28, + 0x11, 0x04, 0xec, 0x01, 0x00, 0x00, 0xac, 0xec, + 0x05, 0x26, 0x00, 0x00, 0x28, 0x11, 0x04, 0xed, + 0x01, 0x00, 0x00, 0xac, 0xec, 0x03, 0x0b, 0x28, + 0x11, 0x04, 0xee, 0x01, 0x00, 0x00, 0xac, 0xec, + 0x07, 0xc1, 0x00, 0xc1, 0x01, 0x33, 0x28, 0x5e, + 0x32, 0x00, 0xc9, 0xf1, 0xec, 0x73, 0x5e, 0x5d, + 0x00, 0xd3, 0xd4, 0xf2, 0xcc, 0x04, 0x03, 0x00, + 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x04, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, + 0x00, 0x26, 0x04, 0x00, 0x42, 0xef, 0x01, 0x00, + 0x00, 0xc8, 0x24, 0x01, 0x00, 0x11, 0xed, 0x0b, + 0x0e, 0x38, 0xf0, 0x01, 0x00, 0x00, 0xc8, 0x8e, + 0xf1, 0x97, 0xec, 0x0d, 0x38, 0x3b, 0x00, 0x00, + 0x00, 0xc8, 0x31, 0x01, 0x00, 0x00, 0x00, 0x28, + 0x5e, 0x5e, 0x00, 0xd3, 0xd4, 0xc8, 0xeb, 0x9f, + 0xf2, 0xcf, 0xf5, 0x11, 0xed, 0x04, 0x0e, 0xc7, + 0xf4, 0xec, 0x03, 0xc7, 0x28, 0xc7, 0xdf, 0xac, + 0xec, 0x13, 0xc7, 0xc8, 0x47, 0xf4, 0xec, 0x0d, + 0x38, 0x3b, 0x00, 0x00, 0x00, 0xc8, 0x31, 0x01, + 0x00, 0x00, 0x00, 0x28, 0xc7, 0xc8, 0x47, 0x28, + 0x0b, 0x28, 0x29, 0x07, 0x02, 0x20, 0x07, 0x34, + 0x00, 0x01, 0x00, 0x13, 0x00, 0x00, 0x00, 0x08, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x07, 0xf5, 0xff, + 0xff, 0xff, 0x0b, 0x00, 0x01, 0x20, 0x00, 0x0c, + 0x00, 0x0a, 0x0e, 0x43, 0x02, 0x03, 0x96, 0x07, + 0x02, 0x0a, 0x02, 0x04, 0x03, 0x01, 0xe3, 0x01, + 0x00, 0x00, 0x5c, 0x01, 0x00, 0x5d, 0x01, 0x00, + 0x00, 0x01, 0xdf, 0xd3, 0xd4, 0xf2, 0xcb, 0xe0, + 0xd3, 0xd4, 0xc7, 0xeb, 0x9f, 0xf2, 0xcd, 0x26, + 0x00, 0x00, 0xce, 0xb7, 0xc5, 0x04, 0xc9, 0xcc, + 0xc4, 0x04, 0xbf, 0x0a, 0xa4, 0xec, 0x67, 0xc8, + 0xf5, 0xed, 0x63, 0xc8, 0x06, 0xad, 0xec, 0x5e, + 0xe1, 0x42, 0xf1, 0x01, 0x00, 0x00, 0xc8, 0x24, + 0x01, 0x00, 0xc5, 0x07, 0xb7, 0xc5, 0x05, 0xc4, + 0x05, 0xc4, 0x07, 0xeb, 0xa4, 0xec, 0x38, 0xc4, + 0x07, 0xc4, 0x05, 0x47, 0xc6, 0x08, 0x98, 0x04, + 0x49, 0x00, 0x00, 0x00, 0xaa, 0xec, 0x24, 0xc3, + 0xc4, 0x08, 0x8e, 0x9e, 0xc4, 0x08, 0xab, 0xec, + 0x1a, 0xc4, 0x08, 0x42, 0xf2, 0x01, 0x00, 0x00, + 0xc7, 0x24, 0x01, 0x00, 0xec, 0x0d, 0xca, 0x42, + 0x87, 0x01, 0x00, 0x00, 0xc4, 0x08, 0x24, 0x01, + 0x00, 0x0e, 0x94, 0x05, 0xee, 0xc2, 0xe1, 0x42, + 0x60, 0x00, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, + 0xcc, 0x94, 0x04, 0xee, 0x94, 0xca, 0xeb, 0xb8, + 0xa6, 0xec, 0x46, 0xc2, 0x00, 0xc5, 0x09, 0xc2, + 0x00, 0x0e, 0xca, 0x42, 0xf3, 0x01, 0x00, 0x00, + 0x62, 0x09, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xb8, + 0xc6, 0x05, 0xc5, 0x04, 0xc4, 0x04, 0xca, 0xeb, + 0xa4, 0xec, 0x1e, 0xca, 0xc4, 0x04, 0x47, 0xca, + 0xc4, 0x04, 0xb8, 0x9f, 0x47, 0xab, 0xec, 0x0d, + 0xca, 0xc4, 0x05, 0x92, 0xc5, 0x05, 0x73, 0xca, + 0xc4, 0x04, 0x47, 0x49, 0x94, 0x04, 0xee, 0xdd, + 0xca, 0xc4, 0x05, 0x43, 0x30, 0x00, 0x00, 0x00, + 0x0b, 0xca, 0x4c, 0xf4, 0x01, 0x00, 0x00, 0xc7, + 0xeb, 0x4c, 0xa9, 0x01, 0x00, 0x00, 0xc9, 0x4c, + 0xf5, 0x01, 0x00, 0x00, 0x28, 0x0e, 0x43, 0x02, + 0x03, 0xec, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, + 0x00, 0x34, 0x00, 0xd3, 0xb7, 0x47, 0xd4, 0xb7, + 0x47, 0xab, 0xec, 0x1b, 0xd3, 0xb7, 0x47, 0x04, + 0x5d, 0x01, 0x00, 0x00, 0xaa, 0xec, 0x03, 0xb8, + 0x28, 0xd4, 0xb7, 0x47, 0x04, 0x5d, 0x01, 0x00, + 0x00, 0xaa, 0xec, 0x03, 0xb6, 0x28, 0xd3, 0xd4, + 0xa4, 0xec, 0x03, 0xb6, 0x28, 0xd3, 0xd4, 0xa6, + 0xec, 0x04, 0xb8, 0x8e, 0x28, 0xb7, 0x28, 0x0e, + 0x43, 0x02, 0x03, 0x98, 0x07, 0x00, 0x0d, 0x00, + 0x07, 0x0a, 0x00, 0x8f, 0x03, 0x00, 0x00, 0x5e, + 0x01, 0x00, 0x1d, 0x01, 0x00, 0x1e, 0x01, 0x00, + 0x39, 0x01, 0x00, 0x23, 0x01, 0x00, 0x5f, 0x01, + 0x00, 0x04, 0x01, 0x00, 0x29, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x65, 0x01, 0xdf, 0xe0, 0xe1, 0xf2, + 0xd0, 0x41, 0xf4, 0x01, 0x00, 0x00, 0xcf, 0xeb, + 0xb7, 0xac, 0xec, 0x02, 0x29, 0xc7, 0xb7, 0x47, + 0xd1, 0xeb, 0xc5, 0x05, 0xb8, 0xce, 0xca, 0xc7, + 0xeb, 0xa4, 0xec, 0x2a, 0xc7, 0xca, 0x47, 0xc5, + 0x06, 0xb7, 0xc5, 0x04, 0xc4, 0x04, 0xc4, 0x05, + 0xa4, 0xec, 0x17, 0xc4, 0x06, 0xc4, 0x04, 0x47, + 0xc9, 0xc4, 0x04, 0x47, 0xad, 0xec, 0x07, 0xc4, + 0x04, 0xc5, 0x05, 0xee, 0x05, 0x94, 0x04, 0xee, + 0xe4, 0x94, 0x03, 0xee, 0xd2, 0xc8, 0x41, 0xa9, + 0x01, 0x00, 0x00, 0xce, 0xca, 0xc4, 0x05, 0xa4, + 0xec, 0x0b, 0xe2, 0xc9, 0xca, 0x47, 0xf1, 0x0e, + 0x94, 0x03, 0xee, 0xf1, 0x5e, 0x04, 0x00, 0x5e, + 0x05, 0x00, 0xac, 0xec, 0x42, 0xc7, 0xeb, 0xb8, + 0xaa, 0xec, 0x3c, 0xc8, 0x41, 0xf5, 0x01, 0x00, + 0x00, 0xc7, 0xb7, 0x47, 0x47, 0xc6, 0x0c, 0xf7, + 0xec, 0x1a, 0xe2, 0x04, 0xf7, 0x01, 0x00, 0x00, + 0xf1, 0x0e, 0xc4, 0x0c, 0xeb, 0xb7, 0xaa, 0xec, + 0x1e, 0xe2, 0x04, 0xf8, 0x01, 0x00, 0x00, 0xf1, + 0x0e, 0xee, 0x14, 0xc4, 0x0c, 0x98, 0x04, 0x4a, + 0x00, 0x00, 0x00, 0xaa, 0xec, 0x09, 0xe2, 0x04, + 0xe9, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0x5e, 0x04, + 0x00, 0x5e, 0x05, 0x00, 0xac, 0x6a, 0xdc, 0x00, + 0x00, 0x00, 0xc7, 0xeb, 0xb9, 0xa7, 0x6a, 0xd3, + 0x00, 0x00, 0x00, 0xb7, 0xc5, 0x07, 0xb7, 0xce, + 0xca, 0xc7, 0xeb, 0xa4, 0xec, 0x18, 0x5e, 0x06, + 0x00, 0x42, 0xf9, 0x01, 0x00, 0x00, 0xc4, 0x07, + 0xc7, 0xca, 0x47, 0xeb, 0x24, 0x02, 0x00, 0xc5, + 0x07, 0x94, 0x03, 0xee, 0xe4, 0xb9, 0x95, 0x07, + 0x5e, 0x06, 0x00, 0x42, 0xf9, 0x01, 0x00, 0x00, + 0xb8, 0x5e, 0x06, 0x00, 0x42, 0xfa, 0x01, 0x00, + 0x00, 0x5e, 0x07, 0x00, 0xb8, 0x9e, 0xc4, 0x07, + 0x9c, 0x24, 0x01, 0x00, 0x24, 0x02, 0x00, 0xc5, + 0x09, 0x5e, 0x06, 0x00, 0x42, 0xfb, 0x01, 0x00, + 0x00, 0xc7, 0xeb, 0xc4, 0x09, 0x9c, 0x24, 0x01, + 0x00, 0xc5, 0x0b, 0x66, 0x08, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xb7, 0xc5, 0x0a, 0xc4, + 0x0a, 0xc4, 0x0b, 0xa4, 0xec, 0x58, 0xb7, 0xc5, + 0x08, 0xc4, 0x08, 0xc4, 0x09, 0xa4, 0xec, 0x39, + 0xc4, 0x08, 0xc4, 0x0b, 0x9b, 0xc4, 0x0a, 0x9e, + 0xd2, 0xc7, 0xeb, 0xa7, 0xed, 0x2b, 0xc7, 0xca, + 0x47, 0xcd, 0xc4, 0x08, 0xc4, 0x09, 0xb8, 0x9f, + 0xab, 0xec, 0x0d, 0xc9, 0x42, 0xfc, 0x01, 0x00, + 0x00, 0xc4, 0x07, 0x24, 0x01, 0x00, 0xcd, 0x66, + 0x08, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xc9, + 0x24, 0x01, 0x00, 0x0e, 0x94, 0x08, 0xee, 0xc2, + 0x66, 0x08, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x21, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0x94, 0x0a, 0xee, 0xa3, 0x5e, 0x09, 0x00, + 0xf0, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x9c, + 0x07, 0x02, 0x01, 0x02, 0x02, 0x00, 0x00, 0x10, + 0x00, 0xc3, 0xcb, 0xd4, 0x91, 0xd8, 0xb7, 0xa6, + 0xec, 0x06, 0xd3, 0x95, 0x00, 0xee, 0xf5, 0xc7, + 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc4, 0x06, 0x00, + 0x00, 0x00, 0x03, 0x07, 0x00, 0x1e, 0x00, 0xc8, + 0x03, 0x00, 0x0c, 0xee, 0x06, 0x12, 0x01, 0x94, + 0x07, 0x2a, 0x01, 0xbe, 0x05, 0x32, 0x01, 0x92, + 0x07, 0x29, 0x01, 0x84, 0x07, 0x1f, 0x01, 0x86, + 0x07, 0x20, 0x01, 0x66, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, 0x0e, + 0xe2, 0xe0, 0xf1, 0x5e, 0x04, 0x00, 0x9d, 0xe5, + 0xc3, 0x5f, 0x05, 0x00, 0xb7, 0x5f, 0x06, 0x00, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa4, 0x07, 0x02, + 0x01, 0x02, 0x05, 0x11, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x1d, 0x01, 0x00, 0x1e, 0x01, 0x00, 0x21, + 0x01, 0x00, 0x0c, 0x01, 0x00, 0x64, 0x01, 0x00, + 0x12, 0x01, 0x00, 0x11, 0x01, 0x00, 0x1b, 0x01, + 0x00, 0x61, 0x01, 0x00, 0x13, 0x01, 0x00, 0x15, + 0x01, 0x00, 0x17, 0x01, 0x00, 0x1a, 0x01, 0x00, + 0x14, 0x01, 0x00, 0x65, 0x01, 0x00, 0x38, 0x01, + 0x00, 0x63, 0x01, 0xd3, 0x11, 0xed, 0x03, 0x0e, + 0xc3, 0xe7, 0xeb, 0xe4, 0xe2, 0xeb, 0xe5, 0xd4, + 0x5f, 0x04, 0x00, 0x5e, 0x06, 0x00, 0x5f, 0x05, + 0x00, 0x5e, 0x07, 0x00, 0xec, 0x22, 0x5e, 0x05, + 0x00, 0x5e, 0x08, 0x00, 0x04, 0xfd, 0x01, 0x00, + 0x00, 0x5e, 0x09, 0x00, 0x5e, 0x05, 0x00, 0xeb, + 0x9f, 0xf2, 0x9e, 0x60, 0x05, 0x00, 0x5e, 0x0a, + 0x00, 0x9e, 0x5f, 0x05, 0x00, 0xee, 0x36, 0x5e, + 0x0b, 0x00, 0xec, 0x20, 0x5e, 0x0c, 0x00, 0xc0, + 0xe8, 0x03, 0x9c, 0xcb, 0x5e, 0x05, 0x00, 0xc7, + 0x42, 0xfe, 0x01, 0x00, 0x00, 0xbd, 0x24, 0x01, + 0x00, 0x04, 0xfd, 0x01, 0x00, 0x00, 0x9e, 0x9e, + 0x5f, 0x05, 0x00, 0x5e, 0x05, 0x00, 0xeb, 0x5f, + 0x09, 0x00, 0x5e, 0x05, 0x00, 0x5e, 0x0d, 0x00, + 0x9e, 0x5f, 0x05, 0x00, 0x5e, 0x0e, 0x00, 0xf0, + 0x0e, 0x5e, 0x0f, 0x00, 0xf0, 0x0e, 0xb7, 0x5f, + 0x10, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xa6, + 0x07, 0x01, 0x01, 0x01, 0x03, 0x04, 0x02, 0x8c, + 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x63, 0x01, + 0x00, 0x62, 0x01, 0x00, 0x68, 0x01, 0xdf, 0x42, + 0xff, 0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, + 0xcb, 0xe0, 0x11, 0xb7, 0xac, 0xec, 0x16, 0xc7, + 0x04, 0x00, 0x02, 0x00, 0x00, 0xaa, 0xec, 0x07, + 0xc7, 0xe5, 0xb8, 0xe4, 0xee, 0x6c, 0xe2, 0xc7, + 0xf1, 0x0e, 0xee, 0x66, 0x11, 0xb8, 0xac, 0xec, + 0x27, 0xe1, 0xc7, 0x9e, 0xe5, 0xc7, 0x04, 0x01, + 0x02, 0x00, 0x00, 0xaa, 0xec, 0x05, 0xb9, 0xe4, + 0xee, 0x50, 0xc7, 0x04, 0x02, 0x02, 0x00, 0x00, + 0xaa, 0xec, 0x05, 0xba, 0xe4, 0xee, 0x43, 0xe2, + 0xe1, 0xf1, 0x0e, 0xb7, 0xe4, 0xee, 0x3b, 0x11, + 0xb9, 0xac, 0xec, 0x27, 0xe1, 0xc7, 0x9e, 0xe5, + 0xc7, 0x04, 0x03, 0x02, 0x00, 0x00, 0xaa, 0x11, + 0xed, 0x0e, 0x0e, 0xc7, 0xc1, 0x00, 0xa7, 0x11, + 0xec, 0x06, 0x0e, 0xc7, 0xc1, 0x01, 0xa5, 0x97, + 0xec, 0x18, 0xe2, 0xe1, 0xf1, 0x0e, 0xb7, 0xe4, + 0xee, 0x10, 0x11, 0xba, 0xac, 0xec, 0x0b, 0xe1, + 0xc7, 0x9e, 0xe5, 0xe2, 0xe1, 0xf1, 0x0e, 0xb7, + 0xe4, 0x29, 0x07, 0x02, 0x30, 0x07, 0x02, 0x39, + 0x0e, 0x43, 0x02, 0x03, 0xa8, 0x07, 0x01, 0x01, + 0x01, 0x05, 0x0d, 0x00, 0xb0, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x32, 0x01, 0x00, 0x39, 0x01, + 0x00, 0x60, 0x01, 0x00, 0x22, 0x01, 0x00, 0x64, + 0x01, 0x00, 0x1d, 0x01, 0x00, 0x01, 0x0c, 0x00, + 0x27, 0x01, 0x00, 0x23, 0x01, 0x00, 0x3c, 0x01, + 0x00, 0x1e, 0x01, 0x00, 0x38, 0x01, 0xdf, 0xec, + 0x10, 0xe0, 0xd3, 0xf1, 0xb8, 0xac, 0xec, 0x05, + 0xe1, 0xd3, 0xf1, 0x0e, 0x09, 0xe3, 0xee, 0x7a, + 0xe2, 0xd3, 0x47, 0xcf, 0xec, 0x55, 0xc7, 0x5f, + 0x04, 0x00, 0xc7, 0xd3, 0xf1, 0x11, 0xb6, 0xac, + 0xec, 0x09, 0x5e, 0x05, 0x00, 0x5e, 0x06, 0x00, + 0xf1, 0x29, 0x11, 0xbf, 0xfe, 0xac, 0xec, 0x07, + 0x5e, 0x05, 0x00, 0x07, 0xf1, 0x29, 0x11, 0xbf, + 0xfd, 0xac, 0xec, 0x26, 0x66, 0x07, 0x00, 0x42, + 0x4e, 0x01, 0x00, 0x00, 0x66, 0x07, 0x00, 0x41, + 0x4f, 0x01, 0x00, 0x00, 0x07, 0x24, 0x02, 0x00, + 0x0e, 0x66, 0x07, 0x00, 0x42, 0x50, 0x01, 0x00, + 0x00, 0x5e, 0x08, 0x00, 0x07, 0x24, 0x02, 0x00, + 0x29, 0x0e, 0x5e, 0x04, 0x00, 0x5f, 0x09, 0x00, + 0xee, 0x20, 0xe0, 0xd3, 0xf1, 0xb8, 0xac, 0xec, + 0x14, 0xd3, 0x04, 0xfd, 0x01, 0x00, 0x00, 0xa7, + 0xec, 0x0b, 0xe1, 0xd3, 0xf1, 0x0e, 0xe1, 0x5f, + 0x09, 0x00, 0xee, 0x06, 0x5e, 0x0a, 0x00, 0xf0, + 0x0e, 0x5e, 0x0b, 0x00, 0xb7, 0xa4, 0xec, 0x04, + 0xb7, 0xee, 0x14, 0x5e, 0x0b, 0x00, 0x5e, 0x06, + 0x00, 0xeb, 0xa6, 0xec, 0x07, 0x5e, 0x06, 0x00, + 0xeb, 0xee, 0x04, 0x5e, 0x0b, 0x00, 0x5f, 0x0b, + 0x00, 0x5e, 0x0c, 0x00, 0xf0, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0xae, 0x07, 0x02, 0x01, 0x02, 0x05, + 0x02, 0x01, 0x70, 0x00, 0x00, 0x05, 0x01, 0x00, + 0x04, 0x01, 0xdf, 0xd3, 0xf1, 0x97, 0xec, 0x0a, + 0xd3, 0x42, 0x38, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0xd3, 0xb7, 0xaa, 0xec, 0x15, 0xb8, 0xd3, + 0x9c, 0xb7, 0xa4, 0xec, 0x09, 0x04, 0x04, 0x02, + 0x00, 0x00, 0xcb, 0xee, 0x4c, 0xc1, 0x00, 0xcb, + 0xee, 0x47, 0xd4, 0xbf, 0x10, 0xaa, 0xec, 0x37, + 0xd3, 0xe0, 0x42, 0xfa, 0x01, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0xac, 0xec, 0x29, 0xd3, 0xb7, + 0xa4, 0xec, 0x0c, 0xd3, 0x8d, 0xd7, 0x04, 0x05, + 0x02, 0x00, 0x00, 0xcb, 0xee, 0x03, 0xc3, 0xcb, + 0xc7, 0x04, 0x06, 0x02, 0x00, 0x00, 0xd3, 0x42, + 0x38, 0x00, 0x00, 0x00, 0xbf, 0x10, 0x24, 0x01, + 0x00, 0x9e, 0x9e, 0xcb, 0xee, 0x0b, 0xd3, 0x42, + 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0xcb, + 0xc7, 0x28, 0x07, 0x02, 0x30, 0x0e, 0x43, 0x02, + 0x03, 0xb0, 0x07, 0x02, 0x01, 0x02, 0x05, 0x01, + 0x01, 0xfe, 0x01, 0x00, 0x00, 0x6a, 0x01, 0x38, + 0xb5, 0x00, 0x00, 0x00, 0x42, 0xe6, 0x00, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0x97, 0xec, 0x29, + 0xdf, 0x04, 0x07, 0x02, 0x00, 0x00, 0xad, 0xec, + 0x17, 0x04, 0x08, 0x02, 0x00, 0x00, 0xd3, 0x42, + 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x9e, + 0x04, 0xf8, 0x01, 0x00, 0x00, 0x9e, 0x28, 0xd3, + 0x42, 0x38, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, + 0xd3, 0xb7, 0xaa, 0xec, 0x15, 0xb8, 0xd3, 0x9c, + 0xb7, 0xa4, 0xec, 0x09, 0x04, 0x04, 0x02, 0x00, + 0x00, 0xcb, 0xee, 0x3e, 0xc1, 0x00, 0xcb, 0xee, + 0x39, 0xd4, 0xbf, 0x10, 0xaa, 0xec, 0x29, 0xd3, + 0xb7, 0xa4, 0xec, 0x0c, 0xd3, 0x8d, 0xd7, 0x04, + 0x05, 0x02, 0x00, 0x00, 0xcb, 0xee, 0x03, 0xc3, + 0xcb, 0xc7, 0x04, 0x06, 0x02, 0x00, 0x00, 0xd3, + 0x42, 0x38, 0x00, 0x00, 0x00, 0xbf, 0x10, 0x24, + 0x01, 0x00, 0x9e, 0x9e, 0xcb, 0xee, 0x0b, 0xd3, + 0x42, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcb, 0xd3, 0x98, 0x04, 0x8e, 0x00, 0x00, 0x00, + 0xac, 0xec, 0x13, 0xdf, 0x04, 0x07, 0x02, 0x00, + 0x00, 0xad, 0xec, 0x0a, 0x04, 0x09, 0x02, 0x00, + 0x00, 0x95, 0x00, 0xee, 0x57, 0xdf, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0xad, 0xec, 0x4e, 0xc7, 0x42, + 0xe8, 0x01, 0x00, 0x00, 0x04, 0xe9, 0x01, 0x00, + 0x00, 0x24, 0x01, 0x00, 0xb7, 0xa4, 0xec, 0x3c, + 0xd4, 0xbf, 0x10, 0xaa, 0x11, 0xec, 0x12, 0x0e, + 0xc7, 0x42, 0xe8, 0x01, 0x00, 0x00, 0x04, 0x0a, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0xb7, 0xa4, + 0x11, 0xed, 0x18, 0x0e, 0xd4, 0xbf, 0x0a, 0xaa, + 0xec, 0x1a, 0xc7, 0x42, 0xe8, 0x01, 0x00, 0x00, + 0x04, 0x0b, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0xb7, 0xa4, 0xec, 0x08, 0x04, 0x0c, 0x02, 0x00, + 0x00, 0x95, 0x00, 0xc7, 0x28, 0x07, 0x02, 0x30, + 0x0e, 0x43, 0x02, 0x03, 0xb2, 0x07, 0x02, 0x01, + 0x02, 0x05, 0x01, 0x00, 0x4a, 0x00, 0x00, 0x6a, + 0x01, 0xd4, 0xbf, 0x10, 0xaa, 0xec, 0x29, 0xd3, + 0xb7, 0xa4, 0xec, 0x0c, 0xd3, 0x8d, 0xd7, 0x04, + 0x05, 0x02, 0x00, 0x00, 0xcb, 0xee, 0x03, 0xc3, + 0xcb, 0xc7, 0x04, 0x06, 0x02, 0x00, 0x00, 0xd3, + 0x42, 0x38, 0x00, 0x00, 0x00, 0xbf, 0x10, 0x24, + 0x01, 0x00, 0x9e, 0x9e, 0xcb, 0xee, 0x0b, 0xd3, + 0x42, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcb, 0xdf, 0x04, 0xe4, 0x00, 0x00, 0x00, 0xac, + 0xec, 0x08, 0x04, 0x0d, 0x02, 0x00, 0x00, 0x95, + 0x00, 0xc7, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xb4, + 0x07, 0x01, 0x02, 0x01, 0x02, 0x09, 0x01, 0x0b, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x01, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x6b, 0x01, + 0x00, 0x69, 0x01, 0x00, 0x6d, 0x01, 0x00, 0x6c, + 0x01, 0x00, 0x01, 0x01, 0xc2, 0x00, 0xcc, 0x26, + 0x00, 0x00, 0xcb, 0xc8, 0xd3, 0xf1, 0x29, 0x0e, + 0x43, 0x02, 0x03, 0x9c, 0x08, 0x01, 0x06, 0x01, + 0x05, 0x0b, 0x00, 0x95, 0x06, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x05, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x08, 0x00, 0xd3, + 0x98, 0xc6, 0x04, 0x04, 0x4a, 0x00, 0x00, 0x00, + 0xac, 0x6a, 0xdd, 0x01, 0x00, 0x00, 0xd3, 0xf5, + 0xec, 0x0f, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, 0x29, + 0xe0, 0x42, 0xe8, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0xb7, 0xa7, 0xec, 0x13, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x0f, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x29, + 0xe1, 0xec, 0x62, 0xd3, 0x38, 0xe9, 0x00, 0x00, + 0x00, 0xa8, 0x11, 0xed, 0x40, 0x0e, 0xd3, 0x38, + 0x10, 0x02, 0x00, 0x00, 0xa8, 0x11, 0xed, 0x35, + 0x0e, 0xd3, 0x38, 0x11, 0x02, 0x00, 0x00, 0xa8, + 0x11, 0xed, 0x2a, 0x0e, 0xd3, 0x38, 0x12, 0x02, + 0x00, 0x00, 0xa8, 0x11, 0xed, 0x1f, 0x0e, 0xd3, + 0x38, 0x13, 0x02, 0x00, 0x00, 0xa8, 0x11, 0xed, + 0x14, 0x0e, 0xd3, 0x38, 0x14, 0x02, 0x00, 0x00, + 0xa8, 0x11, 0xed, 0x09, 0x0e, 0xd3, 0x38, 0x15, + 0x02, 0x00, 0x00, 0xa8, 0xec, 0x17, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xd3, 0x42, + 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0xe0, 0x42, 0x87, 0x01, + 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, 0xe2, + 0x42, 0x16, 0x02, 0x00, 0x00, 0xd3, 0x24, 0x01, + 0x00, 0x6a, 0x86, 0x00, 0x00, 0x00, 0xd3, 0xeb, + 0xcb, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x17, 0x02, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xb7, 0xcc, 0xc8, 0xc7, 0xa4, 0xec, + 0x54, 0xc8, 0xb7, 0xad, 0xec, 0x12, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x18, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xc8, + 0xd3, 0xa9, 0xec, 0x0b, 0x5e, 0x04, 0x00, 0xd3, + 0xc8, 0x47, 0xf1, 0x0e, 0xee, 0x12, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x19, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xc8, + 0xbf, 0x14, 0xa6, 0xec, 0x14, 0x66, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x1a, 0x02, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xee, 0x05, + 0x94, 0x01, 0xee, 0xa9, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x1b, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xef, 0x9d, 0x00, + 0x5e, 0x05, 0x00, 0x42, 0x1c, 0x02, 0x00, 0x00, + 0xd3, 0x24, 0x01, 0x00, 0x04, 0xa5, 0x00, 0x00, + 0x00, 0xac, 0xec, 0x18, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xd3, 0x42, 0x38, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xee, 0x71, 0x5e, 0x05, 0x00, 0x42, 0x1d, + 0x02, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xd1, + 0xeb, 0xcb, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x1e, 0x02, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xb7, 0xcc, 0xc8, 0xc7, 0xa4, + 0xec, 0x39, 0xc8, 0xb7, 0xad, 0xec, 0x12, 0x66, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x18, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0xc9, 0xc8, 0x47, 0xce, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xca, 0x04, 0x1f, 0x02, + 0x00, 0x00, 0x24, 0x02, 0x00, 0x0e, 0x5e, 0x04, + 0x00, 0xd3, 0xca, 0x47, 0xf1, 0x0e, 0x94, 0x01, + 0xee, 0xc4, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x20, 0x02, 0x00, 0x00, 0x24, + 0x01, 0x00, 0x0e, 0xe0, 0x42, 0x21, 0x02, 0x00, + 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc4, + 0x04, 0x04, 0x49, 0x00, 0x00, 0x00, 0xac, 0xec, + 0x36, 0xd3, 0x42, 0x22, 0x02, 0x00, 0x00, 0x24, + 0x00, 0x00, 0xc6, 0x05, 0xeb, 0xbf, 0x4f, 0xa6, + 0xec, 0x16, 0xc4, 0x05, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xb7, 0xbf, 0x4b, 0x24, 0x02, 0x00, 0x04, + 0x23, 0x02, 0x00, 0x00, 0x9e, 0xc5, 0x05, 0x66, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xc4, + 0x05, 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc4, 0x04, + 0x04, 0x47, 0x00, 0x00, 0x00, 0xac, 0xec, 0x1e, + 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x5e, 0x06, 0x00, 0xd3, 0x5e, 0x07, 0x00, 0xec, + 0x05, 0xbf, 0x10, 0xee, 0x03, 0xbf, 0x0a, 0xf2, + 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc4, 0x04, 0x04, + 0x8d, 0x00, 0x00, 0x00, 0xac, 0xec, 0x1e, 0x66, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, + 0x08, 0x00, 0xd3, 0x5e, 0x07, 0x00, 0xec, 0x05, + 0xbf, 0x10, 0xee, 0x03, 0xbf, 0x0a, 0xf2, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0xc4, 0x04, 0x04, 0x8e, + 0x00, 0x00, 0x00, 0xac, 0xec, 0x1e, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x5e, 0x09, + 0x00, 0xd3, 0x5e, 0x07, 0x00, 0xec, 0x05, 0xbf, + 0x10, 0xee, 0x03, 0xbf, 0x0a, 0xf2, 0x24, 0x01, + 0x00, 0x0e, 0x29, 0xc4, 0x04, 0x04, 0x8f, 0x00, + 0x00, 0x00, 0xac, 0xec, 0x1d, 0x66, 0x00, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0xd3, 0x42, 0x38, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x04, 0x24, + 0x02, 0x00, 0x00, 0x9e, 0x24, 0x01, 0x00, 0x0e, + 0x29, 0xc4, 0x04, 0x04, 0x4b, 0x00, 0x00, 0x00, + 0xac, 0xec, 0x13, 0x66, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x5e, 0x0a, 0x00, 0xd3, 0xf1, + 0x24, 0x01, 0x00, 0x0e, 0x29, 0xc4, 0x04, 0x04, + 0x1b, 0x00, 0x00, 0x00, 0xac, 0xec, 0x20, 0x66, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x25, 0x02, 0x00, 0x00, 0xd3, 0x41, 0x37, 0x00, + 0x00, 0x00, 0x9e, 0x04, 0x64, 0x01, 0x00, 0x00, + 0x9e, 0x24, 0x01, 0x00, 0x0e, 0x29, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0xd3, 0x24, + 0x01, 0x00, 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xb6, 0x07, 0x01, 0x01, 0x01, 0x04, 0x01, 0x00, + 0x2c, 0x00, 0x00, 0x2f, 0x01, 0xd3, 0xb7, 0x47, + 0x04, 0x26, 0x02, 0x00, 0x00, 0xad, 0xec, 0x03, + 0xc3, 0x28, 0xb8, 0xcb, 0xc7, 0xd3, 0xeb, 0xa4, + 0xec, 0x0d, 0xdf, 0xd3, 0xc7, 0x47, 0xf1, 0x97, + 0xed, 0x05, 0x94, 0x00, 0xee, 0xef, 0xd3, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xb8, 0xc7, 0x25, 0x02, + 0x00, 0x0e, 0x43, 0x02, 0x03, 0xb8, 0x07, 0x02, + 0x04, 0x02, 0x07, 0x0c, 0x00, 0xb2, 0x07, 0x00, + 0x00, 0x71, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x69, + 0x01, 0x00, 0x17, 0x01, 0x00, 0x09, 0x01, 0x00, + 0x0e, 0x01, 0x00, 0x04, 0x01, 0x00, 0x10, 0x01, + 0x00, 0x0f, 0x01, 0x00, 0x06, 0x01, 0x00, 0x6a, + 0x01, 0x00, 0x08, 0x01, 0xd3, 0x04, 0x27, 0x02, + 0x00, 0x00, 0xac, 0x11, 0xed, 0x14, 0x0e, 0xd3, + 0x04, 0x28, 0x02, 0x00, 0x00, 0xac, 0x11, 0xed, + 0x09, 0x0e, 0xd3, 0x04, 0xdd, 0x01, 0x00, 0x00, + 0xaa, 0xec, 0x07, 0xdf, 0xf0, 0x0e, 0xef, 0x8d, + 0x03, 0xd3, 0x04, 0x29, 0x02, 0x00, 0x00, 0xac, + 0xec, 0x4b, 0xd4, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xd3, 0xeb, 0xb8, 0x9e, 0x24, 0x01, 0x00, 0x42, + 0x2a, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0xd2, + 0x42, 0x2b, 0x02, 0x00, 0x00, 0x04, 0xe9, 0x01, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xca, 0x42, 0x2b, + 0x02, 0x00, 0x00, 0x04, 0xee, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0xa5, 0xec, 0x08, 0x04, 0x2c, + 0x02, 0x00, 0x00, 0x95, 0x03, 0x66, 0x01, 0x00, + 0x42, 0x2d, 0x02, 0x00, 0x00, 0xca, 0x24, 0x01, + 0x00, 0x0e, 0x09, 0x28, 0xd3, 0x04, 0x2e, 0x02, + 0x00, 0x00, 0xac, 0xec, 0x06, 0x0a, 0xe5, 0xef, + 0x2c, 0x03, 0xd3, 0x04, 0x2f, 0x02, 0x00, 0x00, + 0xac, 0xec, 0x06, 0x09, 0xe5, 0xef, 0x1e, 0x03, + 0xd3, 0x04, 0x30, 0x02, 0x00, 0x00, 0xac, 0xec, + 0x07, 0xe2, 0x97, 0xe6, 0xef, 0x0f, 0x03, 0x5e, + 0x04, 0x00, 0x6a, 0x96, 0x01, 0x00, 0x00, 0xd3, + 0x04, 0x0a, 0x02, 0x00, 0x00, 0xac, 0x6a, 0x8a, + 0x01, 0x00, 0x00, 0xd4, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xd3, 0xeb, 0xb8, 0x9e, 0x24, 0x01, 0x00, + 0x42, 0x2a, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x42, 0x5e, 0x00, 0x00, 0x00, 0x04, 0xfd, 0x01, + 0x00, 0x00, 0x24, 0x01, 0x00, 0xcf, 0xeb, 0xb8, + 0xac, 0xec, 0x49, 0xc7, 0xb7, 0x47, 0xc3, 0xac, + 0xec, 0x42, 0x66, 0x01, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x31, 0x02, 0x00, 0x00, 0x5e, + 0x05, 0x00, 0x9e, 0x04, 0x32, 0x02, 0x00, 0x00, + 0x9e, 0x5e, 0x06, 0x00, 0x42, 0xfa, 0x01, 0x00, + 0x00, 0x5e, 0x05, 0x00, 0x5e, 0x07, 0x00, 0x9c, + 0x24, 0x01, 0x00, 0x9e, 0x04, 0x33, 0x02, 0x00, + 0x00, 0x9e, 0x5e, 0x08, 0x00, 0x9e, 0x04, 0x34, + 0x02, 0x00, 0x00, 0x9e, 0x24, 0x01, 0x00, 0x0e, + 0xef, 0x16, 0x01, 0xc7, 0xb7, 0x47, 0x04, 0x35, + 0x02, 0x00, 0x00, 0xac, 0xec, 0x0d, 0xbf, 0x0b, + 0x5f, 0x05, 0x00, 0xbc, 0x5f, 0x08, 0x00, 0xef, + 0xff, 0x00, 0xc7, 0xb7, 0x47, 0x04, 0x36, 0x02, + 0x00, 0x00, 0xac, 0xec, 0x0e, 0xbf, 0x18, 0x5f, + 0x05, 0x00, 0xbf, 0x08, 0x5f, 0x08, 0x00, 0xef, + 0xe7, 0x00, 0xc7, 0xb7, 0x47, 0x04, 0x37, 0x02, + 0x00, 0x00, 0xac, 0xec, 0x0e, 0xbf, 0x35, 0x5f, + 0x05, 0x00, 0xbf, 0x0b, 0x5f, 0x08, 0x00, 0xef, + 0xcf, 0x00, 0xc7, 0xb7, 0x47, 0x04, 0x38, 0x02, + 0x00, 0x00, 0xac, 0xec, 0x0e, 0xbf, 0x71, 0x5f, + 0x05, 0x00, 0xbf, 0x0f, 0x5f, 0x08, 0x00, 0xef, + 0xb7, 0x00, 0x38, 0x39, 0x02, 0x00, 0x00, 0xc7, + 0xb7, 0x47, 0xf1, 0xcc, 0xc7, 0xeb, 0xb9, 0xa7, + 0xec, 0x0d, 0x38, 0x39, 0x02, 0x00, 0x00, 0xc7, + 0xb8, 0x47, 0xf1, 0xcd, 0xee, 0x0c, 0x38, 0xb6, + 0x00, 0x00, 0x00, 0x41, 0x3a, 0x02, 0x00, 0x00, + 0xcd, 0x38, 0x9a, 0x00, 0x00, 0x00, 0x42, 0xf0, + 0x01, 0x00, 0x00, 0xc8, 0x24, 0x01, 0x00, 0x11, + 0xed, 0x1e, 0x0e, 0xc8, 0x38, 0xb6, 0x00, 0x00, + 0x00, 0x41, 0x3b, 0x02, 0x00, 0x00, 0xa4, 0x11, + 0xed, 0x0e, 0x0e, 0xc8, 0x38, 0xb6, 0x00, 0x00, + 0x00, 0x41, 0x3c, 0x02, 0x00, 0x00, 0xa6, 0xec, + 0x14, 0x66, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x3d, 0x02, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0x09, 0x28, 0x38, 0x9a, 0x00, 0x00, + 0x00, 0x42, 0xf0, 0x01, 0x00, 0x00, 0xc9, 0x24, + 0x01, 0x00, 0x11, 0xed, 0x1e, 0x0e, 0xc9, 0x38, + 0xb6, 0x00, 0x00, 0x00, 0x41, 0x3e, 0x02, 0x00, + 0x00, 0xa4, 0x11, 0xed, 0x0e, 0x0e, 0xc9, 0x38, + 0xb6, 0x00, 0x00, 0x00, 0x41, 0x3a, 0x02, 0x00, + 0x00, 0xa6, 0xec, 0x14, 0x66, 0x01, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x3f, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x09, 0x28, 0xc8, + 0x5f, 0x05, 0x00, 0xc9, 0x5f, 0x08, 0x00, 0x09, + 0x28, 0x5e, 0x04, 0x00, 0xec, 0x78, 0xd3, 0x04, + 0x40, 0x02, 0x00, 0x00, 0xac, 0xec, 0x6f, 0xd4, + 0x42, 0x69, 0x01, 0x00, 0x00, 0xd3, 0xeb, 0xb8, + 0x9e, 0x24, 0x01, 0x00, 0x42, 0x2a, 0x02, 0x00, + 0x00, 0x24, 0x00, 0x00, 0xcb, 0x5e, 0x06, 0x00, + 0x42, 0xfb, 0x01, 0x00, 0x00, 0x5e, 0x09, 0x00, + 0xc7, 0xf1, 0x5e, 0x07, 0x00, 0x9b, 0x24, 0x01, + 0x00, 0xd0, 0x38, 0xb6, 0x00, 0x00, 0x00, 0x41, + 0x3b, 0x02, 0x00, 0x00, 0xa4, 0x11, 0xed, 0x0e, + 0x0e, 0xc8, 0x38, 0xb6, 0x00, 0x00, 0x00, 0x41, + 0x3c, 0x02, 0x00, 0x00, 0xa6, 0xec, 0x14, 0x66, + 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x3d, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0x09, 0x28, 0xc8, 0x5f, 0x05, 0x00, 0x38, 0xb6, + 0x00, 0x00, 0x00, 0x41, 0x3a, 0x02, 0x00, 0x00, + 0x5f, 0x08, 0x00, 0x09, 0x28, 0x5e, 0x04, 0x00, + 0xec, 0x6e, 0xd3, 0x04, 0x41, 0x02, 0x00, 0x00, + 0xac, 0xec, 0x65, 0xd4, 0x42, 0x69, 0x01, 0x00, + 0x00, 0xd3, 0xeb, 0xb8, 0x9e, 0x24, 0x01, 0x00, + 0x42, 0x2a, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, + 0xcf, 0xc3, 0xac, 0xec, 0x1e, 0x66, 0x01, 0x00, + 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x42, 0x02, + 0x00, 0x00, 0x5e, 0x0a, 0x00, 0x9e, 0x04, 0x21, + 0x01, 0x00, 0x00, 0x9e, 0x24, 0x01, 0x00, 0x0e, + 0xee, 0x2c, 0xc7, 0x04, 0xe4, 0x00, 0x00, 0x00, + 0xac, 0x11, 0xed, 0x09, 0x0e, 0xc7, 0x04, 0x07, + 0x02, 0x00, 0x00, 0xac, 0xec, 0x07, 0xc7, 0x5f, + 0x0a, 0x00, 0xee, 0x12, 0x66, 0x01, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x43, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x09, 0x28, 0xd3, + 0x04, 0x44, 0x02, 0x00, 0x00, 0xac, 0xec, 0x14, + 0x66, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x04, 0x45, 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, + 0x0e, 0xee, 0x6a, 0xd3, 0x04, 0x46, 0x02, 0x00, + 0x00, 0xac, 0xec, 0x10, 0x66, 0x01, 0x00, 0x42, + 0xa3, 0x01, 0x00, 0x00, 0xb7, 0x24, 0x01, 0x00, + 0x0e, 0xee, 0x52, 0x5e, 0x0b, 0x00, 0xec, 0x17, + 0xd3, 0x04, 0x59, 0x01, 0x00, 0x00, 0xac, 0xec, + 0x0e, 0x36, 0x47, 0x02, 0x00, 0x00, 0x0a, 0x3b, + 0x47, 0x02, 0x00, 0x00, 0xee, 0x37, 0x5e, 0x0b, + 0x00, 0xec, 0x17, 0xd3, 0x04, 0x0d, 0x02, 0x00, + 0x00, 0xac, 0xec, 0x0e, 0x36, 0x47, 0x02, 0x00, + 0x00, 0x09, 0x3b, 0x47, 0x02, 0x00, 0x00, 0xee, + 0x1c, 0x66, 0x01, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x04, 0x48, 0x02, 0x00, 0x00, 0xd3, 0x9e, + 0x04, 0x21, 0x01, 0x00, 0x00, 0x9e, 0x24, 0x01, + 0x00, 0x0e, 0x09, 0x28, 0x0a, 0x28, 0x0e, 0x43, + 0x02, 0x03, 0x00, 0x01, 0x00, 0x01, 0x03, 0x01, + 0x00, 0x46, 0x00, 0x00, 0x69, 0x01, 0xd3, 0x11, + 0x04, 0x49, 0x02, 0x00, 0x00, 0xac, 0xec, 0x05, + 0x09, 0xe3, 0xee, 0x38, 0x11, 0x04, 0x4a, 0x02, + 0x00, 0x00, 0xac, 0xec, 0x05, 0x0a, 0xe3, 0xee, + 0x2b, 0x11, 0x04, 0x4b, 0x02, 0x00, 0x00, 0xac, + 0xec, 0x0e, 0x36, 0x47, 0x02, 0x00, 0x00, 0x09, + 0x3b, 0x47, 0x02, 0x00, 0x00, 0xee, 0x15, 0x11, + 0x04, 0x4c, 0x02, 0x00, 0x00, 0xac, 0xec, 0x0c, + 0x36, 0x47, 0x02, 0x00, 0x00, 0x0a, 0x3b, 0x47, + 0x02, 0x00, 0x00, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xba, 0x07, 0x00, 0x01, 0x00, 0x05, 0x07, 0x01, + 0xd5, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x69, + 0x01, 0x00, 0x17, 0x01, 0x00, 0x08, 0x01, 0x00, + 0x09, 0x01, 0x00, 0x6a, 0x01, 0x00, 0x07, 0x01, + 0xc2, 0x00, 0xcb, 0x66, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x4d, 0x02, 0x00, 0x00, + 0x04, 0x4e, 0x02, 0x00, 0x00, 0x9e, 0xc7, 0xe0, + 0xf1, 0x9e, 0x04, 0x4f, 0x02, 0x00, 0x00, 0x9e, + 0x04, 0x50, 0x02, 0x00, 0x00, 0x9e, 0xc7, 0xe0, + 0x97, 0xf1, 0x9e, 0x04, 0x51, 0x02, 0x00, 0x00, + 0x9e, 0x04, 0x52, 0x02, 0x00, 0x00, 0x9e, 0xc7, + 0xe1, 0xf1, 0x9e, 0x04, 0x53, 0x02, 0x00, 0x00, + 0x9e, 0x04, 0x54, 0x02, 0x00, 0x00, 0x9e, 0x24, + 0x01, 0x00, 0x0e, 0xe2, 0xec, 0x35, 0x66, 0x00, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x55, + 0x02, 0x00, 0x00, 0xc7, 0x38, 0x47, 0x02, 0x00, + 0x00, 0xf1, 0x9e, 0x04, 0x56, 0x02, 0x00, 0x00, + 0x9e, 0x04, 0x57, 0x02, 0x00, 0x00, 0x9e, 0xc7, + 0x38, 0x47, 0x02, 0x00, 0x00, 0x97, 0xf1, 0x9e, + 0x04, 0x58, 0x02, 0x00, 0x00, 0x9e, 0x24, 0x01, + 0x00, 0x0e, 0x5e, 0x04, 0x00, 0xec, 0x37, 0x66, + 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x59, 0x02, 0x00, 0x00, 0x04, 0x5a, 0x02, 0x00, + 0x00, 0x9e, 0x24, 0x01, 0x00, 0x0e, 0xe2, 0x97, + 0xec, 0x1c, 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, + 0x00, 0x00, 0x04, 0x5b, 0x02, 0x00, 0x00, 0x5e, + 0x05, 0x00, 0x9e, 0x04, 0x5c, 0x02, 0x00, 0x00, + 0x9e, 0x24, 0x01, 0x00, 0x0e, 0x5e, 0x06, 0x00, + 0x97, 0xec, 0x12, 0x66, 0x00, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x5d, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x29, 0x0e, 0x43, 0x02, + 0x03, 0xbc, 0x09, 0x01, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x0f, 0x00, 0xd3, 0xec, 0x07, 0x04, 0x7e, + 0x00, 0x00, 0x00, 0x28, 0x04, 0xfd, 0x01, 0x00, + 0x00, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xbc, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x0b, 0x00, 0x6e, 0x00, + 0xdc, 0x06, 0x07, 0x01, 0xde, 0x06, 0x08, 0x01, + 0xc8, 0x03, 0x00, 0x0c, 0xe0, 0x06, 0x09, 0x01, + 0xea, 0x06, 0x10, 0x01, 0xbe, 0x02, 0x04, 0x01, + 0xe6, 0x06, 0x0e, 0x01, 0xe8, 0x06, 0x0f, 0x01, + 0xac, 0x07, 0x6a, 0x01, 0xda, 0x06, 0x00, 0x03, + 0xbe, 0x07, 0x73, 0x01, 0xdf, 0x97, 0xec, 0x28, + 0xe0, 0xec, 0x14, 0x66, 0x02, 0x00, 0x42, 0x68, + 0x01, 0x00, 0x00, 0x04, 0x5f, 0x02, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0xee, 0x12, 0x66, 0x02, + 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, 0x60, + 0x02, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xe2, + 0xec, 0x3c, 0x5e, 0x05, 0x00, 0x42, 0x61, 0x02, + 0x00, 0x00, 0xbf, 0x0a, 0x24, 0x01, 0x00, 0x5e, + 0x05, 0x00, 0x42, 0x61, 0x02, 0x00, 0x00, 0xb9, + 0x24, 0x01, 0x00, 0x9c, 0x5f, 0x04, 0x00, 0xbf, + 0x71, 0x5f, 0x06, 0x00, 0xbf, 0x0f, 0x5f, 0x07, + 0x00, 0xe0, 0xec, 0x12, 0x04, 0x07, 0x02, 0x00, + 0x00, 0x5f, 0x08, 0x00, 0x5e, 0x09, 0x00, 0xdf, + 0x43, 0x47, 0x02, 0x00, 0x00, 0x5e, 0x0a, 0x00, + 0xf0, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xbe, 0x07, + 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x0c, 0x00, + 0xa4, 0x07, 0x66, 0x01, 0x9c, 0x07, 0x61, 0x01, + 0x82, 0x07, 0x1c, 0x01, 0xc0, 0x07, 0x74, 0x01, + 0xdf, 0xe0, 0x04, 0x62, 0x02, 0x00, 0x00, 0xe1, + 0xf2, 0xe2, 0xf2, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xc0, 0x07, 0x01, 0x00, 0x01, 0x02, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x75, 0x01, 0x00, 0x73, 0x01, + 0xdf, 0xd3, 0xf1, 0x97, 0xec, 0x04, 0xe0, 0xf0, + 0x0e, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xc2, 0x07, + 0x01, 0x02, 0x01, 0x07, 0x0b, 0x00, 0x98, 0x01, + 0x00, 0x00, 0x71, 0x01, 0x00, 0x6f, 0x01, 0x00, + 0x70, 0x01, 0x00, 0x1b, 0x01, 0x00, 0x7a, 0x01, + 0x00, 0x11, 0x01, 0x00, 0x1c, 0x01, 0x00, 0x09, + 0x01, 0x00, 0x76, 0x01, 0x00, 0x0e, 0x01, 0x00, + 0x0f, 0x01, 0xd3, 0xf5, 0xec, 0x05, 0xc3, 0xd7, + 0x09, 0x28, 0xd3, 0x04, 0x28, 0x02, 0x00, 0x00, + 0xac, 0xec, 0x06, 0xdf, 0xf0, 0x0e, 0x09, 0x28, + 0xe0, 0xd3, 0xf1, 0xd0, 0xeb, 0xb7, 0xa6, 0xec, + 0x18, 0xe1, 0xc8, 0xd3, 0xf2, 0x97, 0xec, 0x03, + 0x09, 0x28, 0xd3, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xc8, 0xeb, 0xb8, 0x9e, 0x24, 0x01, 0x00, 0xd7, + 0xd3, 0xc3, 0xac, 0xec, 0x03, 0x09, 0x28, 0xe2, + 0xec, 0x0b, 0xe2, 0x04, 0x21, 0x01, 0x00, 0x00, + 0x9e, 0xd3, 0x9e, 0xd7, 0x5e, 0x04, 0x00, 0xd3, + 0xf1, 0xcf, 0xb7, 0x47, 0x5f, 0x05, 0x00, 0xc7, + 0xb8, 0x47, 0x5f, 0x06, 0x00, 0x5e, 0x05, 0x00, + 0xec, 0x05, 0xd3, 0xe6, 0x09, 0x28, 0xc3, 0xe6, + 0x5e, 0x07, 0x00, 0xec, 0x25, 0x38, 0xb6, 0x00, + 0x00, 0x00, 0x42, 0x63, 0x02, 0x00, 0x00, 0x5e, + 0x08, 0x00, 0x42, 0x64, 0x02, 0x00, 0x00, 0x07, + 0xd3, 0x09, 0x24, 0x03, 0x00, 0x5e, 0x09, 0x00, + 0x5e, 0x0a, 0x00, 0x24, 0x03, 0x00, 0x0e, 0xee, + 0x08, 0x5e, 0x08, 0x00, 0xd3, 0x0a, 0xf2, 0x0e, + 0x0a, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xc4, 0x07, + 0x02, 0x02, 0x02, 0x06, 0x06, 0x00, 0x68, 0x00, + 0x00, 0x6a, 0x01, 0x00, 0x19, 0x01, 0x00, 0x01, + 0x0c, 0x00, 0x00, 0x0c, 0x00, 0x77, 0x01, 0x00, + 0x78, 0x01, 0x6d, 0x58, 0x00, 0x00, 0x00, 0xdf, + 0x04, 0x07, 0x02, 0x00, 0x00, 0xac, 0xec, 0x09, + 0x04, 0x65, 0x02, 0x00, 0x00, 0xd3, 0x9e, 0xd7, + 0x66, 0x02, 0x00, 0x42, 0x66, 0x02, 0x00, 0x00, + 0x24, 0x00, 0x00, 0xe4, 0x66, 0x03, 0x00, 0x42, + 0x67, 0x02, 0x00, 0x00, 0xd3, 0x0b, 0x0a, 0x4c, + 0x68, 0x02, 0x00, 0x00, 0xd4, 0x4c, 0x86, 0x00, + 0x00, 0x00, 0x24, 0x02, 0x00, 0xcb, 0xd4, 0xec, + 0x13, 0xc7, 0x42, 0x80, 0x00, 0x00, 0x00, 0x5e, + 0x04, 0x00, 0x5e, 0x05, 0x00, 0x24, 0x02, 0x00, + 0x0e, 0xee, 0x07, 0x5e, 0x04, 0x00, 0xc7, 0xf1, + 0x0e, 0x0e, 0x29, 0xcc, 0x6d, 0x0c, 0x00, 0x00, + 0x00, 0x5e, 0x05, 0x00, 0xc8, 0xf1, 0x0e, 0x0e, + 0x29, 0x2f, 0x0e, 0x43, 0x02, 0x03, 0xc6, 0x07, + 0x01, 0x00, 0x01, 0x04, 0x09, 0x00, 0x5f, 0x00, + 0x00, 0x1a, 0x01, 0x00, 0x01, 0x0c, 0x00, 0x19, + 0x01, 0x00, 0x00, 0x0c, 0x00, 0x0a, 0x01, 0x00, + 0x0b, 0x01, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x03, + 0x00, 0x79, 0x01, 0x66, 0x01, 0x00, 0x42, 0x66, + 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, 0xe1, 0x9f, + 0xe3, 0x66, 0x03, 0x00, 0x42, 0x68, 0x01, 0x00, + 0x00, 0x5e, 0x04, 0x00, 0x5e, 0x05, 0x00, 0x41, + 0x13, 0x01, 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, + 0x0e, 0x5e, 0x06, 0x00, 0xd3, 0xf1, 0x0e, 0x66, + 0x03, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, 0x04, + 0x21, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, + 0x66, 0x03, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0x5e, 0x04, 0x00, 0x41, 0xeb, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x0e, 0x5e, 0x07, 0x00, 0xd3, + 0x43, 0x5d, 0x01, 0x00, 0x00, 0x5e, 0x08, 0x00, + 0xf0, 0x29, 0x0e, 0x43, 0x02, 0x03, 0xc8, 0x07, + 0x01, 0x00, 0x01, 0x04, 0x04, 0x00, 0x7d, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x0a, 0x01, 0x00, 0x0b, + 0x01, 0x00, 0x79, 0x01, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xe0, 0xe1, 0x41, 0x14, + 0x01, 0x00, 0x00, 0x47, 0x24, 0x01, 0x00, 0x0e, + 0xd3, 0x38, 0x99, 0x00, 0x00, 0x00, 0xa8, 0xec, + 0x2c, 0x38, 0x69, 0x02, 0x00, 0x00, 0x42, 0x61, + 0x02, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0x0e, + 0xd3, 0x41, 0x36, 0x00, 0x00, 0x00, 0xec, 0x35, + 0x66, 0x00, 0x00, 0x42, 0x68, 0x01, 0x00, 0x00, + 0xd3, 0x41, 0x36, 0x00, 0x00, 0x00, 0x24, 0x01, + 0x00, 0x0e, 0xee, 0x21, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0x04, 0x6a, 0x02, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38, 0x69, 0x02, + 0x00, 0x00, 0x42, 0x61, 0x02, 0x00, 0x00, 0xd3, + 0x24, 0x01, 0x00, 0x0e, 0x66, 0x00, 0x00, 0x42, + 0x68, 0x01, 0x00, 0x00, 0xe0, 0x41, 0xeb, 0x00, + 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0xe2, 0xf0, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xca, 0x07, 0x00, + 0x00, 0x00, 0x02, 0x03, 0x00, 0x11, 0x00, 0x82, + 0x07, 0x1c, 0x01, 0xc8, 0x03, 0x00, 0x0c, 0xbe, + 0x07, 0x73, 0x01, 0xb7, 0xe3, 0x66, 0x01, 0x00, + 0x42, 0x6b, 0x02, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x0e, 0xe1, 0xf0, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0xcc, 0x07, 0x01, 0x17, 0x01, 0x04, 0x03, 0x0a, + 0x8f, 0x04, 0x00, 0x00, 0x31, 0x01, 0x00, 0x34, + 0x01, 0x00, 0x30, 0x01, 0xc2, 0x00, 0xc5, 0x0a, + 0xc2, 0x01, 0xc5, 0x0b, 0xc2, 0x02, 0xc5, 0x0c, + 0xc2, 0x03, 0xc5, 0x0d, 0xc2, 0x04, 0xc5, 0x0e, + 0xc2, 0x05, 0xc5, 0x0f, 0xc2, 0x06, 0xc5, 0x10, + 0xc2, 0x07, 0xc5, 0x11, 0xc2, 0x08, 0xc5, 0x15, + 0xc2, 0x09, 0xc5, 0x16, 0xd3, 0xeb, 0xce, 0xc3, + 0xc5, 0x05, 0xb7, 0xc5, 0x06, 0xb8, 0xc5, 0x08, + 0x26, 0x00, 0x00, 0xc5, 0x09, 0x04, 0x6c, 0x02, + 0x00, 0x00, 0x04, 0x6d, 0x02, 0x00, 0x00, 0x9e, + 0x04, 0x6e, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x6f, + 0x02, 0x00, 0x00, 0x9e, 0x04, 0x70, 0x02, 0x00, + 0x00, 0x9e, 0x04, 0x71, 0x02, 0x00, 0x00, 0x9e, + 0x04, 0x72, 0x02, 0x00, 0x00, 0x9e, 0x04, 0x73, + 0x02, 0x00, 0x00, 0x9e, 0x04, 0x74, 0x02, 0x00, + 0x00, 0x9e, 0x04, 0x75, 0x02, 0x00, 0x00, 0x9e, + 0xc5, 0x12, 0x04, 0x76, 0x02, 0x00, 0x00, 0xc5, + 0x13, 0x04, 0x77, 0x02, 0x00, 0x00, 0xc5, 0x14, + 0xb7, 0xcb, 0xc7, 0xca, 0xa4, 0x6a, 0x75, 0x01, + 0x00, 0x00, 0x07, 0xc5, 0x04, 0xc7, 0xcd, 0xd3, + 0xc7, 0x92, 0xcb, 0x47, 0xd0, 0x11, 0x04, 0xfd, + 0x01, 0x00, 0x00, 0xac, 0xed, 0x1c, 0x11, 0x04, + 0x20, 0x01, 0x00, 0x00, 0xac, 0xed, 0x13, 0x11, + 0x04, 0x23, 0x01, 0x00, 0x00, 0xac, 0xed, 0x0a, + 0x11, 0x04, 0x21, 0x01, 0x00, 0x00, 0xac, 0xec, + 0x04, 0x0e, 0xee, 0xc7, 0x11, 0x04, 0x78, 0x02, + 0x00, 0x00, 0xac, 0xed, 0x0a, 0x11, 0x04, 0x05, + 0x02, 0x00, 0x00, 0xac, 0xec, 0x18, 0xc7, 0xca, + 0xa4, 0xec, 0x0d, 0xd3, 0xc7, 0x47, 0xc8, 0xaa, + 0xec, 0x06, 0x94, 0x00, 0x0e, 0xee, 0xa4, 0xb8, + 0xc5, 0x08, 0x0e, 0xee, 0x9e, 0x11, 0x04, 0xee, + 0x01, 0x00, 0x00, 0xac, 0xec, 0x44, 0xc7, 0xca, + 0xa4, 0xec, 0x13, 0xd3, 0xc7, 0x47, 0x04, 0x7e, + 0x00, 0x00, 0x00, 0xaa, 0xec, 0x08, 0xc4, 0x0d, + 0xf0, 0x0e, 0xef, 0xe7, 0x00, 0xc7, 0xca, 0xa4, + 0xec, 0x13, 0xd3, 0xc7, 0x47, 0x04, 0xee, 0x01, + 0x00, 0x00, 0xaa, 0xec, 0x08, 0xc4, 0x0e, 0xf0, + 0x0e, 0xef, 0xd0, 0x00, 0xc4, 0x08, 0xec, 0x0b, + 0xc4, 0x10, 0xf0, 0x0e, 0xb7, 0xc5, 0x08, 0xef, + 0xc2, 0x00, 0xb8, 0xc5, 0x08, 0x0e, 0xef, 0x53, + 0xff, 0x11, 0x04, 0xea, 0x01, 0x00, 0x00, 0xac, + 0xed, 0x13, 0x11, 0x04, 0xeb, 0x01, 0x00, 0x00, + 0xac, 0xed, 0x0a, 0x11, 0x04, 0x79, 0x02, 0x00, + 0x00, 0xac, 0xec, 0x0c, 0xc4, 0x0f, 0xc8, 0xf1, + 0x0e, 0xb7, 0xc5, 0x08, 0xef, 0x95, 0x00, 0x11, + 0x04, 0xf7, 0x01, 0x00, 0x00, 0xac, 0xed, 0x13, + 0x11, 0x04, 0x01, 0x02, 0x00, 0x00, 0xac, 0xed, + 0x0a, 0x11, 0x04, 0x7a, 0x02, 0x00, 0x00, 0xac, + 0xec, 0x0f, 0xb8, 0xc5, 0x08, 0x94, 0x06, 0xc4, + 0x0a, 0xc8, 0xf1, 0x0e, 0x0e, 0xef, 0x04, 0xff, + 0x11, 0x04, 0xf8, 0x01, 0x00, 0x00, 0xac, 0xed, + 0x13, 0x11, 0x04, 0xec, 0x01, 0x00, 0x00, 0xac, + 0xed, 0x0a, 0x11, 0x04, 0xed, 0x01, 0x00, 0x00, + 0xac, 0xec, 0x25, 0xb7, 0xc5, 0x08, 0xc4, 0x06, + 0xb7, 0xa6, 0xec, 0x13, 0xe0, 0xc4, 0x0b, 0xf0, + 0xc8, 0xf2, 0xec, 0x0b, 0x93, 0x06, 0xc4, 0x0c, + 0xf0, 0x0e, 0x0e, 0xef, 0xce, 0xfe, 0x04, 0x12, + 0x01, 0x00, 0x00, 0xc5, 0x04, 0xee, 0x2c, 0xe1, + 0xc8, 0xf1, 0xec, 0x0a, 0xc4, 0x11, 0xf0, 0x0e, + 0xb7, 0xc5, 0x08, 0xee, 0x1e, 0xdf, 0xc8, 0xf1, + 0x11, 0xed, 0x09, 0x0e, 0xc8, 0x04, 0x5e, 0x01, + 0x00, 0x00, 0xaa, 0xec, 0x07, 0xc4, 0x15, 0xf0, + 0x0e, 0xee, 0x08, 0xb8, 0xc5, 0x08, 0x0e, 0xef, + 0x9a, 0xfe, 0x0e, 0xc4, 0x04, 0x6a, 0x94, 0xfe, + 0xff, 0xff, 0xc4, 0x16, 0xc9, 0xc7, 0xf2, 0x0e, + 0xef, 0x89, 0xfe, 0xc4, 0x16, 0xca, 0xca, 0xf2, + 0x0e, 0xc4, 0x05, 0xc4, 0x06, 0xc4, 0x09, 0x26, + 0x03, 0x00, 0x28, 0x0e, 0x43, 0x02, 0x03, 0xf6, + 0x09, 0x01, 0x00, 0x01, 0x02, 0x01, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x01, 0xdf, 0xd3, 0x9e, 0xe3, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0xf8, 0x09, 0x01, + 0x00, 0x01, 0x04, 0x01, 0x00, 0x0d, 0x00, 0x00, + 0x05, 0x01, 0xdf, 0x42, 0x69, 0x01, 0x00, 0x00, + 0xdf, 0xeb, 0xb8, 0x9f, 0x25, 0x01, 0x00, 0x0e, + 0x43, 0x02, 0x03, 0xfa, 0x09, 0x01, 0x00, 0x01, + 0x05, 0x02, 0x00, 0x14, 0x00, 0x00, 0x0b, 0x01, + 0x00, 0x05, 0x01, 0xdf, 0xf0, 0xd7, 0xe0, 0x42, + 0x69, 0x01, 0x00, 0x00, 0xb7, 0xe0, 0xeb, 0xb8, + 0x9f, 0x24, 0x02, 0x00, 0xe4, 0xd3, 0x28, 0x0e, + 0x43, 0x02, 0x03, 0xfc, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x06, 0x00, 0x49, 0x00, 0xfe, 0x09, 0x04, + 0x01, 0xf6, 0x09, 0x0a, 0x01, 0x80, 0x0a, 0x00, + 0x01, 0x9a, 0x08, 0x03, 0x01, 0x82, 0x0a, 0x00, + 0x03, 0xfa, 0x09, 0x0c, 0x01, 0x04, 0x0d, 0x01, + 0x00, 0x00, 0xe3, 0xe0, 0x04, 0xee, 0x01, 0x00, + 0x00, 0xf1, 0x0e, 0xe1, 0x90, 0xe5, 0xe1, 0xe2, + 0xb8, 0x9f, 0xa4, 0xec, 0x31, 0x5e, 0x04, 0x00, + 0xe1, 0x47, 0x04, 0x7e, 0x00, 0x00, 0x00, 0xaa, + 0xec, 0x1f, 0x5e, 0x04, 0x00, 0xe1, 0xb8, 0x9e, + 0x47, 0x04, 0xee, 0x01, 0x00, 0x00, 0xaa, 0xec, + 0x10, 0xe1, 0xb9, 0x9e, 0xe5, 0x5e, 0x05, 0x00, + 0x04, 0xee, 0x01, 0x00, 0x00, 0xf1, 0x0e, 0x29, + 0xe1, 0x90, 0xe5, 0xee, 0xca, 0x29, 0x0e, 0x43, + 0x02, 0x03, 0x84, 0x0a, 0x00, 0x00, 0x00, 0x02, + 0x04, 0x00, 0x1f, 0x00, 0xfe, 0x09, 0x04, 0x01, + 0x80, 0x0a, 0x00, 0x01, 0x9a, 0x08, 0x03, 0x01, + 0x82, 0x0a, 0x00, 0x03, 0x04, 0x0d, 0x01, 0x00, + 0x00, 0xe3, 0xe0, 0x90, 0xe4, 0xe0, 0xe1, 0xa4, + 0xec, 0x11, 0xe2, 0xe0, 0x47, 0x04, 0x21, 0x01, + 0x00, 0x00, 0xaa, 0xed, 0x06, 0xe0, 0x90, 0xe4, + 0xee, 0xec, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x86, + 0x0a, 0x01, 0x00, 0x01, 0x03, 0x07, 0x00, 0x4c, + 0x00, 0x00, 0x04, 0x01, 0x00, 0x0a, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x03, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x04, 0x49, + 0x00, 0x00, 0x00, 0xe3, 0xe0, 0xd3, 0xf1, 0x0e, + 0xe1, 0xe2, 0xa4, 0xec, 0x3d, 0x5e, 0x05, 0x00, + 0xe1, 0x92, 0xe5, 0x47, 0x60, 0x04, 0x00, 0x04, + 0x21, 0x01, 0x00, 0x00, 0xaa, 0xec, 0x09, 0x04, + 0x12, 0x01, 0x00, 0x00, 0xe3, 0xee, 0xe2, 0x5e, + 0x04, 0x00, 0x04, 0x26, 0x02, 0x00, 0x00, 0xaa, + 0xec, 0x0b, 0xe1, 0xe2, 0xa7, 0xed, 0x13, 0xe1, + 0x90, 0xe5, 0xee, 0xcd, 0x5e, 0x04, 0x00, 0xd3, + 0xaa, 0xec, 0xc6, 0x5e, 0x06, 0x00, 0xf0, 0x0e, + 0x29, 0x29, 0x0e, 0x43, 0x02, 0x03, 0x88, 0x0a, + 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0xc4, 0x01, + 0x00, 0xfe, 0x09, 0x04, 0x01, 0xf6, 0x09, 0x0a, + 0x01, 0x80, 0x0a, 0x00, 0x01, 0x9a, 0x08, 0x03, + 0x01, 0xd8, 0x06, 0x01, 0x01, 0x82, 0x0a, 0x00, + 0x03, 0xf8, 0x09, 0x0b, 0x01, 0xfa, 0x09, 0x0c, + 0x01, 0xb8, 0x05, 0x00, 0x00, 0x04, 0x0e, 0x01, + 0x00, 0x00, 0xe3, 0xe0, 0x04, 0xee, 0x01, 0x00, + 0x00, 0xf1, 0x0e, 0xe1, 0xe2, 0xa4, 0x6a, 0xb1, + 0x00, 0x00, 0x00, 0x5e, 0x05, 0x00, 0xe1, 0x92, + 0xe5, 0x47, 0x60, 0x04, 0x00, 0x04, 0x21, 0x01, + 0x00, 0x00, 0xaa, 0xec, 0x09, 0x04, 0x12, 0x01, + 0x00, 0x00, 0xe3, 0xee, 0xdf, 0x5e, 0x04, 0x00, + 0x04, 0x26, 0x02, 0x00, 0x00, 0xaa, 0xec, 0x0b, + 0xe1, 0xe2, 0xa4, 0xec, 0xcf, 0xe1, 0x90, 0xe5, + 0xee, 0xca, 0x5e, 0x06, 0x00, 0xf0, 0x04, 0x01, + 0x02, 0x00, 0x00, 0xaa, 0xec, 0x13, 0x5e, 0x04, + 0x00, 0x04, 0xec, 0x01, 0x00, 0x00, 0xaa, 0xec, + 0xb3, 0x5e, 0x07, 0x00, 0xf0, 0x0e, 0xee, 0xac, + 0x5e, 0x04, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, + 0xaa, 0xec, 0x2e, 0xe0, 0x04, 0x01, 0x02, 0x00, + 0x00, 0xf1, 0x0e, 0x5e, 0x05, 0x00, 0xe1, 0x47, + 0x04, 0x01, 0x02, 0x00, 0x00, 0xaa, 0x11, 0xed, + 0x0d, 0x0e, 0x5e, 0x05, 0x00, 0xe1, 0x47, 0x04, + 0xec, 0x01, 0x00, 0x00, 0xaa, 0x6a, 0x7d, 0xff, + 0xff, 0xff, 0xe1, 0x90, 0xe5, 0xef, 0x75, 0xff, + 0x5e, 0x04, 0x00, 0x04, 0xee, 0x01, 0x00, 0x00, + 0xaa, 0x6a, 0x69, 0xff, 0xff, 0xff, 0x5e, 0x07, + 0x00, 0xf0, 0x0e, 0xe1, 0xe2, 0xa4, 0xec, 0x11, + 0x5e, 0x08, 0x00, 0x5e, 0x05, 0x00, 0xe1, 0x47, + 0xf1, 0xec, 0x06, 0xe1, 0x90, 0xe5, 0xee, 0xec, + 0x29, 0x0e, 0x43, 0x02, 0x03, 0x8a, 0x0a, 0x00, + 0x00, 0x00, 0x03, 0x05, 0x00, 0x41, 0x00, 0xfe, + 0x09, 0x04, 0x01, 0x80, 0x0a, 0x00, 0x01, 0x9a, + 0x08, 0x03, 0x01, 0xb8, 0x05, 0x00, 0x00, 0x82, + 0x0a, 0x00, 0x03, 0x04, 0x47, 0x00, 0x00, 0x00, + 0xe3, 0xe0, 0xe1, 0xa4, 0xec, 0x36, 0xe2, 0x5e, + 0x04, 0x00, 0xe0, 0x47, 0xf1, 0x11, 0xed, 0x25, + 0x0e, 0x5e, 0x04, 0x00, 0xe0, 0x47, 0x04, 0xe9, + 0x01, 0x00, 0x00, 0xaa, 0xec, 0x1e, 0xe0, 0xe1, + 0xb8, 0x9f, 0xaa, 0x11, 0xed, 0x0f, 0x0e, 0x5e, + 0x04, 0x00, 0xe0, 0xb8, 0x9e, 0x47, 0x04, 0xe9, + 0x01, 0x00, 0x00, 0xab, 0xec, 0x06, 0xe0, 0x90, + 0xe4, 0xee, 0xc7, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x8c, 0x0a, 0x00, 0x02, 0x00, 0x05, 0x0a, 0x00, + 0xb3, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x02, 0x01, 0x00, 0x12, 0x01, + 0x00, 0x04, 0x01, 0x00, 0x13, 0x01, 0x00, 0x14, + 0x01, 0xb8, 0xe3, 0xe0, 0xe1, 0xa4, 0xec, 0x0f, + 0xe2, 0x5e, 0x04, 0x00, 0xe0, 0x47, 0xf1, 0xec, + 0x06, 0xe0, 0x90, 0xe4, 0xee, 0xee, 0x04, 0x6c, + 0x02, 0x00, 0x00, 0x5e, 0x04, 0x00, 0x42, 0x69, + 0x01, 0x00, 0x00, 0x5e, 0x05, 0x00, 0xe0, 0x24, + 0x02, 0x00, 0x9e, 0x04, 0x6c, 0x02, 0x00, 0x00, + 0x9e, 0xcb, 0x5e, 0x06, 0x00, 0x42, 0xe8, 0x01, + 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0xb7, 0xa7, + 0xec, 0x1c, 0x04, 0x0f, 0x01, 0x00, 0x00, 0x5f, + 0x07, 0x00, 0x5e, 0x08, 0x00, 0x42, 0xe8, 0x01, + 0x00, 0x00, 0xc7, 0x24, 0x01, 0x00, 0xb7, 0xa7, + 0xec, 0x03, 0xb7, 0xe3, 0x29, 0xe0, 0xcc, 0xc8, + 0xe1, 0xa4, 0xec, 0x12, 0x5e, 0x04, 0x00, 0xc8, + 0x47, 0x04, 0xfd, 0x01, 0x00, 0x00, 0xaa, 0xec, + 0x05, 0x94, 0x01, 0xee, 0xeb, 0xc8, 0xe1, 0xa4, + 0xec, 0x17, 0x5e, 0x04, 0x00, 0xc8, 0x47, 0x04, + 0xf7, 0x01, 0x00, 0x00, 0xaa, 0xec, 0x0a, 0x04, + 0x1b, 0x00, 0x00, 0x00, 0x5f, 0x07, 0x00, 0x29, + 0x5e, 0x09, 0x00, 0x42, 0xe8, 0x01, 0x00, 0x00, + 0xc7, 0x24, 0x01, 0x00, 0xb7, 0xa7, 0xec, 0x0a, + 0x04, 0x10, 0x01, 0x00, 0x00, 0x5f, 0x07, 0x00, + 0x29, 0x04, 0x11, 0x01, 0x00, 0x00, 0x5f, 0x07, + 0x00, 0xb7, 0xe3, 0x29, 0x0e, 0x43, 0x02, 0x03, + 0x8e, 0x0a, 0x02, 0x00, 0x02, 0x03, 0x02, 0x00, + 0x2b, 0x00, 0x00, 0x09, 0x01, 0x00, 0x04, 0x01, + 0xdf, 0xeb, 0xd3, 0xa4, 0xec, 0x12, 0xdf, 0x42, + 0x87, 0x01, 0x00, 0x00, 0x04, 0x16, 0x00, 0x00, + 0x00, 0x24, 0x01, 0x00, 0x0e, 0xee, 0xea, 0xdf, + 0xeb, 0xd4, 0xa4, 0xec, 0x0e, 0xdf, 0x42, 0x87, + 0x01, 0x00, 0x00, 0xe0, 0x24, 0x01, 0x00, 0x0e, + 0xee, 0xee, 0x29, +}; + diff --git a/deps/quickjs/repl.js b/deps/quickjs/repl.js new file mode 100644 index 0000000..62714a9 --- /dev/null +++ b/deps/quickjs/repl.js @@ -0,0 +1,1590 @@ +/* + * QuickJS Read Eval Print Loop + * + * Copyright (c) 2017-2020 Fabrice Bellard + * Copyright (c) 2017-2020 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +"use strip"; + +import * as std from "std"; +import * as os from "os"; + +(function(g) { + /* add 'os' and 'std' bindings */ + g.os = os; + g.std = std; + + /* close global objects */ + var Object = g.Object; + var String = g.String; + var Array = g.Array; + var Date = g.Date; + var Math = g.Math; + var isFinite = g.isFinite; + var parseFloat = g.parseFloat; + + /* XXX: use preprocessor ? */ + var config_numcalc = (typeof os.open === "undefined"); + var has_jscalc = (typeof Fraction === "function"); + var has_bignum = (typeof BigFloat === "function"); + + var colors = { + none: "\x1b[0m", + black: "\x1b[30m", + red: "\x1b[31m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + magenta: "\x1b[35m", + cyan: "\x1b[36m", + white: "\x1b[37m", + gray: "\x1b[30;1m", + grey: "\x1b[30;1m", + bright_red: "\x1b[31;1m", + bright_green: "\x1b[32;1m", + bright_yellow: "\x1b[33;1m", + bright_blue: "\x1b[34;1m", + bright_magenta: "\x1b[35;1m", + bright_cyan: "\x1b[36;1m", + bright_white: "\x1b[37;1m", + }; + + var styles; + if (config_numcalc) { + styles = { + 'default': 'black', + 'comment': 'white', + 'string': 'green', + 'regex': 'cyan', + 'number': 'green', + 'keyword': 'blue', + 'function': 'gray', + 'type': 'bright_magenta', + 'identifier': 'yellow', + 'error': 'bright_red', + 'result': 'black', + 'error_msg': 'bright_red', + }; + } else { + styles = { + 'default': 'bright_green', + 'comment': 'white', + 'string': 'bright_cyan', + 'regex': 'cyan', + 'number': 'green', + 'keyword': 'bright_white', + 'function': 'bright_yellow', + 'type': 'bright_magenta', + 'identifier': 'bright_green', + 'error': 'red', + 'result': 'bright_white', + 'error_msg': 'bright_red', + }; + } + + var history = []; + var clip_board = ""; + var prec; + var expBits; + var log2_10; + + var pstate = ""; + var prompt = ""; + var plen = 0; + var ps1; + if (config_numcalc) + ps1 = "> "; + else + ps1 = "qjs > "; + var ps2 = " ... "; + var utf8 = true; + var show_time = false; + var show_colors = true; + var eval_start_time; + var eval_time = 0; + + var mexpr = ""; + var level = 0; + var cmd = ""; + var cursor_pos = 0; + var last_cmd = ""; + var last_cursor_pos = 0; + var history_index; + var this_fun, last_fun; + var quote_flag = false; + + var utf8_state = 0; + var utf8_val = 0; + + var term_fd; + var term_read_buf; + var term_width; + /* current X position of the cursor in the terminal */ + var term_cursor_x = 0; + + function termInit() { + var tab; + term_fd = std.in.fileno(); + + /* get the terminal size */ + term_width = 80; + if (os.isatty(term_fd)) { + if (os.ttyGetWinSize) { + tab = os.ttyGetWinSize(term_fd); + if (tab) + term_width = tab[0]; + } + if (os.ttySetRaw) { + /* set the TTY to raw mode */ + os.ttySetRaw(term_fd); + } + } + + /* install a Ctrl-C signal handler */ + os.signal(os.SIGINT, sigint_handler); + + /* install a handler to read stdin */ + term_read_buf = new Uint8Array(64); + os.setReadHandler(term_fd, term_read_handler); + } + + function sigint_handler() { + /* send Ctrl-C to readline */ + handle_byte(3); + } + + function term_read_handler() { + var l, i; + l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length); + for(i = 0; i < l; i++) + handle_byte(term_read_buf[i]); + } + + function handle_byte(c) { + if (!utf8) { + handle_char(c); + } else if (utf8_state !== 0 && (c >= 0x80 && c < 0xc0)) { + utf8_val = (utf8_val << 6) | (c & 0x3F); + utf8_state--; + if (utf8_state === 0) { + handle_char(utf8_val); + } + } else if (c >= 0xc0 && c < 0xf8) { + utf8_state = 1 + (c >= 0xe0) + (c >= 0xf0); + utf8_val = c & ((1 << (6 - utf8_state)) - 1); + } else { + utf8_state = 0; + handle_char(c); + } + } + + function is_alpha(c) { + return typeof c === "string" && + ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); + } + + function is_digit(c) { + return typeof c === "string" && (c >= '0' && c <= '9'); + } + + function is_word(c) { + return typeof c === "string" && + (is_alpha(c) || is_digit(c) || c == '_' || c == '$'); + } + + function ucs_length(str) { + var len, c, i, str_len = str.length; + len = 0; + /* we never count the trailing surrogate to have the + following property: ucs_length(str) = + ucs_length(str.substring(0, a)) + ucs_length(str.substring(a, + str.length)) for 0 <= a <= str.length */ + for(i = 0; i < str_len; i++) { + c = str.charCodeAt(i); + if (c < 0xdc00 || c >= 0xe000) + len++; + } + return len; + } + + function is_trailing_surrogate(c) { + var d; + if (typeof c !== "string") + return false; + d = c.codePointAt(0); /* can be NaN if empty string */ + return d >= 0xdc00 && d < 0xe000; + } + + function is_balanced(a, b) { + switch (a + b) { + case "()": + case "[]": + case "{}": + return true; + } + return false; + } + + function print_color_text(str, start, style_names) { + var i, j; + for (j = start; j < str.length;) { + var style = style_names[i = j]; + while (++j < str.length && style_names[j] == style) + continue; + std.puts(colors[styles[style] || 'default']); + std.puts(str.substring(i, j)); + std.puts(colors['none']); + } + } + + function print_csi(n, code) { + std.puts("\x1b[" + ((n != 1) ? n : "") + code); + } + + /* XXX: handle double-width characters */ + function move_cursor(delta) { + var i, l; + if (delta > 0) { + while (delta != 0) { + if (term_cursor_x == (term_width - 1)) { + std.puts("\n"); /* translated to CRLF */ + term_cursor_x = 0; + delta--; + } else { + l = Math.min(term_width - 1 - term_cursor_x, delta); + print_csi(l, "C"); /* right */ + delta -= l; + term_cursor_x += l; + } + } + } else { + delta = -delta; + while (delta != 0) { + if (term_cursor_x == 0) { + print_csi(1, "A"); /* up */ + print_csi(term_width - 1, "C"); /* right */ + delta--; + term_cursor_x = term_width - 1; + } else { + l = Math.min(delta, term_cursor_x); + print_csi(l, "D"); /* left */ + delta -= l; + term_cursor_x -= l; + } + } + } + } + + function update() { + var i, cmd_len; + /* cursor_pos is the position in 16 bit characters inside the + UTF-16 string 'cmd' */ + if (cmd != last_cmd) { + if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) { + /* optimize common case */ + std.puts(cmd.substring(last_cursor_pos)); + } else { + /* goto the start of the line */ + move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos))); + if (show_colors) { + var str = mexpr ? mexpr + '\n' + cmd : cmd; + var start = str.length - cmd.length; + var colorstate = colorize_js(str); + print_color_text(str, start, colorstate[2]); + } else { + std.puts(cmd); + } + } + term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width; + if (term_cursor_x == 0) { + /* show the cursor on the next line */ + std.puts(" \x08"); + } + /* remove the trailing characters */ + std.puts("\x1b[J"); + last_cmd = cmd; + last_cursor_pos = cmd.length; + } + if (cursor_pos > last_cursor_pos) { + move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos))); + } else if (cursor_pos < last_cursor_pos) { + move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos))); + } + last_cursor_pos = cursor_pos; + std.out.flush(); + } + + /* editing commands */ + function insert(str) { + if (str) { + cmd = cmd.substring(0, cursor_pos) + str + cmd.substring(cursor_pos); + cursor_pos += str.length; + } + } + + function quoted_insert() { + quote_flag = true; + } + + function abort() { + cmd = ""; + cursor_pos = 0; + return -2; + } + + function alert() { + } + + function beginning_of_line() { + cursor_pos = 0; + } + + function end_of_line() { + cursor_pos = cmd.length; + } + + function forward_char() { + if (cursor_pos < cmd.length) { + cursor_pos++; + while (is_trailing_surrogate(cmd.charAt(cursor_pos))) + cursor_pos++; + } + } + + function backward_char() { + if (cursor_pos > 0) { + cursor_pos--; + while (is_trailing_surrogate(cmd.charAt(cursor_pos))) + cursor_pos--; + } + } + + function skip_word_forward(pos) { + while (pos < cmd.length && !is_word(cmd.charAt(pos))) + pos++; + while (pos < cmd.length && is_word(cmd.charAt(pos))) + pos++; + return pos; + } + + function skip_word_backward(pos) { + while (pos > 0 && !is_word(cmd.charAt(pos - 1))) + pos--; + while (pos > 0 && is_word(cmd.charAt(pos - 1))) + pos--; + return pos; + } + + function forward_word() { + cursor_pos = skip_word_forward(cursor_pos); + } + + function backward_word() { + cursor_pos = skip_word_backward(cursor_pos); + } + + function accept_line() { + std.puts("\n"); + history_add(cmd); + return -1; + } + + function history_add(str) { + if (str) { + history.push(str); + } + history_index = history.length; + } + + function previous_history() { + if (history_index > 0) { + if (history_index == history.length) { + history.push(cmd); + } + history_index--; + cmd = history[history_index]; + cursor_pos = cmd.length; + } + } + + function next_history() { + if (history_index < history.length - 1) { + history_index++; + cmd = history[history_index]; + cursor_pos = cmd.length; + } + } + + function history_search(dir) { + var pos = cursor_pos; + for (var i = 1; i <= history.length; i++) { + var index = (history.length + i * dir + history_index) % history.length; + if (history[index].substring(0, pos) == cmd.substring(0, pos)) { + history_index = index; + cmd = history[index]; + return; + } + } + } + + function history_search_backward() { + return history_search(-1); + } + + function history_search_forward() { + return history_search(1); + } + + function delete_char_dir(dir) { + var start, end; + + start = cursor_pos; + if (dir < 0) { + start--; + while (is_trailing_surrogate(cmd.charAt(start))) + start--; + } + end = start + 1; + while (is_trailing_surrogate(cmd.charAt(end))) + end++; + + if (start >= 0 && start < cmd.length) { + if (last_fun === kill_region) { + kill_region(start, end, dir); + } else { + cmd = cmd.substring(0, start) + cmd.substring(end); + cursor_pos = start; + } + } + } + + function delete_char() { + delete_char_dir(1); + } + + function control_d() { + if (cmd.length == 0) { + std.puts("\n"); + return -3; /* exit read eval print loop */ + } else { + delete_char_dir(1); + } + } + + function backward_delete_char() { + delete_char_dir(-1); + } + + function transpose_chars() { + var pos = cursor_pos; + if (cmd.length > 1 && pos > 0) { + if (pos == cmd.length) + pos--; + cmd = cmd.substring(0, pos - 1) + cmd.substring(pos, pos + 1) + + cmd.substring(pos - 1, pos) + cmd.substring(pos + 1); + cursor_pos = pos + 1; + } + } + + function transpose_words() { + var p1 = skip_word_backward(cursor_pos); + var p2 = skip_word_forward(p1); + var p4 = skip_word_forward(cursor_pos); + var p3 = skip_word_backward(p4); + + if (p1 < p2 && p2 <= cursor_pos && cursor_pos <= p3 && p3 < p4) { + cmd = cmd.substring(0, p1) + cmd.substring(p3, p4) + + cmd.substring(p2, p3) + cmd.substring(p1, p2); + cursor_pos = p4; + } + } + + function upcase_word() { + var end = skip_word_forward(cursor_pos); + cmd = cmd.substring(0, cursor_pos) + + cmd.substring(cursor_pos, end).toUpperCase() + + cmd.substring(end); + } + + function downcase_word() { + var end = skip_word_forward(cursor_pos); + cmd = cmd.substring(0, cursor_pos) + + cmd.substring(cursor_pos, end).toLowerCase() + + cmd.substring(end); + } + + function kill_region(start, end, dir) { + var s = cmd.substring(start, end); + if (last_fun !== kill_region) + clip_board = s; + else if (dir < 0) + clip_board = s + clip_board; + else + clip_board = clip_board + s; + + cmd = cmd.substring(0, start) + cmd.substring(end); + if (cursor_pos > end) + cursor_pos -= end - start; + else if (cursor_pos > start) + cursor_pos = start; + this_fun = kill_region; + } + + function kill_line() { + kill_region(cursor_pos, cmd.length, 1); + } + + function backward_kill_line() { + kill_region(0, cursor_pos, -1); + } + + function kill_word() { + kill_region(cursor_pos, skip_word_forward(cursor_pos), 1); + } + + function backward_kill_word() { + kill_region(skip_word_backward(cursor_pos), cursor_pos, -1); + } + + function yank() { + insert(clip_board); + } + + function control_c() { + if (last_fun === control_c) { + std.puts("\n"); + std.exit(0); + } else { + std.puts("\n(Press Ctrl-C again to quit)\n"); + readline_print_prompt(); + } + } + + function reset() { + cmd = ""; + cursor_pos = 0; + } + + function get_context_word(line, pos) { + var s = ""; + while (pos > 0 && is_word(line[pos - 1])) { + pos--; + s = line[pos] + s; + } + return s; + } + function get_context_object(line, pos) { + var obj, base, c; + if (pos <= 0 || " ~!%^&*(-+={[|:;,<>?/".indexOf(line[pos - 1]) >= 0) + return g; + if (pos >= 2 && line[pos - 1] === ".") { + pos--; + obj = {}; + switch (c = line[pos - 1]) { + case '\'': + case '\"': + return "a"; + case ']': + return []; + case '}': + return {}; + case '/': + return / /; + default: + if (is_word(c)) { + base = get_context_word(line, pos); + if (["true", "false", "null", "this"].includes(base) || !isNaN(+base)) + return eval(base); + obj = get_context_object(line, pos - base.length); + if (obj === null || obj === void 0) + return obj; + if (obj === g && obj[base] === void 0) + return eval(base); + else + return obj[base]; + } + return {}; + } + } + return void 0; + } + + function get_completions(line, pos) { + var s, obj, ctx_obj, r, i, j, paren; + + s = get_context_word(line, pos); + ctx_obj = get_context_object(line, pos - s.length); + r = []; + /* enumerate properties from object and its prototype chain, + add non-numeric regular properties with s as e prefix + */ + for (i = 0, obj = ctx_obj; i < 10 && obj !== null && obj !== void 0; i++) { + var props = Object.getOwnPropertyNames(obj); + /* add non-numeric regular properties */ + for (j = 0; j < props.length; j++) { + var prop = props[j]; + if (typeof prop == "string" && ""+(+prop) != prop && prop.startsWith(s)) + r.push(prop); + } + obj = Object.getPrototypeOf(obj); + } + if (r.length > 1) { + /* sort list with internal names last and remove duplicates */ + function symcmp(a, b) { + if (a[0] != b[0]) { + if (a[0] == '_') + return 1; + if (b[0] == '_') + return -1; + } + if (a < b) + return -1; + if (a > b) + return +1; + return 0; + } + r.sort(symcmp); + for(i = j = 1; i < r.length; i++) { + if (r[i] != r[i - 1]) + r[j++] = r[i]; + } + r.length = j; + } + /* 'tab' = list of completions, 'pos' = cursor position inside + the completions */ + return { tab: r, pos: s.length, ctx: ctx_obj }; + } + + function completion() { + var tab, res, s, i, j, len, t, max_width, col, n_cols, row, n_rows; + res = get_completions(cmd, cursor_pos); + tab = res.tab; + if (tab.length === 0) + return; + s = tab[0]; + len = s.length; + /* add the chars which are identical in all the completions */ + for(i = 1; i < tab.length; i++) { + t = tab[i]; + for(j = 0; j < len; j++) { + if (t[j] !== s[j]) { + len = j; + break; + } + } + } + for(i = res.pos; i < len; i++) { + insert(s[i]); + } + if (last_fun === completion && tab.length == 1) { + /* append parentheses to function names */ + var m = res.ctx[tab[0]]; + if (typeof m == "function") { + insert('('); + if (m.length == 0) + insert(')'); + } else if (typeof m == "object") { + insert('.'); + } + } + /* show the possible completions */ + if (last_fun === completion && tab.length >= 2) { + max_width = 0; + for(i = 0; i < tab.length; i++) + max_width = Math.max(max_width, tab[i].length); + max_width += 2; + n_cols = Math.max(1, Math.floor((term_width + 1) / max_width)); + n_rows = Math.ceil(tab.length / n_cols); + std.puts("\n"); + /* display the sorted list column-wise */ + for (row = 0; row < n_rows; row++) { + for (col = 0; col < n_cols; col++) { + i = col * n_rows + row; + if (i >= tab.length) + break; + s = tab[i]; + if (col != n_cols - 1) + s = s.padEnd(max_width); + std.puts(s); + } + std.puts("\n"); + } + /* show a new prompt */ + readline_print_prompt(); + } + } + + var commands = { /* command table */ + "\x01": beginning_of_line, /* ^A - bol */ + "\x02": backward_char, /* ^B - backward-char */ + "\x03": control_c, /* ^C - abort */ + "\x04": control_d, /* ^D - delete-char or exit */ + "\x05": end_of_line, /* ^E - eol */ + "\x06": forward_char, /* ^F - forward-char */ + "\x07": abort, /* ^G - bell */ + "\x08": backward_delete_char, /* ^H - backspace */ + "\x09": completion, /* ^I - history-search-backward */ + "\x0a": accept_line, /* ^J - newline */ + "\x0b": kill_line, /* ^K - delete to end of line */ + "\x0d": accept_line, /* ^M - enter */ + "\x0e": next_history, /* ^N - down */ + "\x10": previous_history, /* ^P - up */ + "\x11": quoted_insert, /* ^Q - quoted-insert */ + "\x12": alert, /* ^R - reverse-search */ + "\x13": alert, /* ^S - search */ + "\x14": transpose_chars, /* ^T - transpose */ + "\x18": reset, /* ^X - cancel */ + "\x19": yank, /* ^Y - yank */ + "\x1bOA": previous_history, /* ^[OA - up */ + "\x1bOB": next_history, /* ^[OB - down */ + "\x1bOC": forward_char, /* ^[OC - right */ + "\x1bOD": backward_char, /* ^[OD - left */ + "\x1bOF": forward_word, /* ^[OF - ctrl-right */ + "\x1bOH": backward_word, /* ^[OH - ctrl-left */ + "\x1b[1;5C": forward_word, /* ^[[1;5C - ctrl-right */ + "\x1b[1;5D": backward_word, /* ^[[1;5D - ctrl-left */ + "\x1b[1~": beginning_of_line, /* ^[[1~ - bol */ + "\x1b[3~": delete_char, /* ^[[3~ - delete */ + "\x1b[4~": end_of_line, /* ^[[4~ - eol */ + "\x1b[5~": history_search_backward,/* ^[[5~ - page up */ + "\x1b[6~": history_search_forward, /* ^[[5~ - page down */ + "\x1b[A": previous_history, /* ^[[A - up */ + "\x1b[B": next_history, /* ^[[B - down */ + "\x1b[C": forward_char, /* ^[[C - right */ + "\x1b[D": backward_char, /* ^[[D - left */ + "\x1b[F": end_of_line, /* ^[[F - end */ + "\x1b[H": beginning_of_line, /* ^[[H - home */ + "\x1b\x7f": backward_kill_word, /* M-C-? - backward_kill_word */ + "\x1bb": backward_word, /* M-b - backward_word */ + "\x1bd": kill_word, /* M-d - kill_word */ + "\x1bf": forward_word, /* M-f - backward_word */ + "\x1bk": backward_kill_line, /* M-k - backward_kill_line */ + "\x1bl": downcase_word, /* M-l - downcase_word */ + "\x1bt": transpose_words, /* M-t - transpose_words */ + "\x1bu": upcase_word, /* M-u - upcase_word */ + "\x7f": backward_delete_char, /* ^? - delete */ + }; + + function dupstr(str, count) { + var res = ""; + while (count-- > 0) + res += str; + return res; + } + + var readline_keys; + var readline_state; + var readline_cb; + + function readline_print_prompt() + { + std.puts(prompt); + term_cursor_x = ucs_length(prompt) % term_width; + last_cmd = ""; + last_cursor_pos = 0; + } + + function readline_start(defstr, cb) { + cmd = defstr || ""; + cursor_pos = cmd.length; + history_index = history.length; + readline_cb = cb; + + prompt = pstate; + + if (mexpr) { + prompt += dupstr(" ", plen - prompt.length); + prompt += ps2; + } else { + if (show_time) { + var t = eval_time / 1000; + prompt += t.toFixed(6) + " "; + } + plen = prompt.length; + prompt += ps1; + } + readline_print_prompt(); + update(); + readline_state = 0; + } + + function handle_char(c1) { + var c; + c = String.fromCodePoint(c1); + switch(readline_state) { + case 0: + if (c == '\x1b') { /* '^[' - ESC */ + readline_keys = c; + readline_state = 1; + } else { + handle_key(c); + } + break; + case 1: /* '^[ */ + readline_keys += c; + if (c == '[') { + readline_state = 2; + } else if (c == 'O') { + readline_state = 3; + } else { + handle_key(readline_keys); + readline_state = 0; + } + break; + case 2: /* '^[[' - CSI */ + readline_keys += c; + if (!(c == ';' || (c >= '0' && c <= '9'))) { + handle_key(readline_keys); + readline_state = 0; + } + break; + case 3: /* '^[O' - ESC2 */ + readline_keys += c; + handle_key(readline_keys); + readline_state = 0; + break; + } + } + + function handle_key(keys) { + var fun; + + if (quote_flag) { + if (ucs_length(keys) === 1) + insert(keys); + quote_flag = false; + } else if (fun = commands[keys]) { + this_fun = fun; + switch (fun(keys)) { + case -1: + readline_cb(cmd); + return; + case -2: + readline_cb(null); + return; + case -3: + /* uninstall a Ctrl-C signal handler */ + os.signal(os.SIGINT, null); + /* uninstall the stdin read handler */ + os.setReadHandler(term_fd, null); + return; + } + last_fun = this_fun; + } else if (ucs_length(keys) === 1 && keys >= ' ') { + insert(keys); + last_fun = insert; + } else { + alert(); /* beep! */ + } + + cursor_pos = (cursor_pos < 0) ? 0 : + (cursor_pos > cmd.length) ? cmd.length : cursor_pos; + update(); + } + + var hex_mode = false; + var eval_mode = "std"; + + function number_to_string(a, radix) { + var s; + if (!isFinite(a)) { + /* NaN, Infinite */ + return a.toString(); + } else { + if (a == 0) { + if (1 / a < 0) + s = "-0"; + else + s = "0"; + } else { + if (radix == 16 && a === Math.floor(a)) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + } + return s; + } + } + + function bigfloat_to_string(a, radix) { + var s; + if (!BigFloat.isFinite(a)) { + /* NaN, Infinite */ + if (eval_mode !== "math") { + return "BigFloat(" + a.toString() + ")"; + } else { + return a.toString(); + } + } else { + if (a == 0) { + if (1 / a < 0) + s = "-0"; + else + s = "0"; + } else { + if (radix == 16) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + } + if (typeof a === "bigfloat" && eval_mode !== "math") { + s += "l"; + } else if (eval_mode !== "std" && s.indexOf(".") < 0 && + ((radix == 16 && s.indexOf("p") < 0) || + (radix == 10 && s.indexOf("e") < 0))) { + /* add a decimal point so that the floating point type + is visible */ + s += ".0"; + } + return s; + } + } + + function bigint_to_string(a, radix) { + var s; + if (radix == 16) { + var s; + if (a < 0) { + a = -a; + s = "-"; + } else { + s = ""; + } + s += "0x" + a.toString(16); + } else { + s = a.toString(); + } + if (eval_mode === "std") + s += "n"; + return s; + } + + function print(a) { + var stack = []; + + function print_rec(a) { + var n, i, keys, key, type, s; + + type = typeof(a); + if (type === "object") { + if (a === null) { + std.puts(a); + } else if (stack.indexOf(a) >= 0) { + std.puts("[circular]"); + } else if (has_jscalc && (a instanceof Fraction || + a instanceof Complex || + a instanceof Mod || + a instanceof Polynomial || + a instanceof PolyMod || + a instanceof RationalFunction || + a instanceof Series)) { + std.puts(a.toString()); + } else { + stack.push(a); + if (Array.isArray(a)) { + n = a.length; + std.puts("[ "); + for(i = 0; i < n; i++) { + if (i !== 0) + std.puts(", "); + if (i in a) { + print_rec(a[i]); + } else { + std.puts(""); + } + if (i > 20) { + std.puts("..."); + break; + } + } + std.puts(" ]"); + } else if (Object.__getClass(a) === "RegExp") { + std.puts(a.toString()); + } else { + keys = Object.keys(a); + n = keys.length; + std.puts("{ "); + for(i = 0; i < n; i++) { + if (i !== 0) + std.puts(", "); + key = keys[i]; + std.puts(key, ": "); + print_rec(a[key]); + } + std.puts(" }"); + } + stack.pop(a); + } + } else if (type === "string") { + s = a.__quote(); + if (s.length > 79) + s = s.substring(0, 75) + "...\""; + std.puts(s); + } else if (type === "number") { + std.puts(number_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigint") { + std.puts(bigint_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigfloat") { + std.puts(bigfloat_to_string(a, hex_mode ? 16 : 10)); + } else if (type === "bigdecimal") { + std.puts(a.toString() + "m"); + } else if (type === "symbol") { + std.puts(String(a)); + } else if (type === "function") { + std.puts("function " + a.name + "()"); + } else { + std.puts(a); + } + } + print_rec(a); + } + + function extract_directive(a) { + var pos; + if (a[0] !== '\\') + return ""; + for (pos = 1; pos < a.length; pos++) { + if (!is_alpha(a[pos])) + break; + } + return a.substring(1, pos); + } + + /* return true if the string after cmd can be evaluted as JS */ + function handle_directive(cmd, expr) { + var param, prec1, expBits1; + + if (cmd === "h" || cmd === "?" || cmd == "help") { + help(); + } else if (cmd === "load") { + var filename = expr.substring(cmd.length + 1).trim(); + if (filename.lastIndexOf(".") <= filename.lastIndexOf("/")) + filename += ".js"; + std.loadScript(filename); + return false; + } else if (cmd === "x") { + hex_mode = true; + } else if (cmd === "d") { + hex_mode = false; + } else if (cmd === "t") { + show_time = !show_time; + } else if (has_bignum && cmd === "p") { + param = expr.substring(cmd.length + 1).trim().split(" "); + if (param.length === 1 && param[0] === "") { + std.puts("BigFloat precision=" + prec + " bits (~" + + Math.floor(prec / log2_10) + + " digits), exponent size=" + expBits + " bits\n"); + } else if (param[0] === "f16") { + prec = 11; + expBits = 5; + } else if (param[0] === "f32") { + prec = 24; + expBits = 8; + } else if (param[0] === "f64") { + prec = 53; + expBits = 11; + } else if (param[0] === "f128") { + prec = 113; + expBits = 15; + } else { + prec1 = parseInt(param[0]); + if (param.length >= 2) + expBits1 = parseInt(param[1]); + else + expBits1 = BigFloatEnv.expBitsMax; + if (Number.isNaN(prec1) || + prec1 < BigFloatEnv.precMin || + prec1 > BigFloatEnv.precMax) { + std.puts("Invalid precision\n"); + return false; + } + if (Number.isNaN(expBits1) || + expBits1 < BigFloatEnv.expBitsMin || + expBits1 > BigFloatEnv.expBitsMax) { + std.puts("Invalid exponent bits\n"); + return false; + } + prec = prec1; + expBits = expBits1; + } + return false; + } else if (has_bignum && cmd === "digits") { + param = expr.substring(cmd.length + 1).trim(); + prec1 = Math.ceil(parseFloat(param) * log2_10); + if (prec1 < BigFloatEnv.precMin || + prec1 > BigFloatEnv.precMax) { + std.puts("Invalid precision\n"); + return false; + } + prec = prec1; + expBits = BigFloatEnv.expBitsMax; + return false; + } else if (has_bignum && cmd === "mode") { + param = expr.substring(cmd.length + 1).trim(); + if (param === "") { + std.puts("Running mode=" + eval_mode + "\n"); + } else if (param === "std" || param === "math") { + eval_mode = param; + } else { + std.puts("Invalid mode\n"); + } + return false; + } else if (cmd === "clear") { + std.puts("\x1b[H\x1b[J"); + } else if (cmd === "q") { + std.exit(0); + } else if (has_jscalc && cmd === "a") { + algebraicMode = true; + } else if (has_jscalc && cmd === "n") { + algebraicMode = false; + } else { + std.puts("Unknown directive: " + cmd + "\n"); + return false; + } + return true; + } + + if (config_numcalc) { + /* called by the GUI */ + g.execCmd = function (cmd) { + switch(cmd) { + case "dec": + hex_mode = false; + break; + case "hex": + hex_mode = true; + break; + case "num": + algebraicMode = false; + break; + case "alg": + algebraicMode = true; + break; + } + } + } + + function help() { + function sel(n) { + return n ? "*": " "; + } + std.puts("\\h this help\n" + + "\\x " + sel(hex_mode) + "hexadecimal number display\n" + + "\\d " + sel(!hex_mode) + "decimal number display\n" + + "\\t " + sel(show_time) + "toggle timing display\n" + + "\\clear clear the terminal\n"); + if (has_jscalc) { + std.puts("\\a " + sel(algebraicMode) + "algebraic mode\n" + + "\\n " + sel(!algebraicMode) + "numeric mode\n"); + } + if (has_bignum) { + std.puts("\\p [m [e]] set the BigFloat precision to 'm' bits\n" + + "\\digits n set the BigFloat precision to 'ceil(n*log2(10))' bits\n"); + if (!has_jscalc) { + std.puts("\\mode [std|math] change the running mode (current = " + eval_mode + ")\n"); + } + } + if (!config_numcalc) { + std.puts("\\q exit\n"); + } + } + + function cmd_start() { + if (!config_numcalc) { + if (has_jscalc) + std.puts('QJSCalc - Type "\\h" for help\n'); + else + std.puts('QuickJS - Type "\\h" for help\n'); + } + if (has_bignum) { + log2_10 = Math.log(10) / Math.log(2); + prec = 113; + expBits = 15; + if (has_jscalc) { + eval_mode = "math"; + /* XXX: numeric mode should always be the default ? */ + g.algebraicMode = config_numcalc; + } + } + + cmd_readline_start(); + } + + function cmd_readline_start() { + readline_start(dupstr(" ", level), readline_handle_cmd); + } + + function readline_handle_cmd(expr) { + if (!handle_cmd(expr)) { + cmd_readline_start(); + } + } + + /* return true if async termination */ + function handle_cmd(expr) { + var colorstate, cmd; + + if (expr === null) { + expr = ""; + return false; + } + if (expr === "?") { + help(); + return false; + } + cmd = extract_directive(expr); + if (cmd.length > 0) { + if (!handle_directive(cmd, expr)) { + return false; + } + expr = expr.substring(cmd.length + 1); + } + if (expr === "") + return false; + + if (mexpr) + expr = mexpr + '\n' + expr; + colorstate = colorize_js(expr); + pstate = colorstate[0]; + level = colorstate[1]; + if (pstate) { + mexpr = expr; + return false; + } + mexpr = ""; + + if (has_bignum) { + /* XXX: async is not supported in this case */ + BigFloatEnv.setPrec(eval_and_print_start.bind(null, expr, false), + prec, expBits); + } else { + eval_and_print_start(expr, true); + } + return true; + } + + function eval_and_print_start(expr, is_async) { + var result; + + try { + if (eval_mode === "math") + expr = '"use math"; void 0;' + expr; + eval_start_time = os.now(); + /* eval as a script */ + result = std.evalScript(expr, { backtrace_barrier: true, async: is_async }); + if (is_async) { + /* result is a promise */ + result.then(print_eval_result, print_eval_error); + } else { + print_eval_result(result); + } + } catch (error) { + print_eval_error(error); + } + } + + function print_eval_result(result) { + eval_time = os.now() - eval_start_time; + std.puts(colors[styles.result]); + print(result); + std.puts("\n"); + std.puts(colors.none); + /* set the last result */ + g._ = result; + + handle_cmd_end(); + } + + function print_eval_error(error) { + std.puts(colors[styles.error_msg]); + if (error instanceof Error) { + console.log(error); + if (error.stack) { + std.puts(error.stack); + } + } else { + std.puts("Throw: "); + console.log(error); + } + std.puts(colors.none); + + handle_cmd_end(); + } + + function handle_cmd_end() { + level = 0; + /* run the garbage collector after each command */ + std.gc(); + cmd_readline_start(); + } + + function colorize_js(str) { + var i, c, start, n = str.length; + var style, state = "", level = 0; + var primary, can_regex = 1; + var r = []; + + function push_state(c) { state += c; } + function last_state(c) { return state.substring(state.length - 1); } + function pop_state(c) { + var c = last_state(); + state = state.substring(0, state.length - 1); + return c; + } + + function parse_block_comment() { + style = 'comment'; + push_state('/'); + for (i++; i < n - 1; i++) { + if (str[i] == '*' && str[i + 1] == '/') { + i += 2; + pop_state('/'); + break; + } + } + } + + function parse_line_comment() { + style = 'comment'; + for (i++; i < n; i++) { + if (str[i] == '\n') { + break; + } + } + } + + function parse_string(delim) { + style = 'string'; + push_state(delim); + while (i < n) { + c = str[i++]; + if (c == '\n') { + style = 'error'; + continue; + } + if (c == '\\') { + if (i >= n) + break; + i++; + } else + if (c == delim) { + pop_state(); + break; + } + } + } + + function parse_regex() { + style = 'regex'; + push_state('/'); + while (i < n) { + c = str[i++]; + if (c == '\n') { + style = 'error'; + continue; + } + if (c == '\\') { + if (i < n) { + i++; + } + continue; + } + if (last_state() == '[') { + if (c == ']') { + pop_state() + } + // ECMA 5: ignore '/' inside char classes + continue; + } + if (c == '[') { + push_state('['); + if (str[i] == '[' || str[i] == ']') + i++; + continue; + } + if (c == '/') { + pop_state(); + while (i < n && is_word(str[i])) + i++; + break; + } + } + } + + function parse_number() { + style = 'number'; + while (i < n && (is_word(str[i]) || (str[i] == '.' && (i == n - 1 || str[i + 1] != '.')))) { + i++; + } + } + + var js_keywords = "|" + + "break|case|catch|continue|debugger|default|delete|do|" + + "else|finally|for|function|if|in|instanceof|new|" + + "return|switch|this|throw|try|typeof|while|with|" + + "class|const|enum|import|export|extends|super|" + + "implements|interface|let|package|private|protected|" + + "public|static|yield|" + + "undefined|null|true|false|Infinity|NaN|" + + "eval|arguments|" + + "await|"; + + var js_no_regex = "|this|super|undefined|null|true|false|Infinity|NaN|arguments|"; + var js_types = "|void|var|"; + + function parse_identifier() { + can_regex = 1; + + while (i < n && is_word(str[i])) + i++; + + var w = '|' + str.substring(start, i) + '|'; + + if (js_keywords.indexOf(w) >= 0) { + style = 'keyword'; + if (js_no_regex.indexOf(w) >= 0) + can_regex = 0; + return; + } + + var i1 = i; + while (i1 < n && str[i1] == ' ') + i1++; + + if (i1 < n && str[i1] == '(') { + style = 'function'; + return; + } + + if (js_types.indexOf(w) >= 0) { + style = 'type'; + return; + } + + style = 'identifier'; + can_regex = 0; + } + + function set_style(from, to) { + while (r.length < from) + r.push('default'); + while (r.length < to) + r.push(style); + } + + for (i = 0; i < n;) { + style = null; + start = i; + switch (c = str[i++]) { + case ' ': + case '\t': + case '\r': + case '\n': + continue; + case '+': + case '-': + if (i < n && str[i] == c) { + i++; + continue; + } + can_regex = 1; + continue; + case '/': + if (i < n && str[i] == '*') { // block comment + parse_block_comment(); + break; + } + if (i < n && str[i] == '/') { // line comment + parse_line_comment(); + break; + } + if (can_regex) { + parse_regex(); + can_regex = 0; + break; + } + can_regex = 1; + continue; + case '\'': + case '\"': + case '`': + parse_string(c); + can_regex = 0; + break; + case '(': + case '[': + case '{': + can_regex = 1; + level++; + push_state(c); + continue; + case ')': + case ']': + case '}': + can_regex = 0; + if (level > 0 && is_balanced(last_state(), c)) { + level--; + pop_state(); + continue; + } + style = 'error'; + break; + default: + if (is_digit(c)) { + parse_number(); + can_regex = 0; + break; + } + if (is_word(c) || c == '$') { + parse_identifier(); + break; + } + can_regex = 1; + continue; + } + if (style) + set_style(start, i); + } + set_style(n, n); + return [ state, level, r ]; + } + + termInit(); + + cmd_start(); + +})(globalThis); diff --git a/deps/quickjs/run-test262.c b/deps/quickjs/run-test262.c new file mode 100644 index 0000000..bf905bd --- /dev/null +++ b/deps/quickjs/run-test262.c @@ -0,0 +1,2145 @@ +/* + * ECMA Test 262 Runner for QuickJS + * + * Copyright (c) 2017-2021 Fabrice Bellard + * Copyright (c) 2017-2021 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" +#include "list.h" +#include "quickjs-libc.h" + +/* enable test262 thread support to test SharedArrayBuffer and Atomics */ +#define CONFIG_AGENT + +#define CMD_NAME "run-test262" + +typedef struct namelist_t { + char **array; + int count; + int size; + unsigned int sorted : 1; +} namelist_t; + +namelist_t test_list; +namelist_t exclude_list; +namelist_t exclude_dir_list; + +FILE *outfile; +enum test_mode_t { + TEST_DEFAULT_NOSTRICT, /* run tests as nostrict unless test is flagged as strictonly */ + TEST_DEFAULT_STRICT, /* run tests as strict unless test is flagged as nostrict */ + TEST_NOSTRICT, /* run tests as nostrict, skip strictonly tests */ + TEST_STRICT, /* run tests as strict, skip nostrict tests */ + TEST_ALL, /* run tests in both strict and nostrict, unless restricted by spec */ +} test_mode = TEST_DEFAULT_NOSTRICT; +int skip_async; +int skip_module; +int new_style; +int dump_memory; +int stats_count; +JSMemoryUsage stats_all, stats_avg, stats_min, stats_max; +char *stats_min_filename; +char *stats_max_filename; +int verbose; +char *harness_dir; +char *harness_exclude; +char *harness_features; +char *harness_skip_features; +char *error_filename; +char *error_file; +FILE *error_out; +char *report_filename; +int update_errors; +int test_count, test_failed, test_index, test_skipped, test_excluded; +int new_errors, changed_errors, fixed_errors; +int async_done; + +void warning(const char *, ...) __attribute__((__format__(__printf__, 1, 2))); +void fatal(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3))); + +void warning(const char *fmt, ...) +{ + va_list ap; + + fflush(stdout); + fprintf(stderr, "%s: ", CMD_NAME); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); +} + +void fatal(int errcode, const char *fmt, ...) +{ + va_list ap; + + fflush(stdout); + fprintf(stderr, "%s: ", CMD_NAME); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + + exit(errcode); +} + +void perror_exit(int errcode, const char *s) +{ + fflush(stdout); + fprintf(stderr, "%s: ", CMD_NAME); + perror(s); + exit(errcode); +} + +char *strdup_len(const char *str, int len) +{ + char *p = malloc(len + 1); + memcpy(p, str, len); + p[len] = '\0'; + return p; +} + +static inline int str_equal(const char *a, const char *b) { + return !strcmp(a, b); +} + +char *str_append(char **pp, const char *sep, const char *str) { + char *res, *p; + size_t len = 0; + p = *pp; + if (p) { + len = strlen(p) + strlen(sep); + } + res = malloc(len + strlen(str) + 1); + if (p) { + strcpy(res, p); + strcat(res, sep); + } + strcpy(res + len, str); + free(p); + return *pp = res; +} + +char *str_strip(char *p) +{ + size_t len = strlen(p); + while (len > 0 && isspace((unsigned char)p[len - 1])) + p[--len] = '\0'; + while (isspace((unsigned char)*p)) + p++; + return p; +} + +int has_prefix(const char *str, const char *prefix) +{ + return !strncmp(str, prefix, strlen(prefix)); +} + +char *skip_prefix(const char *str, const char *prefix) +{ + int i; + for (i = 0;; i++) { + if (prefix[i] == '\0') { /* skip the prefix */ + str += i; + break; + } + if (str[i] != prefix[i]) + break; + } + return (char *)str; +} + +char *get_basename(const char *filename) +{ + char *p; + + p = strrchr(filename, '/'); + if (!p) + return NULL; + return strdup_len(filename, p - filename); +} + +char *compose_path(const char *path, const char *name) +{ + int path_len, name_len; + char *d, *q; + + if (!path || path[0] == '\0' || *name == '/') { + d = strdup(name); + } else { + path_len = strlen(path); + name_len = strlen(name); + d = malloc(path_len + 1 + name_len + 1); + if (d) { + q = d; + memcpy(q, path, path_len); + q += path_len; + if (path[path_len - 1] != '/') + *q++ = '/'; + memcpy(q, name, name_len + 1); + } + } + return d; +} + +int namelist_cmp(const char *a, const char *b) +{ + /* compare strings in modified lexicographical order */ + for (;;) { + int ca = (unsigned char)*a++; + int cb = (unsigned char)*b++; + if (isdigit(ca) && isdigit(cb)) { + int na = ca - '0'; + int nb = cb - '0'; + while (isdigit(ca = (unsigned char)*a++)) + na = na * 10 + ca - '0'; + while (isdigit(cb = (unsigned char)*b++)) + nb = nb * 10 + cb - '0'; + if (na < nb) + return -1; + if (na > nb) + return +1; + } + if (ca < cb) + return -1; + if (ca > cb) + return +1; + if (ca == '\0') + return 0; + } +} + +int namelist_cmp_indirect(const void *a, const void *b) +{ + return namelist_cmp(*(const char **)a, *(const char **)b); +} + +void namelist_sort(namelist_t *lp) +{ + int i, count; + if (lp->count > 1) { + qsort(lp->array, lp->count, sizeof(*lp->array), namelist_cmp_indirect); + /* remove duplicates */ + for (count = i = 1; i < lp->count; i++) { + if (namelist_cmp(lp->array[count - 1], lp->array[i]) == 0) { + free(lp->array[i]); + } else { + lp->array[count++] = lp->array[i]; + } + } + lp->count = count; + } + lp->sorted = 1; +} + +int namelist_find(namelist_t *lp, const char *name) +{ + int a, b, m, cmp; + + if (!lp->sorted) { + namelist_sort(lp); + } + for (a = 0, b = lp->count; a < b;) { + m = a + (b - a) / 2; + cmp = namelist_cmp(lp->array[m], name); + if (cmp < 0) + a = m + 1; + else if (cmp > 0) + b = m; + else + return m; + } + return -1; +} + +void namelist_add(namelist_t *lp, const char *base, const char *name) +{ + char *s; + + s = compose_path(base, name); + if (!s) + goto fail; + if (lp->count == lp->size) { + size_t newsize = lp->size + (lp->size >> 1) + 4; + char **a = realloc(lp->array, sizeof(lp->array[0]) * newsize); + if (!a) + goto fail; + lp->array = a; + lp->size = newsize; + } + lp->array[lp->count] = s; + lp->count++; + return; +fail: + fatal(1, "allocation failure\n"); +} + +void namelist_load(namelist_t *lp, const char *filename) +{ + char buf[1024]; + char *base_name; + FILE *f; + + f = fopen(filename, "rb"); + if (!f) { + perror_exit(1, filename); + } + base_name = get_basename(filename); + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p = str_strip(buf); + if (*p == '#' || *p == ';' || *p == '\0') + continue; /* line comment */ + + namelist_add(lp, base_name, p); + } + free(base_name); + fclose(f); +} + +void namelist_add_from_error_file(namelist_t *lp, const char *file) +{ + const char *p, *p0; + char *pp; + + for (p = file; (p = strstr(p, ".js:")) != NULL; p++) { + for (p0 = p; p0 > file && p0[-1] != '\n'; p0--) + continue; + pp = strdup_len(p0, p + 3 - p0); + namelist_add(lp, NULL, pp); + free(pp); + } +} + +void namelist_free(namelist_t *lp) +{ + while (lp->count > 0) { + free(lp->array[--lp->count]); + } + free(lp->array); + lp->array = NULL; + lp->size = 0; +} + +static int add_test_file(const char *filename, const struct stat *ptr, int flag) +{ + namelist_t *lp = &test_list; + if (has_suffix(filename, ".js") && !has_suffix(filename, "_FIXTURE.js")) + namelist_add(lp, NULL, filename); + return 0; +} + +/* find js files from the directory tree and sort the list */ +static void enumerate_tests(const char *path) +{ + namelist_t *lp = &test_list; + int start = lp->count; + ftw(path, add_test_file, 100); + qsort(lp->array + start, lp->count - start, sizeof(*lp->array), + namelist_cmp_indirect); +} + +static JSValue js_print(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + int i; + const char *str; + + if (outfile) { + for (i = 0; i < argc; i++) { + if (i != 0) + fputc(' ', outfile); + str = JS_ToCString(ctx, argv[i]); + if (!str) + return JS_EXCEPTION; + if (!strcmp(str, "Test262:AsyncTestComplete")) { + async_done++; + } else if (strstart(str, "Test262:AsyncTestFailure", NULL)) { + async_done = 2; /* force an error */ + } + fputs(str, outfile); + JS_FreeCString(ctx, str); + } + fputc('\n', outfile); + } + return JS_UNDEFINED; +} + +static JSValue js_detachArrayBuffer(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JS_DetachArrayBuffer(ctx, argv[0]); + return JS_UNDEFINED; +} + +static JSValue js_evalScript(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + const char *str; + size_t len; + JSValue ret; + str = JS_ToCStringLen(ctx, &len, argv[0]); + if (!str) + return JS_EXCEPTION; + ret = JS_Eval(ctx, str, len, "", JS_EVAL_TYPE_GLOBAL); + JS_FreeCString(ctx, str); + return ret; +} + +#ifdef CONFIG_AGENT + +#include + +typedef struct { + struct list_head link; + pthread_t tid; + char *script; + JSValue broadcast_func; + BOOL broadcast_pending; + JSValue broadcast_sab; /* in the main context */ + uint8_t *broadcast_sab_buf; + size_t broadcast_sab_size; + int32_t broadcast_val; +} Test262Agent; + +typedef struct { + struct list_head link; + char *str; +} AgentReport; + +static JSValue add_helpers1(JSContext *ctx); +static void add_helpers(JSContext *ctx); + +static pthread_mutex_t agent_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t agent_cond = PTHREAD_COND_INITIALIZER; +/* list of Test262Agent.link */ +static struct list_head agent_list = LIST_HEAD_INIT(agent_list); + +static pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER; +/* list of AgentReport.link */ +static struct list_head report_list = LIST_HEAD_INIT(report_list); + +static void *agent_start(void *arg) +{ + Test262Agent *agent = arg; + JSRuntime *rt; + JSContext *ctx; + JSValue ret_val; + int ret; + + rt = JS_NewRuntime(); + if (rt == NULL) { + fatal(1, "JS_NewRuntime failure"); + } + ctx = JS_NewContext(rt); + if (ctx == NULL) { + JS_FreeRuntime(rt); + fatal(1, "JS_NewContext failure"); + } + JS_SetContextOpaque(ctx, agent); + JS_SetRuntimeInfo(rt, "agent"); + JS_SetCanBlock(rt, TRUE); + + add_helpers(ctx); + ret_val = JS_Eval(ctx, agent->script, strlen(agent->script), + "", JS_EVAL_TYPE_GLOBAL); + free(agent->script); + agent->script = NULL; + if (JS_IsException(ret_val)) + js_std_dump_error(ctx); + JS_FreeValue(ctx, ret_val); + + for(;;) { + JSContext *ctx1; + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (ret < 0) { + js_std_dump_error(ctx); + break; + } else if (ret == 0) { + if (JS_IsUndefined(agent->broadcast_func)) { + break; + } else { + JSValue args[2]; + + pthread_mutex_lock(&agent_mutex); + while (!agent->broadcast_pending) { + pthread_cond_wait(&agent_cond, &agent_mutex); + } + + agent->broadcast_pending = FALSE; + pthread_cond_signal(&agent_cond); + + pthread_mutex_unlock(&agent_mutex); + + args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf, + agent->broadcast_sab_size, + NULL, NULL, TRUE); + args[1] = JS_NewInt32(ctx, agent->broadcast_val); + ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED, + 2, (JSValueConst *)args); + JS_FreeValue(ctx, args[0]); + JS_FreeValue(ctx, args[1]); + if (JS_IsException(ret_val)) + js_std_dump_error(ctx); + JS_FreeValue(ctx, ret_val); + JS_FreeValue(ctx, agent->broadcast_func); + agent->broadcast_func = JS_UNDEFINED; + } + } + } + JS_FreeValue(ctx, agent->broadcast_func); + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return NULL; +} + +static JSValue js_agent_start(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + const char *script; + Test262Agent *agent; + + if (JS_GetContextOpaque(ctx) != NULL) + return JS_ThrowTypeError(ctx, "cannot be called inside an agent"); + + script = JS_ToCString(ctx, argv[0]); + if (!script) + return JS_EXCEPTION; + agent = malloc(sizeof(*agent)); + memset(agent, 0, sizeof(*agent)); + agent->broadcast_func = JS_UNDEFINED; + agent->broadcast_sab = JS_UNDEFINED; + agent->script = strdup(script); + JS_FreeCString(ctx, script); + list_add_tail(&agent->link, &agent_list); + pthread_create(&agent->tid, NULL, agent_start, agent); + return JS_UNDEFINED; +} + +static void js_agent_free(JSContext *ctx) +{ + struct list_head *el, *el1; + Test262Agent *agent; + + list_for_each_safe(el, el1, &agent_list) { + agent = list_entry(el, Test262Agent, link); + pthread_join(agent->tid, NULL); + JS_FreeValue(ctx, agent->broadcast_sab); + list_del(&agent->link); + free(agent); + } +} + +static JSValue js_agent_leaving(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + Test262Agent *agent = JS_GetContextOpaque(ctx); + if (!agent) + return JS_ThrowTypeError(ctx, "must be called inside an agent"); + /* nothing to do */ + return JS_UNDEFINED; +} + +static BOOL is_broadcast_pending(void) +{ + struct list_head *el; + Test262Agent *agent; + list_for_each(el, &agent_list) { + agent = list_entry(el, Test262Agent, link); + if (agent->broadcast_pending) + return TRUE; + } + return FALSE; +} + +static JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSValueConst sab = argv[0]; + struct list_head *el; + Test262Agent *agent; + uint8_t *buf; + size_t buf_size; + int32_t val; + + if (JS_GetContextOpaque(ctx) != NULL) + return JS_ThrowTypeError(ctx, "cannot be called inside an agent"); + + buf = JS_GetArrayBuffer(ctx, &buf_size, sab); + if (!buf) + return JS_EXCEPTION; + if (JS_ToInt32(ctx, &val, argv[1])) + return JS_EXCEPTION; + + /* broadcast the values and wait until all agents have started + calling their callbacks */ + pthread_mutex_lock(&agent_mutex); + list_for_each(el, &agent_list) { + agent = list_entry(el, Test262Agent, link); + agent->broadcast_pending = TRUE; + /* the shared array buffer is used by the thread, so increment + its refcount */ + agent->broadcast_sab = JS_DupValue(ctx, sab); + agent->broadcast_sab_buf = buf; + agent->broadcast_sab_size = buf_size; + agent->broadcast_val = val; + } + pthread_cond_broadcast(&agent_cond); + + while (is_broadcast_pending()) { + pthread_cond_wait(&agent_cond, &agent_mutex); + } + pthread_mutex_unlock(&agent_mutex); + return JS_UNDEFINED; +} + +static JSValue js_agent_receiveBroadcast(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + Test262Agent *agent = JS_GetContextOpaque(ctx); + if (!agent) + return JS_ThrowTypeError(ctx, "must be called inside an agent"); + if (!JS_IsFunction(ctx, argv[0])) + return JS_ThrowTypeError(ctx, "expecting function"); + JS_FreeValue(ctx, agent->broadcast_func); + agent->broadcast_func = JS_DupValue(ctx, argv[0]); + return JS_UNDEFINED; +} + +static JSValue js_agent_sleep(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + uint32_t duration; + if (JS_ToUint32(ctx, &duration, argv[0])) + return JS_EXCEPTION; + usleep(duration * 1000); + return JS_UNDEFINED; +} + +static int64_t get_clock_ms(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000); +} + +static JSValue js_agent_monotonicNow(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return JS_NewInt64(ctx, get_clock_ms()); +} + +static JSValue js_agent_getReport(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + AgentReport *rep; + JSValue ret; + + pthread_mutex_lock(&report_mutex); + if (list_empty(&report_list)) { + rep = NULL; + } else { + rep = list_entry(report_list.next, AgentReport, link); + list_del(&rep->link); + } + pthread_mutex_unlock(&report_mutex); + if (rep) { + ret = JS_NewString(ctx, rep->str); + free(rep->str); + free(rep); + } else { + ret = JS_NULL; + } + return ret; +} + +static JSValue js_agent_report(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + const char *str; + AgentReport *rep; + + str = JS_ToCString(ctx, argv[0]); + if (!str) + return JS_EXCEPTION; + rep = malloc(sizeof(*rep)); + rep->str = strdup(str); + JS_FreeCString(ctx, str); + + pthread_mutex_lock(&report_mutex); + list_add_tail(&rep->link, &report_list); + pthread_mutex_unlock(&report_mutex); + return JS_UNDEFINED; +} + +static const JSCFunctionListEntry js_agent_funcs[] = { + /* only in main */ + JS_CFUNC_DEF("start", 1, js_agent_start ), + JS_CFUNC_DEF("getReport", 0, js_agent_getReport ), + JS_CFUNC_DEF("broadcast", 2, js_agent_broadcast ), + /* only in agent */ + JS_CFUNC_DEF("report", 1, js_agent_report ), + JS_CFUNC_DEF("leaving", 0, js_agent_leaving ), + JS_CFUNC_DEF("receiveBroadcast", 1, js_agent_receiveBroadcast ), + /* in both */ + JS_CFUNC_DEF("sleep", 1, js_agent_sleep ), + JS_CFUNC_DEF("monotonicNow", 0, js_agent_monotonicNow ), +}; + +static JSValue js_new_agent(JSContext *ctx) +{ + JSValue agent; + agent = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, agent, js_agent_funcs, + countof(js_agent_funcs)); + return agent; +} +#endif + +static JSValue js_createRealm(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + JSContext *ctx1; + JSValue ret; + + ctx1 = JS_NewContext(JS_GetRuntime(ctx)); + if (!ctx1) + return JS_ThrowOutOfMemory(ctx); + ret = add_helpers1(ctx1); + /* ctx1 has a refcount so it stays alive */ + JS_FreeContext(ctx1); + return ret; +} + +static JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv) +{ + return JS_NULL; +} + +static JSValue add_helpers1(JSContext *ctx) +{ + JSValue global_obj; + JSValue obj262, obj; + + global_obj = JS_GetGlobalObject(ctx); + + JS_SetPropertyStr(ctx, global_obj, "print", + JS_NewCFunction(ctx, js_print, "print", 1)); + + /* $262 special object used by the tests */ + obj262 = JS_NewObject(ctx); + JS_SetPropertyStr(ctx, obj262, "detachArrayBuffer", + JS_NewCFunction(ctx, js_detachArrayBuffer, + "detachArrayBuffer", 1)); + JS_SetPropertyStr(ctx, obj262, "evalScript", + JS_NewCFunction(ctx, js_evalScript, + "evalScript", 1)); + JS_SetPropertyStr(ctx, obj262, "codePointRange", + JS_NewCFunction(ctx, js_string_codePointRange, + "codePointRange", 2)); +#ifdef CONFIG_AGENT + JS_SetPropertyStr(ctx, obj262, "agent", js_new_agent(ctx)); +#endif + + JS_SetPropertyStr(ctx, obj262, "global", + JS_DupValue(ctx, global_obj)); + JS_SetPropertyStr(ctx, obj262, "createRealm", + JS_NewCFunction(ctx, js_createRealm, + "createRealm", 0)); + obj = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0); + JS_SetIsHTMLDDA(ctx, obj); + JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj); + + JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262)); + + JS_FreeValue(ctx, global_obj); + return obj262; +} + +static void add_helpers(JSContext *ctx) +{ + JS_FreeValue(ctx, add_helpers1(ctx)); +} + +static char *load_file(const char *filename, size_t *lenp) +{ + char *buf; + size_t buf_len; + buf = (char *)js_load_file(NULL, &buf_len, filename); + if (!buf) + perror_exit(1, filename); + if (lenp) + *lenp = buf_len; + return buf; +} + +static JSModuleDef *js_module_loader_test(JSContext *ctx, + const char *module_name, void *opaque) +{ + size_t buf_len; + uint8_t *buf; + JSModuleDef *m; + JSValue func_val; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", + module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + return m; +} + +int is_line_sep(char c) +{ + return (c == '\0' || c == '\n' || c == '\r'); +} + +char *find_line(const char *str, const char *line) +{ + if (str) { + const char *p; + int len = strlen(line); + for (p = str; (p = strstr(p, line)) != NULL; p += len + 1) { + if ((p == str || is_line_sep(p[-1])) && is_line_sep(p[len])) + return (char *)p; + } + } + return NULL; +} + +int is_word_sep(char c) +{ + return (c == '\0' || isspace((unsigned char)c) || c == ','); +} + +char *find_word(const char *str, const char *word) +{ + const char *p; + int len = strlen(word); + if (str && len) { + for (p = str; (p = strstr(p, word)) != NULL; p += len) { + if ((p == str || is_word_sep(p[-1])) && is_word_sep(p[len])) + return (char *)p; + } + } + return NULL; +} + +/* handle exclude directories */ +void update_exclude_dirs(void) +{ + namelist_t *lp = &test_list; + namelist_t *ep = &exclude_list; + namelist_t *dp = &exclude_dir_list; + char *name; + int i, j, count; + + /* split directpries from exclude_list */ + for (count = i = 0; i < ep->count; i++) { + name = ep->array[i]; + if (has_suffix(name, "/")) { + namelist_add(dp, NULL, name); + free(name); + } else { + ep->array[count++] = name; + } + } + ep->count = count; + + namelist_sort(dp); + + /* filter out excluded directories */ + for (count = i = 0; i < lp->count; i++) { + name = lp->array[i]; + for (j = 0; j < dp->count; j++) { + if (has_prefix(name, dp->array[j])) { + test_excluded++; + free(name); + name = NULL; + break; + } + } + if (name) { + lp->array[count++] = name; + } + } + lp->count = count; +} + +void load_config(const char *filename) +{ + char buf[1024]; + FILE *f; + char *base_name; + enum { + SECTION_NONE = 0, + SECTION_CONFIG, + SECTION_EXCLUDE, + SECTION_FEATURES, + SECTION_TESTS, + } section = SECTION_NONE; + int lineno = 0; + + f = fopen(filename, "rb"); + if (!f) { + perror_exit(1, filename); + } + base_name = get_basename(filename); + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p, *q; + lineno++; + p = str_strip(buf); + if (*p == '#' || *p == ';' || *p == '\0') + continue; /* line comment */ + + if (*p == "[]"[0]) { + /* new section */ + p++; + p[strcspn(p, "]")] = '\0'; + if (str_equal(p, "config")) + section = SECTION_CONFIG; + else if (str_equal(p, "exclude")) + section = SECTION_EXCLUDE; + else if (str_equal(p, "features")) + section = SECTION_FEATURES; + else if (str_equal(p, "tests")) + section = SECTION_TESTS; + else + section = SECTION_NONE; + continue; + } + q = strchr(p, '='); + if (q) { + /* setting: name=value */ + *q++ = '\0'; + q = str_strip(q); + } + switch (section) { + case SECTION_CONFIG: + if (!q) { + printf("%s:%d: syntax error\n", filename, lineno); + continue; + } + if (str_equal(p, "style")) { + new_style = str_equal(q, "new"); + continue; + } + if (str_equal(p, "testdir")) { + char *testdir = compose_path(base_name, q); + enumerate_tests(testdir); + free(testdir); + continue; + } + if (str_equal(p, "harnessdir")) { + harness_dir = compose_path(base_name, q); + continue; + } + if (str_equal(p, "harnessexclude")) { + str_append(&harness_exclude, " ", q); + continue; + } + if (str_equal(p, "features")) { + str_append(&harness_features, " ", q); + continue; + } + if (str_equal(p, "skip-features")) { + str_append(&harness_skip_features, " ", q); + continue; + } + if (str_equal(p, "mode")) { + if (str_equal(q, "default") || str_equal(q, "default-nostrict")) + test_mode = TEST_DEFAULT_NOSTRICT; + else if (str_equal(q, "default-strict")) + test_mode = TEST_DEFAULT_STRICT; + else if (str_equal(q, "nostrict")) + test_mode = TEST_NOSTRICT; + else if (str_equal(q, "strict")) + test_mode = TEST_STRICT; + else if (str_equal(q, "all") || str_equal(q, "both")) + test_mode = TEST_ALL; + else + fatal(2, "unknown test mode: %s", q); + continue; + } + if (str_equal(p, "strict")) { + if (str_equal(q, "skip") || str_equal(q, "no")) + test_mode = TEST_NOSTRICT; + continue; + } + if (str_equal(p, "nostrict")) { + if (str_equal(q, "skip") || str_equal(q, "no")) + test_mode = TEST_STRICT; + continue; + } + if (str_equal(p, "async")) { + skip_async = !str_equal(q, "yes"); + continue; + } + if (str_equal(p, "module")) { + skip_module = !str_equal(q, "yes"); + continue; + } + if (str_equal(p, "verbose")) { + verbose = str_equal(q, "yes"); + continue; + } + if (str_equal(p, "errorfile")) { + error_filename = compose_path(base_name, q); + continue; + } + if (str_equal(p, "excludefile")) { + char *path = compose_path(base_name, q); + namelist_load(&exclude_list, path); + free(path); + continue; + } + if (str_equal(p, "reportfile")) { + report_filename = compose_path(base_name, q); + continue; + } + case SECTION_EXCLUDE: + namelist_add(&exclude_list, base_name, p); + break; + case SECTION_FEATURES: + if (!q || str_equal(q, "yes")) + str_append(&harness_features, " ", p); + else + str_append(&harness_skip_features, " ", p); + break; + case SECTION_TESTS: + namelist_add(&test_list, base_name, p); + break; + default: + /* ignore settings in other sections */ + break; + } + } + fclose(f); + free(base_name); +} + +char *find_error(const char *filename, int *pline, int is_strict) +{ + if (error_file) { + size_t len = strlen(filename); + const char *p, *q, *r; + int line; + + for (p = error_file; (p = strstr(p, filename)) != NULL; p += len) { + if ((p == error_file || p[-1] == '\n' || p[-1] == '(') && p[len] == ':') { + q = p + len; + line = 1; + if (*q == ':') { + line = strtol(q + 1, (char**)&q, 10); + if (*q == ':') + q++; + } + while (*q == ' ') { + q++; + } + /* check strict mode indicator */ + if (!strstart(q, "strict mode: ", &q) != !is_strict) + continue; + r = q = skip_prefix(q, "unexpected error: "); + r += strcspn(r, "\n"); + while (r[0] == '\n' && r[1] && strncmp(r + 1, filename, 8)) { + r++; + r += strcspn(r, "\n"); + } + if (pline) + *pline = line; + return strdup_len(q, r - q); + } + } + } + return NULL; +} + +int skip_comments(const char *str, int line, int *pline) +{ + const char *p; + int c; + + p = str; + while ((c = (unsigned char)*p++) != '\0') { + if (isspace(c)) { + if (c == '\n') + line++; + continue; + } + if (c == '/' && *p == '/') { + while (*++p && *p != '\n') + continue; + continue; + } + if (c == '/' && *p == '*') { + for (p += 1; *p; p++) { + if (*p == '\n') { + line++; + continue; + } + if (*p == '*' && p[1] == '/') { + p += 2; + break; + } + } + continue; + } + break; + } + if (pline) + *pline = line; + + return p - str; +} + +int longest_match(const char *str, const char *find, int pos, int *ppos, int line, int *pline) +{ + int len, maxlen; + + maxlen = 0; + + if (*find) { + const char *p; + for (p = str + pos; *p; p++) { + if (*p == *find) { + for (len = 1; p[len] && p[len] == find[len]; len++) + continue; + if (len > maxlen) { + maxlen = len; + if (ppos) + *ppos = p - str; + if (pline) + *pline = line; + if (!find[len]) + break; + } + } + if (*p == '\n') + line++; + } + } + return maxlen; +} + +static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len, + const char *filename, int is_test, int is_negative, + const char *error_type, FILE *outfile, int eval_flags, + int is_async) +{ + JSValue res_val, exception_val; + int ret, error_line, pos, pos_line; + BOOL is_error, has_error_line, ret_promise; + const char *error_name; + + pos = skip_comments(buf, 1, &pos_line); + error_line = pos_line; + has_error_line = FALSE; + exception_val = JS_UNDEFINED; + error_name = NULL; + + /* a module evaluation returns a promise */ + ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0); + async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */ + + res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); + + if ((is_async || ret_promise) && !JS_IsException(res_val)) { + JSValue promise = JS_UNDEFINED; + if (ret_promise) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } + for(;;) { + JSContext *ctx1; + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (ret < 0) { + res_val = JS_EXCEPTION; + break; + } else if (ret == 0) { + if (is_async) { + /* test if the test called $DONE() once */ + if (async_done != 1) { + res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); + } else { + res_val = JS_UNDEFINED; + } + } else { + /* check that the returned promise is fulfilled */ + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_FULFILLED) + res_val = JS_UNDEFINED; + else if (state == JS_PROMISE_REJECTED) + res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + else + res_val = JS_ThrowTypeError(ctx, "promise is pending"); + } + break; + } + } + JS_FreeValue(ctx, promise); + } + + if (JS_IsException(res_val)) { + exception_val = JS_GetException(ctx); + is_error = JS_IsError(ctx, exception_val); + /* XXX: should get the filename and line number */ + if (outfile) { + if (!is_error) + fprintf(outfile, "%sThrow: ", (eval_flags & JS_EVAL_FLAG_STRICT) ? + "strict mode: " : ""); + js_print(ctx, JS_NULL, 1, &exception_val); + } + if (is_error) { + JSValue name, stack; + const char *stack_str; + + name = JS_GetPropertyStr(ctx, exception_val, "name"); + error_name = JS_ToCString(ctx, name); + stack = JS_GetPropertyStr(ctx, exception_val, "stack"); + if (!JS_IsUndefined(stack)) { + stack_str = JS_ToCString(ctx, stack); + if (stack_str) { + const char *p; + int len; + + if (outfile) + fprintf(outfile, "%s", stack_str); + + len = strlen(filename); + p = strstr(stack_str, filename); + if (p != NULL && p[len] == ':') { + error_line = atoi(p + len + 1); + has_error_line = TRUE; + } + JS_FreeCString(ctx, stack_str); + } + } + JS_FreeValue(ctx, stack); + JS_FreeValue(ctx, name); + } + if (is_negative) { + ret = 0; + if (error_type) { + char *error_class; + const char *msg; + + msg = JS_ToCString(ctx, exception_val); + error_class = strdup_len(msg, strcspn(msg, ":")); + if (!str_equal(error_class, error_type)) + ret = -1; + free(error_class); + JS_FreeCString(ctx, msg); + } + } else { + ret = -1; + } + } else { + if (is_negative) + ret = -1; + else + ret = 0; + } + + if (verbose && is_test) { + JSValue msg_val = JS_UNDEFINED; + const char *msg = NULL; + int s_line; + char *s = find_error(filename, &s_line, eval_flags & JS_EVAL_FLAG_STRICT); + const char *strict_mode = (eval_flags & JS_EVAL_FLAG_STRICT) ? "strict mode: " : ""; + + if (!JS_IsUndefined(exception_val)) { + msg_val = JS_ToString(ctx, exception_val); + msg = JS_ToCString(ctx, msg_val); + } + if (is_negative) { // expect error + if (ret == 0) { + if (msg && s && + (str_equal(s, "expected error") || + strstart(s, "unexpected error type:", NULL) || + str_equal(s, msg))) { // did not have error yet + if (!has_error_line) { + longest_match(buf, msg, pos, &pos, pos_line, &error_line); + } + printf("%s:%d: %sOK, now has error %s\n", + filename, error_line, strict_mode, msg); + fixed_errors++; + } + } else { + if (!s) { // not yet reported + if (msg) { + fprintf(error_out, "%s:%d: %sunexpected error type: %s\n", + filename, error_line, strict_mode, msg); + } else { + fprintf(error_out, "%s:%d: %sexpected error\n", + filename, error_line, strict_mode); + } + new_errors++; + } + } + } else { // should not have error + if (msg) { + if (!s || !str_equal(s, msg)) { + if (!has_error_line) { + char *p = skip_prefix(msg, "Test262 Error: "); + if (strstr(p, "Test case returned non-true value!")) { + longest_match(buf, "runTestCase", pos, &pos, pos_line, &error_line); + } else { + longest_match(buf, p, pos, &pos, pos_line, &error_line); + } + } + fprintf(error_out, "%s:%d: %s%s%s\n", filename, error_line, strict_mode, + error_file ? "unexpected error: " : "", msg); + + if (s && (!str_equal(s, msg) || error_line != s_line)) { + printf("%s:%d: %sprevious error: %s\n", filename, s_line, strict_mode, s); + changed_errors++; + } else { + new_errors++; + } + } + } else { + if (s) { + printf("%s:%d: %sOK, fixed error: %s\n", filename, s_line, strict_mode, s); + fixed_errors++; + } + } + } + JS_FreeValue(ctx, msg_val); + JS_FreeCString(ctx, msg); + free(s); + } + JS_FreeCString(ctx, error_name); + JS_FreeValue(ctx, exception_val); + JS_FreeValue(ctx, res_val); + return ret; +} + +static int eval_file(JSContext *ctx, const char *base, const char *p, + int eval_flags) +{ + char *buf; + size_t buf_len; + char *filename = compose_path(base, p); + + buf = load_file(filename, &buf_len); + if (!buf) { + warning("cannot load %s", filename); + goto fail; + } + if (eval_buf(ctx, buf, buf_len, filename, FALSE, FALSE, NULL, stderr, + eval_flags, FALSE)) { + warning("error evaluating %s", filename); + goto fail; + } + free(buf); + free(filename); + return 0; + +fail: + free(buf); + free(filename); + return 1; +} + +char *extract_desc(const char *buf, char style) +{ + const char *p, *desc_start; + char *desc; + int len; + + p = buf; + while (*p != '\0') { + if (p[0] == '/' && p[1] == '*' && p[2] == style && p[3] != '/') { + p += 3; + desc_start = p; + while (*p != '\0' && (p[0] != '*' || p[1] != '/')) + p++; + if (*p == '\0') { + warning("Expecting end of desc comment"); + return NULL; + } + len = p - desc_start; + desc = malloc(len + 1); + memcpy(desc, desc_start, len); + desc[len] = '\0'; + return desc; + } else { + p++; + } + } + return NULL; +} + +static char *find_tag(char *desc, const char *tag, int *state) +{ + char *p; + p = strstr(desc, tag); + if (p) { + p += strlen(tag); + *state = 0; + } + return p; +} + +static char *get_option(char **pp, int *state) +{ + char *p, *p0, *option = NULL; + if (*pp) { + for (p = *pp;; p++) { + switch (*p) { + case '[': + *state += 1; + continue; + case ']': + *state -= 1; + if (*state > 0) + continue; + p = NULL; + break; + case ' ': + case '\t': + case '\r': + case ',': + case '-': + continue; + case '\n': + if (*state > 0 || p[1] == ' ') + continue; + p = NULL; + break; + case '\0': + p = NULL; + break; + default: + p0 = p; + p += strcspn(p0, " \t\r\n,]"); + option = strdup_len(p0, p - p0); + break; + } + break; + } + *pp = p; + } + return option; +} + +void update_stats(JSRuntime *rt, const char *filename) { + JSMemoryUsage stats; + JS_ComputeMemoryUsage(rt, &stats); + if (stats_count++ == 0) { + stats_avg = stats_all = stats_min = stats_max = stats; + stats_min_filename = strdup(filename); + stats_max_filename = strdup(filename); + } else { + if (stats_max.malloc_size < stats.malloc_size) { + stats_max = stats; + free(stats_max_filename); + stats_max_filename = strdup(filename); + } + if (stats_min.malloc_size > stats.malloc_size) { + stats_min = stats; + free(stats_min_filename); + stats_min_filename = strdup(filename); + } + +#define update(f) stats_avg.f = (stats_all.f += stats.f) / stats_count + update(malloc_count); + update(malloc_size); + update(memory_used_count); + update(memory_used_size); + update(atom_count); + update(atom_size); + update(str_count); + update(str_size); + update(obj_count); + update(obj_size); + update(prop_count); + update(prop_size); + update(shape_count); + update(shape_size); + update(js_func_count); + update(js_func_size); + update(js_func_code_size); + update(js_func_pc2line_count); + update(js_func_pc2line_size); + update(c_func_count); + update(array_count); + update(fast_array_count); + update(fast_array_elements); + } +#undef update +} + +int run_test_buf(const char *filename, const char *harness, namelist_t *ip, + char *buf, size_t buf_len, const char* error_type, + int eval_flags, BOOL is_negative, BOOL is_async, + BOOL can_block) +{ + JSRuntime *rt; + JSContext *ctx; + int i, ret; + + rt = JS_NewRuntime(); + if (rt == NULL) { + fatal(1, "JS_NewRuntime failure"); + } + ctx = JS_NewContext(rt); + if (ctx == NULL) { + JS_FreeRuntime(rt); + fatal(1, "JS_NewContext failure"); + } + JS_SetRuntimeInfo(rt, filename); + + JS_SetCanBlock(rt, can_block); + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); + + add_helpers(ctx); + + for (i = 0; i < ip->count; i++) { + if (eval_file(ctx, harness, ip->array[i], + JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRIP)) { + fatal(1, "error including %s for %s", ip->array[i], filename); + } + } + + ret = eval_buf(ctx, buf, buf_len, filename, TRUE, is_negative, + error_type, outfile, eval_flags, is_async); + ret = (ret != 0); + + if (dump_memory) { + update_stats(rt, filename); + } +#ifdef CONFIG_AGENT + js_agent_free(ctx); +#endif + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + + test_count++; + if (ret) { + test_failed++; + if (outfile) { + /* do not output a failure number to minimize diff */ + fprintf(outfile, " FAILED\n"); + } + } + return ret; +} + +int run_test(const char *filename, int index) +{ + char harnessbuf[1024]; + char *harness; + char *buf; + size_t buf_len; + char *desc, *p; + char *error_type; + int ret, eval_flags, use_strict, use_nostrict; + BOOL is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip; + BOOL can_block; + namelist_t include_list = { 0 }, *ip = &include_list; + + is_nostrict = is_onlystrict = is_negative = is_async = is_module = skip = FALSE; + can_block = TRUE; + error_type = NULL; + buf = load_file(filename, &buf_len); + + harness = harness_dir; + + if (new_style) { + if (!harness) { + p = strstr(filename, "test/"); + if (p) { + snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", + (int)(p - filename), filename, "harness"); + } else { + pstrcpy(harnessbuf, sizeof(harnessbuf), ""); + } + harness = harnessbuf; + } + namelist_add(ip, NULL, "sta.js"); + namelist_add(ip, NULL, "assert.js"); + /* extract the YAML frontmatter */ + desc = extract_desc(buf, '-'); + if (desc) { + char *ifile, *option; + int state; + p = find_tag(desc, "includes:", &state); + if (p) { + while ((ifile = get_option(&p, &state)) != NULL) { + // skip unsupported harness files + if (find_word(harness_exclude, ifile)) { + skip |= 1; + } else { + namelist_add(ip, NULL, ifile); + } + free(ifile); + } + } + p = find_tag(desc, "flags:", &state); + if (p) { + while ((option = get_option(&p, &state)) != NULL) { + if (str_equal(option, "noStrict") || + str_equal(option, "raw")) { + is_nostrict = TRUE; + skip |= (test_mode == TEST_STRICT); + } + else if (str_equal(option, "onlyStrict")) { + is_onlystrict = TRUE; + skip |= (test_mode == TEST_NOSTRICT); + } + else if (str_equal(option, "async")) { + is_async = TRUE; + skip |= skip_async; + } + else if (str_equal(option, "module")) { + is_module = TRUE; + skip |= skip_module; + } + else if (str_equal(option, "CanBlockIsFalse")) { + can_block = FALSE; + } + free(option); + } + } + p = find_tag(desc, "negative:", &state); + if (p) { + /* XXX: should extract the phase */ + char *q = find_tag(p, "type:", &state); + if (q) { + while (isspace(*q)) + q++; + error_type = strdup_len(q, strcspn(q, " \n")); + } + is_negative = TRUE; + } + p = find_tag(desc, "features:", &state); + if (p) { + while ((option = get_option(&p, &state)) != NULL) { + if (find_word(harness_features, option)) { + /* feature is enabled */ + } else if (find_word(harness_skip_features, option)) { + /* skip disabled feature */ + skip |= 1; + } else { + /* feature is not listed: skip and warn */ + printf("%s:%d: unknown feature: %s\n", filename, 1, option); + skip |= 1; + } + free(option); + } + } + free(desc); + } + if (is_async) + namelist_add(ip, NULL, "doneprintHandle.js"); + } else { + char *ifile; + + if (!harness) { + p = strstr(filename, "test/"); + if (p) { + snprintf(harnessbuf, sizeof(harnessbuf), "%.*s%s", + (int)(p - filename), filename, "test/harness"); + } else { + pstrcpy(harnessbuf, sizeof(harnessbuf), ""); + } + harness = harnessbuf; + } + + namelist_add(ip, NULL, "sta.js"); + + /* include extra harness files */ + for (p = buf; (p = strstr(p, "$INCLUDE(\"")) != NULL; p++) { + p += 10; + ifile = strdup_len(p, strcspn(p, "\"")); + // skip unsupported harness files + if (find_word(harness_exclude, ifile)) { + skip |= 1; + } else { + namelist_add(ip, NULL, ifile); + } + free(ifile); + } + + /* locate the old style configuration comment */ + desc = extract_desc(buf, '*'); + if (desc) { + if (strstr(desc, "@noStrict")) { + is_nostrict = TRUE; + skip |= (test_mode == TEST_STRICT); + } + if (strstr(desc, "@onlyStrict")) { + is_onlystrict = TRUE; + skip |= (test_mode == TEST_NOSTRICT); + } + if (strstr(desc, "@negative")) { + /* XXX: should extract the regex to check error type */ + is_negative = TRUE; + } + free(desc); + } + } + + if (outfile && index >= 0) { + fprintf(outfile, "%d: %s%s%s%s%s%s%s\n", index, filename, + is_nostrict ? " @noStrict" : "", + is_onlystrict ? " @onlyStrict" : "", + is_async ? " async" : "", + is_module ? " module" : "", + is_negative ? " @negative" : "", + skip ? " SKIPPED" : ""); + fflush(outfile); + } + + use_strict = use_nostrict = 0; + /* XXX: should remove 'test_mode' or simplify it just to force + strict or non strict mode for single file tests */ + switch (test_mode) { + case TEST_DEFAULT_NOSTRICT: + if (is_onlystrict) + use_strict = 1; + else + use_nostrict = 1; + break; + case TEST_DEFAULT_STRICT: + if (is_nostrict) + use_nostrict = 1; + else + use_strict = 1; + break; + case TEST_NOSTRICT: + if (!is_onlystrict) + use_nostrict = 1; + break; + case TEST_STRICT: + if (!is_nostrict) + use_strict = 1; + break; + case TEST_ALL: + if (is_module) { + use_nostrict = 1; + } else { + if (!is_nostrict) + use_strict = 1; + if (!is_onlystrict) + use_nostrict = 1; + } + break; + } + + if (skip || use_strict + use_nostrict == 0) { + test_skipped++; + ret = -2; + } else { + clock_t clocks; + + if (is_module) { + eval_flags = JS_EVAL_TYPE_MODULE; + } else { + eval_flags = JS_EVAL_TYPE_GLOBAL; + } + clocks = clock(); + ret = 0; + if (use_nostrict) { + ret = run_test_buf(filename, harness, ip, buf, buf_len, + error_type, eval_flags, is_negative, is_async, + can_block); + } + if (use_strict) { + ret |= run_test_buf(filename, harness, ip, buf, buf_len, + error_type, eval_flags | JS_EVAL_FLAG_STRICT, + is_negative, is_async, can_block); + } + clocks = clock() - clocks; + if (outfile && index >= 0 && clocks >= CLOCKS_PER_SEC / 10) { + /* output timings for tests that take more than 100 ms */ + fprintf(outfile, " time: %d ms\n", (int)(clocks * 1000LL / CLOCKS_PER_SEC)); + } + } + namelist_free(&include_list); + free(error_type); + free(buf); + + return ret; +} + +/* run a test when called by test262-harness+eshost */ +int run_test262_harness_test(const char *filename, BOOL is_module) +{ + JSRuntime *rt; + JSContext *ctx; + char *buf; + size_t buf_len; + int eval_flags, ret_code, ret; + JSValue res_val; + BOOL can_block; + + outfile = stdout; /* for js_print */ + + rt = JS_NewRuntime(); + if (rt == NULL) { + fatal(1, "JS_NewRuntime failure"); + } + ctx = JS_NewContext(rt); + if (ctx == NULL) { + JS_FreeRuntime(rt); + fatal(1, "JS_NewContext failure"); + } + JS_SetRuntimeInfo(rt, filename); + + can_block = TRUE; + JS_SetCanBlock(rt, can_block); + + /* loader for ES6 modules */ + JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); + + add_helpers(ctx); + + buf = load_file(filename, &buf_len); + + if (is_module) { + eval_flags = JS_EVAL_TYPE_MODULE; + } else { + eval_flags = JS_EVAL_TYPE_GLOBAL; + } + res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); + ret_code = 0; + if (JS_IsException(res_val)) { + js_std_dump_error(ctx); + ret_code = 1; + } else { + JSValue promise = JS_UNDEFINED; + if (is_module) { + promise = res_val; + } else { + JS_FreeValue(ctx, res_val); + } + for(;;) { + JSContext *ctx1; + ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); + if (ret < 0) { + js_std_dump_error(ctx1); + ret_code = 1; + } else if (ret == 0) { + break; + } + } + /* dump the error if the module returned an error. */ + if (is_module) { + JSPromiseStateEnum state = JS_PromiseState(ctx, promise); + if (state == JS_PROMISE_REJECTED) { + JS_Throw(ctx, JS_PromiseResult(ctx, promise)); + js_std_dump_error(ctx); + ret_code = 1; + } + } + JS_FreeValue(ctx, promise); + } + free(buf); +#ifdef CONFIG_AGENT + js_agent_free(ctx); +#endif + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + return ret_code; +} + +clock_t last_clock; + +void show_progress(int force) { + clock_t t = clock(); + if (force || !last_clock || (t - last_clock) > CLOCKS_PER_SEC / 20) { + last_clock = t; + /* output progress indicator: erase end of line and return to col 0 */ + fprintf(stderr, "%d/%d/%d\033[K\r", + test_failed, test_count, test_skipped); + fflush(stderr); + } +} + +static int slow_test_threshold; + +void run_test_dir_list(namelist_t *lp, int start_index, int stop_index) +{ + int i; + + namelist_sort(lp); + for (i = 0; i < lp->count; i++) { + const char *p = lp->array[i]; + if (namelist_find(&exclude_list, p) >= 0) { + test_excluded++; + } else if (test_index < start_index) { + test_skipped++; + } else if (stop_index >= 0 && test_index > stop_index) { + test_skipped++; + } else { + int ti; + if (slow_test_threshold != 0) { + ti = get_clock_ms(); + } else { + ti = 0; + } + run_test(p, test_index); + if (slow_test_threshold != 0) { + ti = get_clock_ms() - ti; + if (ti >= slow_test_threshold) + fprintf(stderr, "\n%s (%d ms)\n", p, ti); + } + show_progress(FALSE); + } + test_index++; + } + show_progress(TRUE); +} + +void help(void) +{ + printf("run-test262 version " CONFIG_VERSION "\n" + "usage: run-test262 [options] {-f file ... | [dir_list] [index range]}\n" + "-h help\n" + "-a run tests in strict and nostrict modes\n" + "-m print memory usage summary\n" + "-n use new style harness\n" + "-N run test prepared by test262-harness+eshost\n" + "-s run tests in strict mode, skip @nostrict tests\n" + "-E only run tests from the error file\n" + "-u update error file\n" + "-v verbose: output error messages\n" + "-T duration display tests taking more than 'duration' ms\n" + "-c file read configuration from 'file'\n" + "-d dir run all test files in directory tree 'dir'\n" + "-e file load the known errors from 'file'\n" + "-f file execute single test from 'file'\n" + "-r file set the report file name (default=none)\n" + "-x file exclude tests listed in 'file'\n"); + exit(1); +} + +char *get_opt_arg(const char *option, char *arg) +{ + if (!arg) { + fatal(2, "missing argument for option %s", option); + } + return arg; +} + +int main(int argc, char **argv) +{ + int optind, start_index, stop_index; + BOOL is_dir_list; + BOOL only_check_errors = FALSE; + const char *filename; + BOOL is_test262_harness = FALSE; + BOOL is_module = FALSE; + +#if !defined(_WIN32) + /* Date tests assume California local time */ + setenv("TZ", "America/Los_Angeles", 1); +#endif + + /* cannot use getopt because we want to pass the command line to + the script */ + optind = 1; + is_dir_list = TRUE; + while (optind < argc) { + char *arg = argv[optind]; + if (*arg != '-') + break; + optind++; + if (str_equal(arg, "-h")) { + help(); + } else if (str_equal(arg, "-m")) { + dump_memory++; + } else if (str_equal(arg, "-n")) { + new_style++; + } else if (str_equal(arg, "-s")) { + test_mode = TEST_STRICT; + } else if (str_equal(arg, "-a")) { + test_mode = TEST_ALL; + } else if (str_equal(arg, "-u")) { + update_errors++; + } else if (str_equal(arg, "-v")) { + verbose++; + } else if (str_equal(arg, "-c")) { + load_config(get_opt_arg(arg, argv[optind++])); + } else if (str_equal(arg, "-d")) { + enumerate_tests(get_opt_arg(arg, argv[optind++])); + } else if (str_equal(arg, "-e")) { + error_filename = get_opt_arg(arg, argv[optind++]); + } else if (str_equal(arg, "-x")) { + namelist_load(&exclude_list, get_opt_arg(arg, argv[optind++])); + } else if (str_equal(arg, "-f")) { + is_dir_list = FALSE; + } else if (str_equal(arg, "-r")) { + report_filename = get_opt_arg(arg, argv[optind++]); + } else if (str_equal(arg, "-E")) { + only_check_errors = TRUE; + } else if (str_equal(arg, "-T")) { + slow_test_threshold = atoi(get_opt_arg(arg, argv[optind++])); + } else if (str_equal(arg, "-N")) { + is_test262_harness = TRUE; + } else if (str_equal(arg, "--module")) { + is_module = TRUE; + } else { + fatal(1, "unknown option: %s", arg); + break; + } + } + + if (optind >= argc && !test_list.count) + help(); + + if (is_test262_harness) { + return run_test262_harness_test(argv[optind], is_module); + } + + error_out = stdout; + if (error_filename) { + error_file = load_file(error_filename, NULL); + if (only_check_errors && error_file) { + namelist_free(&test_list); + namelist_add_from_error_file(&test_list, error_file); + } + if (update_errors) { + free(error_file); + error_file = NULL; + error_out = fopen(error_filename, "w"); + if (!error_out) { + perror_exit(1, error_filename); + } + } + } + + update_exclude_dirs(); + + if (is_dir_list) { + if (optind < argc && !isdigit(argv[optind][0])) { + filename = argv[optind++]; + namelist_load(&test_list, filename); + } + start_index = 0; + stop_index = -1; + if (optind < argc) { + start_index = atoi(argv[optind++]); + if (optind < argc) { + stop_index = atoi(argv[optind++]); + } + } + if (!report_filename || str_equal(report_filename, "none")) { + outfile = NULL; + } else if (str_equal(report_filename, "-")) { + outfile = stdout; + } else { + outfile = fopen(report_filename, "wb"); + if (!outfile) { + perror_exit(1, report_filename); + } + } + run_test_dir_list(&test_list, start_index, stop_index); + + if (outfile && outfile != stdout) { + fclose(outfile); + outfile = NULL; + } + } else { + outfile = stdout; + while (optind < argc) { + run_test(argv[optind++], -1); + } + } + + if (dump_memory) { + if (dump_memory > 1 && stats_count > 1) { + printf("\nMininum memory statistics for %s:\n\n", stats_min_filename); + JS_DumpMemoryUsage(stdout, &stats_min, NULL); + printf("\nMaximum memory statistics for %s:\n\n", stats_max_filename); + JS_DumpMemoryUsage(stdout, &stats_max, NULL); + } + printf("\nAverage memory statistics for %d tests:\n\n", stats_count); + JS_DumpMemoryUsage(stdout, &stats_avg, NULL); + printf("\n"); + } + + if (is_dir_list) { + fprintf(stderr, "Result: %d/%d error%s", + test_failed, test_count, test_count != 1 ? "s" : ""); + if (test_excluded) + fprintf(stderr, ", %d excluded", test_excluded); + if (test_skipped) + fprintf(stderr, ", %d skipped", test_skipped); + if (error_file) { + if (new_errors) + fprintf(stderr, ", %d new", new_errors); + if (changed_errors) + fprintf(stderr, ", %d changed", changed_errors); + if (fixed_errors) + fprintf(stderr, ", %d fixed", fixed_errors); + } + fprintf(stderr, "\n"); + } + + if (error_out && error_out != stdout) { + fclose(error_out); + error_out = NULL; + } + + namelist_free(&test_list); + namelist_free(&exclude_list); + namelist_free(&exclude_dir_list); + free(harness_dir); + free(harness_features); + free(harness_exclude); + free(error_file); + + return 0; +} diff --git a/deps/quickjs/test262.conf b/deps/quickjs/test262.conf new file mode 100644 index 0000000..fd9862e --- /dev/null +++ b/deps/quickjs/test262.conf @@ -0,0 +1,227 @@ +[config] +# general settings for test262 ES6 version + +# framework style: old, new +style=new + +# handle tests tagged as [noStrict]: yes, no, skip +nostrict=yes + +# handle tests tagged as [strictOnly]: yes, no, skip +strict=yes + +# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all +mode=default + +# handle tests flagged as [async]: yes, no, skip +# for these, load 'harness/doneprintHandle.js' prior to test +# and expect `print('Test262:AsyncTestComplete')` to be called for +# successful termination +async=yes + +# handle tests flagged as [module]: yes, no, skip +module=yes + +# output error messages: yes, no +verbose=yes + +# load harness files from this directory +harnessdir=test262/harness + +# names of harness include files to skip +#harnessexclude= + +# name of the error file for known errors +errorfile=test262_errors.txt + +# exclude tests enumerated in this file (see also [exclude] section) +#excludefile=test262_exclude.txt + +# report test results to this file +reportfile=test262_report.txt + +# enumerate tests from this directory +testdir=test262/test + +[features] +# Standard language features and proposed extensions +# list the features that are included +# skipped features are tagged as such to avoid warnings +# Keep this list alpha-sorted (:sort i in vim) + +__getter__ +__proto__ +__setter__ +AggregateError +align-detached-buffer-semantics-with-web-reality +arbitrary-module-namespace-names=skip +array-find-from-last +array-grouping +Array.fromAsync=skip +Array.prototype.at +Array.prototype.flat +Array.prototype.flatMap +Array.prototype.flatten +Array.prototype.includes +Array.prototype.values +ArrayBuffer +arraybuffer-transfer=skip +arrow-function +async-functions +async-iteration +Atomics +Atomics.waitAsync=skip +BigInt +caller +change-array-by-copy +class +class-fields-private +class-fields-private-in +class-fields-public +class-methods-private +class-static-block +class-static-fields-private +class-static-fields-public +class-static-methods-private +cleanupSome=skip +coalesce-expression +computed-property-names +const +cross-realm +DataView +DataView.prototype.getFloat32 +DataView.prototype.getFloat64 +DataView.prototype.getInt16 +DataView.prototype.getInt32 +DataView.prototype.getInt8 +DataView.prototype.getUint16 +DataView.prototype.getUint32 +DataView.prototype.setUint8 +decorators=skip +default-parameters +destructuring-assignment +destructuring-binding +dynamic-import +error-cause +exponentiation +export-star-as-namespace-from-module +FinalizationGroup=skip +FinalizationRegistry.prototype.cleanupSome=skip +FinalizationRegistry=skip +Float32Array +Float64Array +for-in-order +for-of +generators +globalThis +hashbang +host-gc-required=skip +import-assertions=skip +import-attributes=skip +import.meta +Int16Array +Int32Array +Int8Array +IsHTMLDDA +iterator-helpers=skip +json-modules=skip +json-parse-with-source=skip +json-superset +legacy-regexp=skip +let +logical-assignment-operators +Map +new.target +numeric-separator-literal +object-rest +object-spread +Object.fromEntries +Object.hasOwn +Object.is +optional-catch-binding +optional-chaining +Promise +promise-with-resolvers +Promise.allSettled +Promise.any +Promise.prototype.finally +Proxy +proxy-missing-checks +Reflect +Reflect.construct +Reflect.set +Reflect.setPrototypeOf +regexp-dotall +regexp-duplicate-named-groups=skip +regexp-lookbehind +regexp-match-indices +regexp-named-groups +regexp-unicode-property-escapes +regexp-v-flag=skip +resizable-arraybuffer=skip +rest-parameters +Set +set-methods=skip +ShadowRealm=skip +SharedArrayBuffer +string-trimming +String.fromCodePoint +String.prototype.at +String.prototype.endsWith +String.prototype.includes +String.prototype.isWellFormed +String.prototype.matchAll +String.prototype.replaceAll +String.prototype.toWellFormed +String.prototype.trimEnd +String.prototype.trimStart +super +Symbol +Symbol.asyncIterator +Symbol.hasInstance +Symbol.isConcatSpreadable +Symbol.iterator +Symbol.match +Symbol.matchAll +Symbol.prototype.description +Symbol.replace +Symbol.search +Symbol.species +Symbol.split +Symbol.toPrimitive +Symbol.toStringTag +Symbol.unscopables +symbols-as-weakmap-keys=skip +tail-call-optimization=skip +template +Temporal=skip +top-level-await +TypedArray +TypedArray.prototype.at +u180e +Uint16Array +Uint32Array +Uint8Array +Uint8ClampedArray +WeakMap +WeakRef=skip +WeakSet +well-formed-json-stringify + +[exclude] +# list excluded tests and directories here + +# intl not supported +test262/test/intl402/ + +# incompatible with the "caller" feature +test262/test/built-ins/Function/prototype/restricted-property-caller.js +test262/test/built-ins/Function/prototype/restricted-property-arguments.js +test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js + +# slow tests +#test262/test/built-ins/RegExp/CharacterClassEscapes/ +#test262/test/built-ins/RegExp/property-escapes/ + +[tests] +# list test files or use config.testdir diff --git a/deps/quickjs/test262_errors.txt b/deps/quickjs/test262_errors.txt new file mode 100644 index 0000000..edf5372 --- /dev/null +++ b/deps/quickjs/test262_errors.txt @@ -0,0 +1,8 @@ +test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all +test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError +test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated. +test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all diff --git a/deps/quickjs/test262o.conf b/deps/quickjs/test262o.conf new file mode 100644 index 0000000..669dead --- /dev/null +++ b/deps/quickjs/test262o.conf @@ -0,0 +1,410 @@ +[config] +# general settings for test262 ES5 version + +# framework style: old, new +style=old + +# handle tests tagged as @noStrict: yes, no, skip +nostrict=yes + +# handle tests tagged as @strictOnly: yes, no, skip +strict=yes + +# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all +mode=default + +# output error messages: yes, no +verbose=yes + +# load harness files this directory +harnessdir=test262o/test/harness + +# name of the error file for known errors +errorfile=test262o_errors.txt + +# exclude tests enumerated in this file +#excludefile=test262o_excluded.txt + +# report test results to this file +reportfile=test262o_report.txt + +# enumerate tests from this directory +testdir=test262o/test/suite + +[exclude] +# list excluded tests and directories here + +# intl not supported +test262o/test/suite/intl402/ + +# ES6 != ES5: block scoped function definitions allowed in strict mode +test262o/test/suite/bestPractice/Sbp_A1_T1.js +test262o/test/suite/bestPractice/Sbp_A2_T1.js +test262o/test/suite/bestPractice/Sbp_A2_T2.js +test262o/test/suite/bestPractice/Sbp_A3_T1.js +test262o/test/suite/bestPractice/Sbp_A3_T2.js +test262o/test/suite/bestPractice/Sbp_A4_T1.js +test262o/test/suite/bestPractice/Sbp_A4_T2.js +test262o/test/suite/bestPractice/Sbp_A5_T2.js + +# ES6 != ES5: `y={x};` is shorthand for `y={x:x}` +test262o/test/suite/ch12/12.1/S12.1_A4_T2.js +test262o/test/suite/ch12/12.6/12.6.4/S12.6.4_A15.js + +# ES6 != ES5: function length property is configurable +test262o/test/suite/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js +test262o/test/suite/ch13/13.2/13.2-15-1.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2.js +test262o/test/suite/ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2.js +test262o/test/suite/ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2.js +test262o/test/suite/ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2.js +test262o/test/suite/ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js +test262o/test/suite/ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js +test262o/test/suite/ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js +test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T1.js +test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T2.js +test262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T3.js +test262o/test/suite/ch15/15.4/15.4.3/S15.4.3_A2.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9.js +test262o/test/suite/ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2.js +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2.js +test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9.js +test262o/test/suite/ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9.js +test262o/test/suite/ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9.js + +# ES6 != ES5: object literals may have duplicates +test262o/test/suite/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js +test262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js + +# ES6 != ES5: Date.prototype is no longer an instance of Date +test262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/15.9.5.40_1.js + +# ES6 != ES5: Object.getPrototypeOf converts argument to object +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1.js + +# ES6 != ES5: Object.getPrototypeOf(NativeError) +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js + +# ES6 != ES5: Object.getOwnPropertyDescriptor converts argument to object +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js + +# ES6 != ES5: Object.getOwnPropertyNames converts argument to object +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js + +# ES6 != ES5: Object.seal accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js + +# ES6 != ES5: Object.freeze accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js + +# ES6 != ES5: Object.preventExtensions accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js + +# ES6 != ES5: Object.isSealed accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js + +# ES6 != ES5: Object.isFrozen accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js + +# ES6 != ES5: Object.isExtensible accepts all types +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js + +# ES6 != ES5: Object.keys converts argument to object +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js + +# ES6 != ES5: source and other properties of RegExp.prototype are not own properties +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214.js +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215.js + +# ES6 != ES5: String numeric object properties are enumerated first +test262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-44.js + +# ES6: new RegExp(regex, flags) is valid +test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js +test262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T2.js +test262o/test/suite/ch15/15.10/15.10.4/15.10.4.1/15.10.4.1-1.js +test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T1.js +test262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T2.js + +# ES6 != ES5: RegExp.prototype.test behavior +test262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A5_T3.js + +# ES6 != ES5: source, global, ignoreCase, multiline, lastIndex are not data properties +# of RegExp objects and RegExp.prototype is not a RegExp object +test262o/test/suite/ch15/15.10/15.10.6/15.10.6.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-1.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-2.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A8.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A9.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A10.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-1.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-2.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A8.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A9.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A10.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-1.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-2.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A8.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A9.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A10.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-1.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-2.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A8.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A9.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A10.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-1.js +test262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-2.js + +# ES6 != ES5: Error.prototype is a normal object +test262o/test/suite/ch15/15.11/15.11.4/S15.11.4_A2.js + +# ES6 different ToLength() semantics +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A4_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A2_T2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T1.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A2_T2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T1.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A3_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A3_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T1.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A4_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T1.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T3.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A3_T2.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-8.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-28.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-29.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-28.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-8.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-29.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-8.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-28.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-29.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-8.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-28.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-29.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-25.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-7.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-12.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-25.js + +# ES6 different ToLength() semantics causes near infinite runtime +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js +test262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js + +# ES6 arguments/caller changes +test262o/test/suite/ch10/10.6/10.6-13-b-1-s.js +test262o/test/suite/ch10/10.6/10.6-13-b-2-s.js +test262o/test/suite/ch10/10.6/10.6-13-b-3-s.js +test262o/test/suite/ch10/10.6/10.6-14-1-s.js +test262o/test/suite/ch10/10.6/10.6-14-b-1-s.js +test262o/test/suite/ch10/10.6/10.6-14-b-4-s.js +test262o/test/suite/ch13/13.2/13.2-29-s.js +test262o/test/suite/ch13/13.2/13.2-30-s.js +test262o/test/suite/ch13/13.2/13.2-31-s.js +test262o/test/suite/ch13/13.2/13.2-32-s.js +test262o/test/suite/ch13/13.2/13.2-33-s.js +test262o/test/suite/ch13/13.2/13.2-34-s.js +test262o/test/suite/ch13/13.2/13.2-35-s.js +test262o/test/suite/ch13/13.2/13.2-36-s.js +test262o/test/suite/ch13/13.2/S13.2.3_A1.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js +test262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js + +# u180e is no longer considered as a space +test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A2.js +test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T1.js +test262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T2.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A2_T10.js +test262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A2_T10.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-2.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-3.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-4.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-5.js +test262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-6.js +test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A1_T1.js +test262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A2_T1.js + +# E6 eval return value is different +test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.js +test262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.1.js + +# ECMA 2019 optional-catch-binding feature allows try{}catch{} +test262o/test/suite/ch12/12.14/S12.14_A16_T4.js + +# Syntax error instead of ReferenceError in ES2020 +test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-1.js +test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-2.js +test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-3.js +test262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-4.js + +[tests] +# list test files or use config.testdir diff --git a/build/.gitkeep b/deps/quickjs/test262o_errors.txt similarity index 100% rename from build/.gitkeep rename to deps/quickjs/test262o_errors.txt diff --git a/deps/quickjs/tests/bjson.c b/deps/quickjs/tests/bjson.c new file mode 100644 index 0000000..8e52741 --- /dev/null +++ b/deps/quickjs/tests/bjson.c @@ -0,0 +1,96 @@ +/* + * QuickJS: binary JSON module (test only) + * + * Copyright (c) 2017-2019 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "../quickjs-libc.h" +#include "../cutils.h" + +static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + uint8_t *buf; + uint64_t pos, len; + JSValue obj; + size_t size; + int flags; + + if (JS_ToIndex(ctx, &pos, argv[1])) + return JS_EXCEPTION; + if (JS_ToIndex(ctx, &len, argv[2])) + return JS_EXCEPTION; + buf = JS_GetArrayBuffer(ctx, &size, argv[0]); + if (!buf) + return JS_EXCEPTION; + if (pos + len > size) + return JS_ThrowRangeError(ctx, "array buffer overflow"); + flags = 0; + if (JS_ToBool(ctx, argv[3])) + flags |= JS_READ_OBJ_REFERENCE; + obj = JS_ReadObject(ctx, buf + pos, len, flags); + return obj; +} + +static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + size_t len; + uint8_t *buf; + JSValue array; + int flags; + + flags = 0; + if (JS_ToBool(ctx, argv[1])) + flags |= JS_WRITE_OBJ_REFERENCE; + buf = JS_WriteObject(ctx, &len, argv[0], flags); + if (!buf) + return JS_EXCEPTION; + array = JS_NewArrayBufferCopy(ctx, buf, len); + js_free(ctx, buf); + return array; +} + +static const JSCFunctionListEntry js_bjson_funcs[] = { + JS_CFUNC_DEF("read", 4, js_bjson_read ), + JS_CFUNC_DEF("write", 2, js_bjson_write ), +}; + +static int js_bjson_init(JSContext *ctx, JSModuleDef *m) +{ + return JS_SetModuleExportList(ctx, m, js_bjson_funcs, + countof(js_bjson_funcs)); +} + +#ifdef JS_SHARED_LIBRARY +#define JS_INIT_MODULE js_init_module +#else +#define JS_INIT_MODULE js_init_module_bjson +#endif + +JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) +{ + JSModuleDef *m; + m = JS_NewCModule(ctx, module_name, js_bjson_init); + if (!m) + return NULL; + JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs)); + return m; +} diff --git a/deps/quickjs/tests/microbench.js b/deps/quickjs/tests/microbench.js new file mode 100644 index 0000000..c1b57bb --- /dev/null +++ b/deps/quickjs/tests/microbench.js @@ -0,0 +1,1057 @@ +/* + * Javascript Micro benchmark + * + * Copyright (c) 2017-2019 Fabrice Bellard + * Copyright (c) 2017-2019 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +import * as std from "std"; +import * as os from "os"; + +function pad(str, n) { + str += ""; + while (str.length < n) + str += " "; + return str; +} + +function pad_left(str, n) { + str += ""; + while (str.length < n) + str = " " + str; + return str; +} + +function pad_center(str, n) { + str += ""; + while (str.length < n) { + if ((n - str.length) & 1) + str = str + " "; + else + str = " " + str; + } + return str; +} + +function toPrec(n, prec) { + var i, s; + for (i = 0; i < prec; i++) + n *= 10; + s = "" + Math.round(n); + for (i = s.length - prec; i <= 0; i++) + s = "0" + s; + if (prec > 0) + s = s.substring(0, i) + "." + s.substring(i); + return s; +} + +var ref_data; +var log_data; + +var heads = [ "TEST", "N", "TIME (ns)", "REF (ns)", "SCORE (%)" ]; +var widths = [ 22, 10, 9, 9, 9 ]; +var precs = [ 0, 0, 2, 2, 2 ]; +var total = [ 0, 0, 0, 0, 0 ]; +var total_score = 0; +var total_scale = 0; + +if (typeof console == "undefined") { + var console = { log: print }; +} + +function log_line() { + var i, n, s, a; + s = ""; + for (i = 0, n = arguments.length; i < n; i++) { + if (i > 0) + s += " "; + a = arguments[i]; + if (typeof a == "number") { + total[i] += a; + a = toPrec(a, precs[i]); + s += pad_left(a, widths[i]); + } else { + s += pad_left(a, widths[i]); + } + } + console.log(s); +} + +var clocks_per_sec = 1000; +var max_iterations = 10; +var clock_threshold = 100; /* favoring short measuring spans */ +var min_n_argument = 1; +//var get_clock = Date.now; +var get_clock = os.now; + +function log_one(text, n, ti) { + var ref; + + if (ref_data) + ref = ref_data[text]; + else + ref = null; + + ti = Math.round(ti * 100) / 100; + log_data[text] = ti; + if (typeof ref === "number") { + log_line(text, n, ti, ref, ti * 100 / ref); + total_score += ti * 100 / ref; + total_scale += 100; + } else { + log_line(text, n, ti); + total_score += 100; + total_scale += 100; + } +} + +function bench(f, text) +{ + var i, j, n, t, t1, ti, nb_its, ref, ti_n, ti_n1, min_ti; + + nb_its = n = 1; + if (f.bench) { + ti_n = f(text); + } else { + ti_n = 1000000000; + min_ti = clock_threshold / 10; + for(i = 0; i < 30; i++) { + ti = 1000000000; + for (j = 0; j < max_iterations; j++) { + t = get_clock(); + while ((t1 = get_clock()) == t) + continue; + nb_its = f(n); + if (nb_its < 0) + return; // test failure + t1 = get_clock() - t1; + if (ti > t1) + ti = t1; + } + if (ti >= min_ti) { + ti_n1 = ti / nb_its; + if (ti_n > ti_n1) + ti_n = ti_n1; + } + if (ti >= clock_threshold && n >= min_n_argument) + break; + + n = n * [ 2, 2.5, 2 ][i % 3]; + } + // to use only the best timing from the last loop, uncomment below + //ti_n = ti / nb_its; + } + /* nano seconds per iteration */ + log_one(text, n, ti_n * 1e9 / clocks_per_sec); +} + +var global_res; /* to be sure the code is not optimized */ + +function empty_loop(n) { + var j; + for(j = 0; j < n; j++) { + } + return n; +} + +function date_now(n) { + var j; + for(j = 0; j < n; j++) { + Date.now(); + } + return n; +} + +function prop_read(n) +{ + var obj, sum, j; + obj = {a: 1, b: 2, c:3, d:4 }; + sum = 0; + for(j = 0; j < n; j++) { + sum += obj.a; + sum += obj.b; + sum += obj.c; + sum += obj.d; + } + global_res = sum; + return n * 4; +} + +function prop_write(n) +{ + var obj, j; + obj = {a: 1, b: 2, c:3, d:4 }; + for(j = 0; j < n; j++) { + obj.a = j; + obj.b = j; + obj.c = j; + obj.d = j; + } + return n * 4; +} + +function prop_create(n) +{ + var obj, j; + for(j = 0; j < n; j++) { + obj = new Object(); + obj.a = 1; + obj.b = 2; + obj.c = 3; + obj.d = 4; + } + return n * 4; +} + +function prop_delete(n) +{ + var obj, j; + obj = {}; + for(j = 0; j < n; j++) { + obj[j] = 1; + } + for(j = 0; j < n; j++) { + delete obj[j]; + } + return n; +} + +function array_read(n) +{ + var tab, len, sum, i, j; + tab = []; + len = 10; + for(i = 0; i < len; i++) + tab[i] = i; + sum = 0; + for(j = 0; j < n; j++) { + sum += tab[0]; + sum += tab[1]; + sum += tab[2]; + sum += tab[3]; + sum += tab[4]; + sum += tab[5]; + sum += tab[6]; + sum += tab[7]; + sum += tab[8]; + sum += tab[9]; + } + global_res = sum; + return len * n; +} + +function array_write(n) +{ + var tab, len, i, j; + tab = []; + len = 10; + for(i = 0; i < len; i++) + tab[i] = i; + for(j = 0; j < n; j++) { + tab[0] = j; + tab[1] = j; + tab[2] = j; + tab[3] = j; + tab[4] = j; + tab[5] = j; + tab[6] = j; + tab[7] = j; + tab[8] = j; + tab[9] = j; + } + return len * n; +} + +function array_prop_create(n) +{ + var tab, i, j, len; + len = 1000; + for(j = 0; j < n; j++) { + tab = []; + for(i = 0; i < len; i++) + tab[i] = i; + } + return len * n; +} + +function array_length_decr(n) +{ + var tab, i, j, len; + len = 1000; + tab = []; + for(i = 0; i < len; i++) + tab[i] = i; + for(j = 0; j < n; j++) { + for(i = len - 1; i >= 0; i--) + tab.length = i; + } + return len * n; +} + +function array_hole_length_decr(n) +{ + var tab, i, j, len; + len = 1000; + tab = []; + for(i = 0; i < len; i++) { + if (i != 3) + tab[i] = i; + } + for(j = 0; j < n; j++) { + for(i = len - 1; i >= 0; i--) + tab.length = i; + } + return len * n; +} + +function array_push(n) +{ + var tab, i, j, len; + len = 500; + for(j = 0; j < n; j++) { + tab = []; + for(i = 0; i < len; i++) + tab.push(i); + } + return len * n; +} + +function array_pop(n) +{ + var tab, i, j, len, sum; + len = 500; + for(j = 0; j < n; j++) { + tab = []; + for(i = 0; i < len; i++) + tab[i] = i; + sum = 0; + for(i = 0; i < len; i++) + sum += tab.pop(); + global_res = sum; + } + return len * n; +} + +function typed_array_read(n) +{ + var tab, len, sum, i, j; + len = 10; + tab = new Int32Array(len); + for(i = 0; i < len; i++) + tab[i] = i; + sum = 0; + for(j = 0; j < n; j++) { + sum += tab[0]; + sum += tab[1]; + sum += tab[2]; + sum += tab[3]; + sum += tab[4]; + sum += tab[5]; + sum += tab[6]; + sum += tab[7]; + sum += tab[8]; + sum += tab[9]; + } + global_res = sum; + return len * n; +} + +function typed_array_write(n) +{ + var tab, len, i, j; + len = 10; + tab = new Int32Array(len); + for(i = 0; i < len; i++) + tab[i] = i; + for(j = 0; j < n; j++) { + tab[0] = j; + tab[1] = j; + tab[2] = j; + tab[3] = j; + tab[4] = j; + tab[5] = j; + tab[6] = j; + tab[7] = j; + tab[8] = j; + tab[9] = j; + } + return len * n; +} + +var global_var0; + +function global_read(n) +{ + var sum, j; + global_var0 = 0; + sum = 0; + for(j = 0; j < n; j++) { + sum += global_var0; + sum += global_var0; + sum += global_var0; + sum += global_var0; + } + global_res = sum; + return n * 4; +} + +var global_write = + (1, eval)(`(function global_write(n) + { + var j; + for(j = 0; j < n; j++) { + global_var0 = j; + global_var0 = j; + global_var0 = j; + global_var0 = j; + } + return n * 4; + })`); + +function global_write_strict(n) +{ + var j; + for(j = 0; j < n; j++) { + global_var0 = j; + global_var0 = j; + global_var0 = j; + global_var0 = j; + } + return n * 4; +} + +function local_destruct(n) +{ + var j, v1, v2, v3, v4; + var array = [ 1, 2, 3, 4, 5]; + var o = { a:1, b:2, c:3, d:4 }; + var a, b, c, d; + for(j = 0; j < n; j++) { + [ v1, v2,, v3, ...v4] = array; + ({ a, b, c, d } = o); + ({ a: a, b: b, c: c, d: d } = o); + } + return n * 12; +} + +var global_v1, global_v2, global_v3, global_v4; +var global_a, global_b, global_c, global_d; + +var global_destruct = + (1, eval)(`(function global_destruct(n) + { + var j, v1, v2, v3, v4; + var array = [ 1, 2, 3, 4, 5 ]; + var o = { a:1, b:2, c:3, d:4 }; + var a, b, c, d; + for(j = 0; j < n; j++) { + [ global_v1, global_v2,, global_v3, ...global_v4] = array; + ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); + } + return n * 8; + })`); + +function global_destruct_strict(n) +{ + var j, v1, v2, v3, v4; + var array = [ 1, 2, 3, 4, 5 ]; + var o = { a:1, b:2, c:3, d:4 }; + var a, b, c, d; + for(j = 0; j < n; j++) { + [ global_v1, global_v2,, global_v3, ...global_v4] = array; + ({ a: global_a, b: global_b, c: global_c, d: global_d } = o); + } + return n * 8; +} + +function func_call(n) +{ + function f(a) + { + return 1; + } + + var j, sum; + sum = 0; + for(j = 0; j < n; j++) { + sum += f(j); + sum += f(j); + sum += f(j); + sum += f(j); + } + global_res = sum; + return n * 4; +} + +function closure_var(n) +{ + function f(a) + { + sum++; + } + + var j, sum; + sum = 0; + for(j = 0; j < n; j++) { + f(j); + f(j); + f(j); + f(j); + } + global_res = sum; + return n * 4; +} + +function int_arith(n) +{ + var i, j, sum; + global_res = 0; + for(j = 0; j < n; j++) { + sum = 0; + for(i = 0; i < 1000; i++) { + sum += i * i; + } + global_res += sum; + } + return n * 1000; +} + +function float_arith(n) +{ + var i, j, sum, a, incr, a0; + global_res = 0; + a0 = 0.1; + incr = 1.1; + for(j = 0; j < n; j++) { + sum = 0; + a = a0; + for(i = 0; i < 1000; i++) { + sum += a * a; + a += incr; + } + global_res += sum; + } + return n * 1000; +} + +function bigfloat_arith(n) +{ + var i, j, sum, a, incr, a0; + global_res = 0; + a0 = BigFloat("0.1"); + incr = BigFloat("1.1"); + for(j = 0; j < n; j++) { + sum = 0; + a = a0; + for(i = 0; i < 1000; i++) { + sum += a * a; + a += incr; + } + global_res += sum; + } + return n * 1000; +} + +function float256_arith(n) +{ + return BigFloatEnv.setPrec(bigfloat_arith.bind(null, n), 237, 19); +} + +function bigint_arith(n, bits) +{ + var i, j, sum, a, incr, a0, sum0; + sum0 = global_res = BigInt(0); + a0 = BigInt(1) << BigInt(Math.floor((bits - 10) * 0.5)); + incr = BigInt(1); + for(j = 0; j < n; j++) { + sum = sum0; + a = a0; + for(i = 0; i < 1000; i++) { + sum += a * a; + a += incr; + } + global_res += sum; + } + return n * 1000; +} + +function bigint64_arith(n) +{ + return bigint_arith(n, 64); +} + +function bigint256_arith(n) +{ + return bigint_arith(n, 256); +} + +function set_collection_add(n) +{ + var s, i, j, len = 100; + s = new Set(); + for(j = 0; j < n; j++) { + for(i = 0; i < len; i++) { + s.add(String(i), i); + } + for(i = 0; i < len; i++) { + if (!s.has(String(i))) + throw Error("bug in Set"); + } + } + return n * len; +} + +function array_for(n) +{ + var r, i, j, sum; + r = []; + for(i = 0; i < 100; i++) + r[i] = i; + for(j = 0; j < n; j++) { + sum = 0; + for(i = 0; i < 100; i++) { + sum += r[i]; + } + global_res = sum; + } + return n * 100; +} + +function array_for_in(n) +{ + var r, i, j, sum; + r = []; + for(i = 0; i < 100; i++) + r[i] = i; + for(j = 0; j < n; j++) { + sum = 0; + for(i in r) { + sum += r[i]; + } + global_res = sum; + } + return n * 100; +} + +function array_for_of(n) +{ + var r, i, j, sum; + r = []; + for(i = 0; i < 100; i++) + r[i] = i; + for(j = 0; j < n; j++) { + sum = 0; + for(i of r) { + sum += i; + } + global_res = sum; + } + return n * 100; +} + +function math_min(n) +{ + var i, j, r; + r = 0; + for(j = 0; j < n; j++) { + for(i = 0; i < 1000; i++) + r = Math.min(i, 500); + global_res = r; + } + return n * 1000; +} + +/* incremental string contruction as local var */ +function string_build1(n) +{ + var i, j, r; + r = ""; + for(j = 0; j < n; j++) { + for(i = 0; i < 100; i++) + r += "x"; + global_res = r; + } + return n * 100; +} + +/* incremental string contruction as arg */ +function string_build2(n, r) +{ + var i, j; + r = ""; + for(j = 0; j < n; j++) { + for(i = 0; i < 100; i++) + r += "x"; + global_res = r; + } + return n * 100; +} + +/* incremental string contruction by prepending */ +function string_build3(n, r) +{ + var i, j; + r = ""; + for(j = 0; j < n; j++) { + for(i = 0; i < 100; i++) + r = "x" + r; + global_res = r; + } + return n * 100; +} + +/* incremental string contruction with multiple reference */ +function string_build4(n) +{ + var i, j, r, s; + r = ""; + for(j = 0; j < n; j++) { + for(i = 0; i < 100; i++) { + s = r; + r += "x"; + } + global_res = r; + } + return n * 100; +} + +/* sort bench */ + +function sort_bench(text) { + function random(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[(Math.random() * n) >> 0]; + } + function random8(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[(Math.random() * 256) >> 0]; + } + function random1(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[(Math.random() * 2) >> 0]; + } + function hill(arr, n, def) { + var mid = n >> 1; + for (var i = 0; i < mid; i++) + arr[i] = def[i]; + for (var i = mid; i < n; i++) + arr[i] = def[n - i]; + } + function comb(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[(i & 1) * i]; + } + function crisscross(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[(i & 1) ? n - i : i]; + } + function zero(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[0]; + } + function increasing(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[i]; + } + function decreasing(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[n - 1 - i]; + } + function alternate(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[i ^ 1]; + } + function jigsaw(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[i % (n >> 4)]; + } + function incbutone(arr, n, def) { + for (var i = 0; i < n; i++) + arr[i] = def[i]; + if (n > 0) + arr[n >> 2] = def[n]; + } + function incbutfirst(arr, n, def) { + if (n > 0) + arr[0] = def[n]; + for (var i = 1; i < n; i++) + arr[i] = def[i]; + } + function incbutlast(arr, n, def) { + for (var i = 0; i < n - 1; i++) + arr[i] = def[i + 1]; + if (n > 0) + arr[n - 1] = def[0]; + } + + var sort_cases = [ random, random8, random1, jigsaw, hill, comb, + crisscross, zero, increasing, decreasing, alternate, + incbutone, incbutlast, incbutfirst ]; + + var n = sort_bench.array_size || 10000; + var array_type = sort_bench.array_type || Array; + var def, arr; + var i, j, x, y; + var total = 0; + + var save_total_score = total_score; + var save_total_scale = total_scale; + + // initialize default sorted array (n + 1 elements) + def = new array_type(n + 1); + if (array_type == Array) { + for (i = 0; i <= n; i++) { + def[i] = i + ""; + } + } else { + for (i = 0; i <= n; i++) { + def[i] = i; + } + } + def.sort(); + for (var f of sort_cases) { + var ti = 0, tx = 0; + for (j = 0; j < 100; j++) { + arr = new array_type(n); + f(arr, n, def); + var t1 = get_clock(); + arr.sort(); + t1 = get_clock() - t1; + tx += t1; + if (!ti || ti > t1) + ti = t1; + if (tx >= clocks_per_sec) + break; + } + total += ti; + + i = 0; + x = arr[0]; + if (x !== void 0) { + for (i = 1; i < n; i++) { + y = arr[i]; + if (y === void 0) + break; + if (x > y) + break; + x = y; + } + } + while (i < n && arr[i] === void 0) + i++; + if (i < n) { + console.log("sort_bench: out of order error for " + f.name + + " at offset " + (i - 1) + + ": " + arr[i - 1] + " > " + arr[i]); + } + if (sort_bench.verbose) + log_one("sort_" + f.name, n, ti, n * 100); + } + total_score = save_total_score; + total_scale = save_total_scale; + return total / n / 1000; +} +sort_bench.bench = true; +sort_bench.verbose = false; + +function int_to_string(n) +{ + var s, r, j; + r = 0; + for(j = 0; j < n; j++) { + s = (j + 1).toString(); + } + return n; +} + +function float_to_string(n) +{ + var s, r, j; + r = 0; + for(j = 0; j < n; j++) { + s = (j + 0.1).toString(); + } + return n; +} + +function string_to_int(n) +{ + var s, r, j; + r = 0; + s = "12345"; + r = 0; + for(j = 0; j < n; j++) { + r += (s | 0); + } + global_res = r; + return n; +} + +function string_to_float(n) +{ + var s, r, j; + r = 0; + s = "12345.6"; + r = 0; + for(j = 0; j < n; j++) { + r -= s; + } + global_res = r; + return n; +} + +function load_result(filename) +{ + var f, str, res; + if (typeof std === "undefined") + return null; + f = std.open(filename, "r"); + if (!f) + return null; + str = f.readAsString(); + res = JSON.parse(str); + f.close(); + return res; +} + +function save_result(filename, obj) +{ + var f; + if (typeof std === "undefined") + return; + f = std.open(filename, "w"); + f.puts(JSON.stringify(obj, null, 2)); + f.puts("\n"); + f.close(); +} + +function main(argc, argv, g) +{ + var test_list = [ + empty_loop, + date_now, + prop_read, + prop_write, + prop_create, + prop_delete, + array_read, + array_write, + array_prop_create, + array_length_decr, + array_hole_length_decr, + array_push, + array_pop, + typed_array_read, + typed_array_write, + global_read, + global_write, + global_write_strict, + local_destruct, + global_destruct, + global_destruct_strict, + func_call, + closure_var, + int_arith, + float_arith, + set_collection_add, + array_for, + array_for_in, + array_for_of, + math_min, + string_build1, + string_build2, + //string_build3, + //string_build4, + sort_bench, + int_to_string, + float_to_string, + string_to_int, + string_to_float, + ]; + var tests = []; + var i, j, n, f, name; + + if (typeof BigInt == "function") { + /* BigInt test */ + test_list.push(bigint64_arith); + test_list.push(bigint256_arith); + } + if (typeof BigFloat == "function") { + /* BigFloat test */ + test_list.push(float256_arith); + } + + for (i = 1; i < argc;) { + name = argv[i++]; + if (name == "-a") { + sort_bench.verbose = true; + continue; + } + if (name == "-t") { + name = argv[i++]; + sort_bench.array_type = g[name]; + if (typeof sort_bench.array_type != "function") { + console.log("unknown array type: " + name); + return 1; + } + continue; + } + if (name == "-n") { + sort_bench.array_size = +argv[i++]; + continue; + } + for (j = 0; j < test_list.length; j++) { + f = test_list[j]; + if (name === f.name) { + tests.push(f); + break; + } + } + if (j == test_list.length) { + console.log("unknown benchmark: " + name); + return 1; + } + } + if (tests.length == 0) + tests = test_list; + + ref_data = load_result("microbench.txt"); + log_data = {}; + log_line.apply(null, heads); + n = 0; + + for(i = 0; i < tests.length; i++) { + f = tests[i]; + bench(f, f.name, ref_data, log_data); + if (ref_data && ref_data[f.name]) + n++; + } + if (ref_data) + log_line("total", "", total[2], total[3], total_score * 100 / total_scale); + else + log_line("total", "", total[2]); + + if (tests == test_list) + save_result("microbench-new.txt", log_data); +} + +if (!scriptArgs) + scriptArgs = []; +main(scriptArgs.length, scriptArgs, this); diff --git a/deps/quickjs/tests/test262.patch b/deps/quickjs/tests/test262.patch new file mode 100644 index 0000000..6576bdc --- /dev/null +++ b/deps/quickjs/tests/test262.patch @@ -0,0 +1,71 @@ +diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js +index 9c1217351e..3c24755558 100644 +--- a/harness/atomicsHelper.js ++++ b/harness/atomicsHelper.js +@@ -227,10 +227,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) { + * } + */ + $262.agent.timeouts = { +- yield: 100, +- small: 200, +- long: 1000, +- huge: 10000, ++// yield: 100, ++// small: 200, ++// long: 1000, ++// huge: 10000, ++ yield: 20, ++ small: 20, ++ long: 100, ++ huge: 1000, + }; + + /** +diff --git a/harness/regExpUtils.js b/harness/regExpUtils.js +index be7039fda0..7b38abf8df 100644 +--- a/harness/regExpUtils.js ++++ b/harness/regExpUtils.js +@@ -6,24 +6,27 @@ description: | + defines: [buildString, testPropertyEscapes, matchValidator] + ---*/ + ++if ($262 && typeof $262.codePointRange === "function") { ++ /* use C function to build the codePointRange (much faster with ++ slow JS engines) */ ++ codePointRange = $262.codePointRange; ++} else { ++ codePointRange = function codePointRange(start, end) { ++ const codePoints = []; ++ let length = 0; ++ for (codePoint = start; codePoint < end; codePoint++) { ++ codePoints[length++] = codePoint; ++ } ++ return String.fromCodePoint.apply(null, codePoints); ++ } ++} ++ + function buildString({ loneCodePoints, ranges }) { +- const CHUNK_SIZE = 10000; +- let result = Reflect.apply(String.fromCodePoint, null, loneCodePoints); +- for (let i = 0; i < ranges.length; i++) { +- const range = ranges[i]; +- const start = range[0]; +- const end = range[1]; +- const codePoints = []; +- for (let length = 0, codePoint = start; codePoint <= end; codePoint++) { +- codePoints[length++] = codePoint; +- if (length === CHUNK_SIZE) { +- result += Reflect.apply(String.fromCodePoint, null, codePoints); +- codePoints.length = length = 0; +- } ++ let result = String.fromCodePoint.apply(null, loneCodePoints); ++ for (const [start, end] of ranges) { ++ result += codePointRange(start, end + 1); + } +- result += Reflect.apply(String.fromCodePoint, null, codePoints); +- } +- return result; ++ return result; + } + + function testPropertyEscapes(regex, string, expression) { diff --git a/deps/quickjs/tests/test_bignum.js b/deps/quickjs/tests/test_bignum.js new file mode 100644 index 0000000..f4f72a0 --- /dev/null +++ b/deps/quickjs/tests/test_bignum.js @@ -0,0 +1,326 @@ +"use strict"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function assertThrows(err, func) +{ + var ex; + ex = false; + try { + func(); + } catch(e) { + ex = true; + assert(e instanceof err); + } + assert(ex, true, "exception expected"); +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function bigint_pow(a, n) +{ + var r, i; + r = 1n; + for(i = 0n; i < n; i++) + r *= a; + return r; +} + +/* a must be < b */ +function test_less(a, b) +{ + assert(a < b); + assert(!(b < a)); + assert(a <= b); + assert(!(b <= a)); + assert(b > a); + assert(!(a > b)); + assert(b >= a); + assert(!(a >= b)); + assert(a != b); + assert(!(a == b)); +} + +/* a must be numerically equal to b */ +function test_eq(a, b) +{ + assert(a == b); + assert(b == a); + assert(!(a != b)); + assert(!(b != a)); + assert(a <= b); + assert(b <= a); + assert(!(a < b)); + assert(a >= b); + assert(b >= a); + assert(!(a > b)); +} + +function test_bigint1() +{ + var a, r; + + test_less(2n, 3n); + test_eq(3n, 3n); + + test_less(2, 3n); + test_eq(3, 3n); + + test_less(2.1, 3n); + test_eq(Math.sqrt(4), 2n); + + a = bigint_pow(3n, 100n); + assert((a - 1n) != a); + assert(a == 515377520732011331036461129765621272702107522001n); + assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n); + + r = 1n << 31n; + assert(r, 2147483648n, "1 << 31n === 2147483648n"); + + r = 1n << 32n; + assert(r, 4294967296n, "1 << 32n === 4294967296n"); +} + +function test_bigint2() +{ + assert(BigInt(""), 0n); + assert(BigInt(" 123"), 123n); + assert(BigInt(" 123 "), 123n); + assertThrows(SyntaxError, () => { BigInt("+") } ); + assertThrows(SyntaxError, () => { BigInt("-") } ); + assertThrows(SyntaxError, () => { BigInt("\x00a") } ); + assertThrows(SyntaxError, () => { BigInt(" 123 r") } ); +} + +function test_divrem(div1, a, b, q) +{ + var div, divrem, t; + div = BigInt[div1]; + divrem = BigInt[div1 + "rem"]; + assert(div(a, b) == q); + t = divrem(a, b); + assert(t[0] == q); + assert(a == b * q + t[1]); +} + +function test_idiv1(div, a, b, r) +{ + test_divrem(div, a, b, r[0]); + test_divrem(div, -a, b, r[1]); + test_divrem(div, a, -b, r[2]); + test_divrem(div, -a, -b, r[3]); +} + +/* QuickJS BigInt extensions */ +function test_bigint_ext() +{ + var r; + assert(BigInt.floorLog2(0n) === -1n); + assert(BigInt.floorLog2(7n) === 2n); + + assert(BigInt.sqrt(0xffffffc000000000000000n) === 17592185913343n); + r = BigInt.sqrtrem(0xffffffc000000000000000n); + assert(r[0] === 17592185913343n); + assert(r[1] === 35167191957503n); + + test_idiv1("tdiv", 3n, 2n, [1n, -1n, -1n, 1n]); + test_idiv1("fdiv", 3n, 2n, [1n, -2n, -2n, 1n]); + test_idiv1("cdiv", 3n, 2n, [2n, -1n, -1n, 2n]); + test_idiv1("ediv", 3n, 2n, [1n, -2n, -1n, 2n]); +} + +function test_bigfloat() +{ + var e, a, b, sqrt2; + + assert(typeof 1n === "bigint"); + assert(typeof 1l === "bigfloat"); + assert(1 == 1.0l); + assert(1 !== 1.0l); + + test_less(2l, 3l); + test_eq(3l, 3l); + + test_less(2, 3l); + test_eq(3, 3l); + + test_less(2.1, 3l); + test_eq(Math.sqrt(9), 3l); + + test_less(2n, 3l); + test_eq(3n, 3l); + + e = new BigFloatEnv(128); + assert(e.prec == 128); + a = BigFloat.sqrt(2l, e); + assert(a === BigFloat.parseFloat("0x1.6a09e667f3bcc908b2fb1366ea957d3e", 0, e)); + assert(e.inexact === true); + assert(BigFloat.fpRound(a) == 0x1.6a09e667f3bcc908b2fb1366ea95l); + + b = BigFloatEnv.setPrec(BigFloat.sqrt.bind(null, 2), 128); + assert(a === b); + + assert(BigFloat.isNaN(BigFloat(NaN))); + assert(BigFloat.isFinite(1l)); + assert(!BigFloat.isFinite(1l/0l)); + + assert(BigFloat.abs(-3l) === 3l); + assert(BigFloat.sign(-3l) === -1l); + + assert(BigFloat.exp(0.2l) === 1.2214027581601698339210719946396742l); + assert(BigFloat.log(3l) === 1.0986122886681096913952452369225256l); + assert(BigFloat.pow(2.1l, 1.6l) === 3.277561666451861947162828744873745l); + + assert(BigFloat.sin(-1l) === -0.841470984807896506652502321630299l); + assert(BigFloat.cos(1l) === 0.5403023058681397174009366074429766l); + assert(BigFloat.tan(0.1l) === 0.10033467208545054505808004578111154l); + + assert(BigFloat.asin(0.3l) === 0.30469265401539750797200296122752915l); + assert(BigFloat.acos(0.4l) === 1.1592794807274085998465837940224159l); + assert(BigFloat.atan(0.7l) === 0.610725964389208616543758876490236l); + assert(BigFloat.atan2(7.1l, -5.1l) === 2.1937053809751415549388104628759813l); + + assert(BigFloat.floor(2.5l) === 2l); + assert(BigFloat.ceil(2.5l) === 3l); + assert(BigFloat.trunc(-2.5l) === -2l); + assert(BigFloat.round(2.5l) === 3l); + + assert(BigFloat.fmod(3l,2l) === 1l); + assert(BigFloat.remainder(3l,2l) === -1l); + + /* string conversion */ + assert((1234.125l).toString(), "1234.125"); + assert((1234.125l).toFixed(2), "1234.13"); + assert((1234.125l).toFixed(2, "down"), "1234.12"); + assert((1234.125l).toExponential(), "1.234125e+3"); + assert((1234.125l).toExponential(5), "1.23413e+3"); + assert((1234.125l).toExponential(5, BigFloatEnv.RNDZ), "1.23412e+3"); + assert((1234.125l).toPrecision(6), "1234.13"); + assert((1234.125l).toPrecision(6, BigFloatEnv.RNDZ), "1234.12"); + + /* string conversion with binary base */ + assert((0x123.438l).toString(16), "123.438"); + assert((0x323.438l).toString(16), "323.438"); + assert((0x723.438l).toString(16), "723.438"); + assert((0xf23.438l).toString(16), "f23.438"); + assert((0x123.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "123.44"); + assert((0x323.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "323.44"); + assert((0x723.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "723.44"); + assert((0xf23.438l).toFixed(2, BigFloatEnv.RNDNA, 16), "f23.44"); + assert((0x0.0000438l).toFixed(6, BigFloatEnv.RNDNA, 16), "0.000044"); + assert((0x1230000000l).toFixed(1, BigFloatEnv.RNDNA, 16), "1230000000.0"); + assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "123.44"); + assert((0x123.438l).toPrecision(5, BigFloatEnv.RNDZ, 16), "123.43"); + assert((0x323.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "323.44"); + assert((0x723.438l).toPrecision(5, BigFloatEnv.RNDNA, 16), "723.44"); + assert((-0xf23.438l).toPrecision(5, BigFloatEnv.RNDD, 16), "-f23.44"); + assert((0x123.438l).toExponential(4, BigFloatEnv.RNDNA, 16), "1.2344p+8"); +} + +function test_bigdecimal() +{ + assert(1m === 1m); + assert(1m !== 2m); + test_less(1m, 2m); + test_eq(2m, 2m); + + test_less(1, 2m); + test_eq(2, 2m); + + test_less(1.1, 2m); + test_eq(Math.sqrt(4), 2m); + + test_less(2n, 3m); + test_eq(3n, 3m); + + assert(BigDecimal("1234.1") === 1234.1m); + assert(BigDecimal(" 1234.1") === 1234.1m); + assert(BigDecimal(" 1234.1 ") === 1234.1m); + + assert(BigDecimal(0.1) === 0.1m); + assert(BigDecimal(123) === 123m); + assert(BigDecimal(true) === 1m); + + assert(123m + 1m === 124m); + assert(123m - 1m === 122m); + + assert(3.2m * 3m === 9.6m); + assert(10m / 2m === 5m); + assertThrows(RangeError, () => { 10m / 3m } ); + + assert(10m % 3m === 1m); + assert(-10m % 3m === -1m); + + assert(1234.5m ** 3m === 1881365963.625m); + assertThrows(RangeError, () => { 2m ** 3.1m } ); + assertThrows(RangeError, () => { 2m ** -3m } ); + + assert(BigDecimal.sqrt(2m, + { roundingMode: "half-even", + maximumSignificantDigits: 4 }) === 1.414m); + assert(BigDecimal.sqrt(101m, + { roundingMode: "half-even", + maximumFractionDigits: 3 }) === 10.050m); + assert(BigDecimal.sqrt(0.002m, + { roundingMode: "half-even", + maximumFractionDigits: 3 }) === 0.045m); + + assert(BigDecimal.round(3.14159m, + { roundingMode: "half-even", + maximumFractionDigits: 3 }) === 3.142m); + + assert(BigDecimal.add(3.14159m, 0.31212m, + { roundingMode: "half-even", + maximumFractionDigits: 2 }) === 3.45m); + assert(BigDecimal.sub(3.14159m, 0.31212m, + { roundingMode: "down", + maximumFractionDigits: 2 }) === 2.82m); + assert(BigDecimal.mul(3.14159m, 0.31212m, + { roundingMode: "half-even", + maximumFractionDigits: 3 }) === 0.981m); + assert(BigDecimal.mod(3.14159m, 0.31211m, + { roundingMode: "half-even", + maximumFractionDigits: 4 }) === 0.0205m); + assert(BigDecimal.div(20m, 3m, + { roundingMode: "half-even", + maximumSignificantDigits: 3 }) === 6.67m); + assert(BigDecimal.div(20m, 3m, + { roundingMode: "half-even", + maximumFractionDigits: 50 }) === + 6.66666666666666666666666666666666666666666666666667m); + + /* string conversion */ + assert((1234.125m).toString(), "1234.125"); + assert((1234.125m).toFixed(2), "1234.13"); + assert((1234.125m).toFixed(2, "down"), "1234.12"); + assert((1234.125m).toExponential(), "1.234125e+3"); + assert((1234.125m).toExponential(5), "1.23413e+3"); + assert((1234.125m).toExponential(5, "down"), "1.23412e+3"); + assert((1234.125m).toPrecision(6), "1234.13"); + assert((1234.125m).toPrecision(6, "down"), "1234.12"); + assert((-1234.125m).toPrecision(6, "floor"), "-1234.13"); +} + +test_bigint1(); +test_bigint2(); +test_bigint_ext(); +test_bigfloat(); +test_bigdecimal(); diff --git a/deps/quickjs/tests/test_bjson.js b/deps/quickjs/tests/test_bjson.js new file mode 100644 index 0000000..fcbb8e6 --- /dev/null +++ b/deps/quickjs/tests/test_bjson.js @@ -0,0 +1,191 @@ +import * as bjson from "./bjson.so"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function toHex(a) +{ + var i, s = "", tab, v; + tab = new Uint8Array(a); + for(i = 0; i < tab.length; i++) { + v = tab[i].toString(16); + if (v.length < 2) + v = "0" + v; + if (i !== 0) + s += " "; + s += v; + } + return s; +} + +function isArrayLike(a) +{ + return Array.isArray(a) || + (a instanceof Uint8ClampedArray) || + (a instanceof Uint8Array) || + (a instanceof Uint16Array) || + (a instanceof Uint32Array) || + (a instanceof Int8Array) || + (a instanceof Int16Array) || + (a instanceof Int32Array) || + (a instanceof Float32Array) || + (a instanceof Float64Array); +} + +function toStr(a) +{ + var s, i, props, prop; + + switch(typeof(a)) { + case "object": + if (a === null) + return "null"; + if (a instanceof Date) { + s = "Date(" + toStr(a.valueOf()) + ")"; + } else if (a instanceof Number) { + s = "Number(" + toStr(a.valueOf()) + ")"; + } else if (a instanceof String) { + s = "String(" + toStr(a.valueOf()) + ")"; + } else if (a instanceof Boolean) { + s = "Boolean(" + toStr(a.valueOf()) + ")"; + } else if (isArrayLike(a)) { + s = "["; + for(i = 0; i < a.length; i++) { + if (i != 0) + s += ","; + s += toStr(a[i]); + } + s += "]"; + } else { + props = Object.keys(a); + s = "{"; + for(i = 0; i < props.length; i++) { + if (i != 0) + s += ","; + prop = props[i]; + s += prop + ":" + toStr(a[prop]); + } + s += "}"; + } + return s; + case "undefined": + return "undefined"; + case "string": + return a.__quote(); + case "number": + case "bigfloat": + if (a == 0 && 1 / a < 0) + return "-0"; + else + return a.toString(); + break; + default: + return a.toString(); + } +} + +function bjson_test(a) +{ + var buf, r, a_str, r_str; + a_str = toStr(a); + buf = bjson.write(a); + if (0) { + print(a_str, "->", toHex(buf)); + } + r = bjson.read(buf, 0, buf.byteLength); + r_str = toStr(r); + if (a_str != r_str) { + print(a_str); + print(r_str); + assert(false); + } +} + +/* test multiple references to an object including circular + references */ +function bjson_test_reference() +{ + var array, buf, i, n, array_buffer; + n = 16; + array = []; + for(i = 0; i < n; i++) + array[i] = {}; + array_buffer = new ArrayBuffer(n); + for(i = 0; i < n; i++) { + array[i].next = array[(i + 1) % n]; + array[i].idx = i; + array[i].typed_array = new Uint8Array(array_buffer, i, 1); + } + buf = bjson.write(array, true); + + array = bjson.read(buf, 0, buf.byteLength, true); + + /* check the result */ + for(i = 0; i < n; i++) { + assert(array[i].next, array[(i + 1) % n]); + assert(array[i].idx, i); + assert(array[i].typed_array.buffer, array_buffer); + assert(array[i].typed_array.length, 1); + assert(array[i].typed_array.byteOffset, i); + } +} + +function bjson_test_all() +{ + var obj; + + bjson_test({x:1, y:2, if:3}); + bjson_test([1, 2, 3]); + bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]); + if (typeof BigInt !== "undefined") { + bjson_test([BigInt("1"), -BigInt("0x123456789"), + BigInt("0x123456789abcdef123456789abcdef")]); + } + if (typeof BigFloat !== "undefined") { + BigFloatEnv.setPrec(function () { + bjson_test([BigFloat("0.1"), BigFloat("-1e30"), BigFloat("0"), + BigFloat("-0"), BigFloat("Infinity"), BigFloat("-Infinity"), + 0.0 / BigFloat("0"), BigFloat.MAX_VALUE, + BigFloat.MIN_VALUE]); + }, 113, 15); + } + if (typeof BigDecimal !== "undefined") { + bjson_test([BigDecimal("0"), + BigDecimal("0.8"), BigDecimal("123321312321321e100"), + BigDecimal("-1233213123213214332333223332e100"), + BigDecimal("1.233e-1000")]); + } + + bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]); + + bjson_test(new Int32Array([123123, 222111, -32222])); + bjson_test(new Float64Array([123123, 222111.5])); + + /* tested with a circular reference */ + obj = {}; + obj.x = obj; + try { + bjson.write(obj); + assert(false); + } catch(e) { + assert(e instanceof TypeError); + } + + bjson_test_reference(); +} + +bjson_test_all(); diff --git a/deps/quickjs/tests/test_builtin.js b/deps/quickjs/tests/test_builtin.js new file mode 100644 index 0000000..e256066 --- /dev/null +++ b/deps/quickjs/tests/test_builtin.js @@ -0,0 +1,713 @@ +"use strict"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function assert_throws(expected_error, func) +{ + var err = false; + try { + func(); + } catch(e) { + err = true; + if (!(e instanceof expected_error)) { + throw Error("unexpected exception type"); + } + } + if (!err) { + throw Error("expected exception"); + } +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function my_func(a, b) +{ + return a + b; +} + +function test_function() +{ + function f(a, b) { + var i, tab = []; + tab.push(this); + for(i = 0; i < arguments.length; i++) + tab.push(arguments[i]); + return tab; + } + function constructor1(a) { + this.x = a; + } + + var r, g; + + r = my_func.call(null, 1, 2); + assert(r, 3, "call"); + + r = my_func.apply(null, [1, 2]); + assert(r, 3, "apply"); + + r = (function () { return 1; }).apply(null, undefined); + assert(r, 1); + + assert_throws(TypeError, (function() { + Reflect.apply((function () { return 1; }), null, undefined); + })); + + r = new Function("a", "b", "return a + b;"); + assert(r(2,3), 5, "function"); + + g = f.bind(1, 2); + assert(g.length, 1); + assert(g.name, "bound f"); + assert(g(3), [1,2,3]); + + g = constructor1.bind(null, 1); + r = new g(); + assert(r.x, 1); +} + +function test() +{ + var r, a, b, c, err; + + r = Error("hello"); + assert(r.message, "hello", "Error"); + + a = new Object(); + a.x = 1; + assert(a.x, 1, "Object"); + + assert(Object.getPrototypeOf(a), Object.prototype, "getPrototypeOf"); + Object.defineProperty(a, "y", { value: 3, writable: true, configurable: true, enumerable: true }); + assert(a.y, 3, "defineProperty"); + + Object.defineProperty(a, "z", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true }); + assert(a.z, 4, "get"); + a.z = 5; + assert(a.z_val, 5, "set"); + + a = { get z() { return 4; }, set z(val) { this.z_val = val; } }; + assert(a.z, 4, "get"); + a.z = 5; + assert(a.z_val, 5, "set"); + + b = Object.create(a); + assert(Object.getPrototypeOf(b), a, "create"); + c = {u:2}; + /* XXX: refcount bug in 'b' instead of 'a' */ + Object.setPrototypeOf(a, c); + assert(Object.getPrototypeOf(a), c, "setPrototypeOf"); + + a = {}; + assert(a.toString(), "[object Object]", "toString"); + + a = {x:1}; + assert(Object.isExtensible(a), true, "extensible"); + Object.preventExtensions(a); + + err = false; + try { + a.y = 2; + } catch(e) { + err = true; + } + assert(Object.isExtensible(a), false, "extensible"); + assert(typeof a.y, "undefined", "extensible"); + assert(err, true, "extensible"); +} + +function test_enum() +{ + var a, tab; + a = {x:1, + "18014398509481984": 1, + "9007199254740992": 1, + "9007199254740991": 1, + "4294967296": 1, + "4294967295": 1, + y:1, + "4294967294": 1, + "1": 2}; + tab = Object.keys(a); +// console.log("tab=" + tab.toString()); + assert(tab, ["1","4294967294","x","18014398509481984","9007199254740992","9007199254740991","4294967296","4294967295","y"], "keys"); +} + +function test_array() +{ + var a, err; + + a = [1, 2, 3]; + assert(a.length, 3, "array"); + assert(a[2], 3, "array1"); + + a = new Array(10); + assert(a.length, 10, "array2"); + + a = new Array(1, 2); + assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array3"); + + a = [1, 2, 3]; + a.length = 2; + assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, "array4"); + + a = []; + a[1] = 10; + a[4] = 3; + assert(a.length, 5); + + a = [1,2]; + a.length = 5; + a[4] = 1; + a.length = 4; + assert(a[4] !== 1, true, "array5"); + + a = [1,2]; + a.push(3,4); + assert(a.join(), "1,2,3,4", "join"); + + a = [1,2,3,4,5]; + Object.defineProperty(a, "3", { configurable: false }); + err = false; + try { + a.length = 2; + } catch(e) { + err = true; + } + assert(err && a.toString() === "1,2,3,4"); +} + +function test_string() +{ + var a; + a = String("abc"); + assert(a.length, 3, "string"); + assert(a[1], "b", "string"); + assert(a.charCodeAt(1), 0x62, "string"); + assert(String.fromCharCode(65), "A", "string"); + assert(String.fromCharCode.apply(null, [65, 66, 67]), "ABC", "string"); + assert(a.charAt(1), "b"); + assert(a.charAt(-1), ""); + assert(a.charAt(3), ""); + + a = "abcd"; + assert(a.substring(1, 3), "bc", "substring"); + a = String.fromCharCode(0x20ac); + assert(a.charCodeAt(0), 0x20ac, "unicode"); + assert(a, "€", "unicode"); + assert(a, "\u20ac", "unicode"); + assert(a, "\u{20ac}", "unicode"); + assert("a", "\x61", "unicode"); + + a = "\u{10ffff}"; + assert(a.length, 2, "unicode"); + assert(a, "\u{dbff}\u{dfff}", "unicode"); + assert(a.codePointAt(0), 0x10ffff); + assert(String.fromCodePoint(0x10ffff), a); + + assert("a".concat("b", "c"), "abc"); + + assert("abcabc".indexOf("cab"), 2); + assert("abcabc".indexOf("cab2"), -1); + assert("abc".indexOf("c"), 2); + + assert("aaa".indexOf("a"), 0); + assert("aaa".indexOf("a", NaN), 0); + assert("aaa".indexOf("a", -Infinity), 0); + assert("aaa".indexOf("a", -1), 0); + assert("aaa".indexOf("a", -0), 0); + assert("aaa".indexOf("a", 0), 0); + assert("aaa".indexOf("a", 1), 1); + assert("aaa".indexOf("a", 2), 2); + assert("aaa".indexOf("a", 3), -1); + assert("aaa".indexOf("a", 4), -1); + assert("aaa".indexOf("a", Infinity), -1); + + assert("aaa".indexOf(""), 0); + assert("aaa".indexOf("", NaN), 0); + assert("aaa".indexOf("", -Infinity), 0); + assert("aaa".indexOf("", -1), 0); + assert("aaa".indexOf("", -0), 0); + assert("aaa".indexOf("", 0), 0); + assert("aaa".indexOf("", 1), 1); + assert("aaa".indexOf("", 2), 2); + assert("aaa".indexOf("", 3), 3); + assert("aaa".indexOf("", 4), 3); + assert("aaa".indexOf("", Infinity), 3); + + assert("aaa".lastIndexOf("a"), 2); + assert("aaa".lastIndexOf("a", NaN), 2); + assert("aaa".lastIndexOf("a", -Infinity), 0); + assert("aaa".lastIndexOf("a", -1), 0); + assert("aaa".lastIndexOf("a", -0), 0); + assert("aaa".lastIndexOf("a", 0), 0); + assert("aaa".lastIndexOf("a", 1), 1); + assert("aaa".lastIndexOf("a", 2), 2); + assert("aaa".lastIndexOf("a", 3), 2); + assert("aaa".lastIndexOf("a", 4), 2); + assert("aaa".lastIndexOf("a", Infinity), 2); + + assert("aaa".lastIndexOf(""), 3); + assert("aaa".lastIndexOf("", NaN), 3); + assert("aaa".lastIndexOf("", -Infinity), 0); + assert("aaa".lastIndexOf("", -1), 0); + assert("aaa".lastIndexOf("", -0), 0); + assert("aaa".lastIndexOf("", 0), 0); + assert("aaa".lastIndexOf("", 1), 1); + assert("aaa".lastIndexOf("", 2), 2); + assert("aaa".lastIndexOf("", 3), 3); + assert("aaa".lastIndexOf("", 4), 3); + assert("aaa".lastIndexOf("", Infinity), 3); + + assert("a,b,c".split(","), ["a","b","c"]); + assert(",b,c".split(","), ["","b","c"]); + assert("a,b,".split(","), ["a","b",""]); + + assert("aaaa".split(), [ "aaaa" ]); + assert("aaaa".split(undefined, 0), [ ]); + assert("aaaa".split(""), [ "a", "a", "a", "a" ]); + assert("aaaa".split("", 0), [ ]); + assert("aaaa".split("", 1), [ "a" ]); + assert("aaaa".split("", 2), [ "a", "a" ]); + assert("aaaa".split("a"), [ "", "", "", "", "" ]); + assert("aaaa".split("a", 2), [ "", "" ]); + assert("aaaa".split("aa"), [ "", "", "" ]); + assert("aaaa".split("aa", 0), [ ]); + assert("aaaa".split("aa", 1), [ "" ]); + assert("aaaa".split("aa", 2), [ "", "" ]); + assert("aaaa".split("aaa"), [ "", "a" ]); + assert("aaaa".split("aaaa"), [ "", "" ]); + assert("aaaa".split("aaaaa"), [ "aaaa" ]); + assert("aaaa".split("aaaaa", 0), [ ]); + assert("aaaa".split("aaaaa", 1), [ "aaaa" ]); + + assert(eval('"\0"'), "\0"); + + assert("abc".padStart(Infinity, ""), "abc"); +} + +function test_math() +{ + var a; + a = 1.4; + assert(Math.floor(a), 1); + assert(Math.ceil(a), 2); + assert(Math.imul(0x12345678, 123), -1088058456); + assert(Math.fround(0.1), 0.10000000149011612); + assert(Math.hypot() == 0); + assert(Math.hypot(-2) == 2); + assert(Math.hypot(3, 4) == 5); + assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15); +} + +function test_number() +{ + assert(parseInt("123"), 123); + assert(parseInt(" 123r"), 123); + assert(parseInt("0x123"), 0x123); + assert(parseInt("0o123"), 0); + assert(+" 123 ", 123); + assert(+"0b111", 7); + assert(+"0o123", 83); + assert(parseFloat("0x1234"), 0); + assert(parseFloat("Infinity"), Infinity); + assert(parseFloat("-Infinity"), -Infinity); + assert(parseFloat("123.2"), 123.2); + assert(parseFloat("123.2e3"), 123200); + assert(Number.isNaN(Number("+"))); + assert(Number.isNaN(Number("-"))); + assert(Number.isNaN(Number("\x00a"))); + + assert((25).toExponential(0), "3e+1"); + assert((-25).toExponential(0), "-3e+1"); + assert((2.5).toPrecision(1), "3"); + assert((-2.5).toPrecision(1), "-3"); + assert((1.125).toFixed(2), "1.13"); + assert((-1.125).toFixed(2), "-1.13"); +} + +function test_eval2() +{ + var g_call_count = 0; + /* force non strict mode for f1 and f2 */ + var f1 = new Function("eval", "eval(1, 2)"); + var f2 = new Function("eval", "eval(...[1, 2])"); + function g(a, b) { + assert(a, 1); + assert(b, 2); + g_call_count++; + } + f1(g); + f2(g); + assert(g_call_count, 2); +} + +function test_eval() +{ + function f(b) { + var x = 1; + return eval(b); + } + var r, a; + + r = eval("1+1;"); + assert(r, 2, "eval"); + + r = eval("var my_var=2; my_var;"); + assert(r, 2, "eval"); + assert(typeof my_var, "undefined"); + + assert(eval("if (1) 2; else 3;"), 2); + assert(eval("if (0) 2; else 3;"), 3); + + assert(f.call(1, "this"), 1); + + a = 2; + assert(eval("a"), 2); + + eval("a = 3"); + assert(a, 3); + + assert(f("arguments.length", 1), 2); + assert(f("arguments[1]", 1), 1); + + a = 4; + assert(f("a"), 4); + f("a=3"); + assert(a, 3); + + test_eval2(); +} + +function test_typed_array() +{ + var buffer, a, i, str; + + a = new Uint8Array(4); + assert(a.length, 4); + for(i = 0; i < a.length; i++) + a[i] = i; + assert(a.join(","), "0,1,2,3"); + a[0] = -1; + assert(a[0], 255); + + a = new Int8Array(3); + a[0] = 255; + assert(a[0], -1); + + a = new Int32Array(3); + a[0] = Math.pow(2, 32) - 1; + assert(a[0], -1); + assert(a.BYTES_PER_ELEMENT, 4); + + a = new Uint8ClampedArray(4); + a[0] = -100; + a[1] = 1.5; + a[2] = 0.5; + a[3] = 1233.5; + assert(a.toString(), "0,2,0,255"); + + buffer = new ArrayBuffer(16); + assert(buffer.byteLength, 16); + a = new Uint32Array(buffer, 12, 1); + assert(a.length, 1); + a[0] = -1; + + a = new Uint16Array(buffer, 2); + a[0] = -1; + + a = new Float32Array(buffer, 8, 1); + a[0] = 1; + + a = new Uint8Array(buffer); + + str = a.toString(); + /* test little and big endian cases */ + if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" && + str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") { + assert(false); + } + + assert(a.buffer, buffer); + + a = new Uint8Array([1, 2, 3, 4]); + assert(a.toString(), "1,2,3,4"); + a.set([10, 11], 2); + assert(a.toString(), "1,2,10,11"); +} + +function test_json() +{ + var a, s; + s = '{"x":1,"y":true,"z":null,"a":[1,2,3],"s":"str"}'; + a = JSON.parse(s); + assert(a.x, 1); + assert(a.y, true); + assert(a.z, null); + assert(JSON.stringify(a), s); + + /* indentation test */ + assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1), +`[ + [ + { + "x": 1, + "y": {}, + "z": [] + }, + 2, + 3 + ] +]`); +} + +function test_date() +{ + var d = new Date(1506098258091), a, s; + assert(d.toISOString(), "2017-09-22T16:37:38.091Z"); + d.setUTCHours(18, 10, 11); + assert(d.toISOString(), "2017-09-22T18:10:11.091Z"); + a = Date.parse(d.toISOString()); + assert((new Date(a)).toISOString(), d.toISOString()); + s = new Date("2020-01-01T01:01:01.1Z").toISOString(); + assert(s == "2020-01-01T01:01:01.100Z"); + s = new Date("2020-01-01T01:01:01.12Z").toISOString(); + assert(s == "2020-01-01T01:01:01.120Z"); + s = new Date("2020-01-01T01:01:01.123Z").toISOString(); + assert(s == "2020-01-01T01:01:01.123Z"); + s = new Date("2020-01-01T01:01:01.1234Z").toISOString(); + assert(s == "2020-01-01T01:01:01.123Z"); + s = new Date("2020-01-01T01:01:01.12345Z").toISOString(); + assert(s == "2020-01-01T01:01:01.123Z"); + s = new Date("2020-01-01T01:01:01.1235Z").toISOString(); + assert(s == "2020-01-01T01:01:01.124Z"); + s = new Date("2020-01-01T01:01:01.9999Z").toISOString(); + assert(s == "2020-01-01T01:01:02.000Z"); +} + +function test_regexp() +{ + var a, str; + str = "abbbbbc"; + a = /(b+)c/.exec(str); + assert(a[0], "bbbbbc"); + assert(a[1], "bbbbb"); + assert(a.index, 1); + assert(a.input, str); + a = /(b+)c/.test(str); + assert(a, true); + assert(/\x61/.exec("a")[0], "a"); + assert(/\u0061/.exec("a")[0], "a"); + assert(/\ca/.exec("\x01")[0], "\x01"); + assert(/\\a/.exec("\\a")[0], "\\a"); + assert(/\c0/.exec("\\c0")[0], "\\c0"); + + a = /(\.(?=com|org)|\/)/.exec("ah.com"); + assert(a.index === 2 && a[0] === "."); + + a = /(\.(?!com|org)|\/)/.exec("ah.com"); + assert(a, null); + + a = /(?=(a+))/.exec("baaabac"); + assert(a.index === 1 && a[0] === "" && a[1] === "aaa"); + + a = /(z)((a+)?(b+)?(c))*/.exec("zaacbbbcac"); + assert(a, ["zaacbbbcac","z","ac","a",,"c"]); + + a = eval("/\0a/"); + assert(a.toString(), "/\0a/"); + assert(a.exec("\0a")[0], "\0a"); + + assert(/{1a}/.toString(), "/{1a}/"); + a = /a{1+/.exec("a{11"); + assert(a, ["a{11"]); + + /* test zero length matches */ + a = /(?:(?=(abc)))a/.exec("abc"); + assert(a, ["a", "abc"]); + a = /(?:(?=(abc)))?a/.exec("abc"); + assert(a, ["a", undefined]); + a = /(?:(?=(abc))){0,2}a/.exec("abc"); + assert(a, ["a", undefined]); + a = /(?:|[\w])+([0-9])/.exec("123a23"); + assert(a, ["123a23", "3"]); +} + +function test_symbol() +{ + var a, b, obj, c; + a = Symbol("abc"); + obj = {}; + obj[a] = 2; + assert(obj[a], 2); + assert(typeof obj["abc"], "undefined"); + assert(String(a), "Symbol(abc)"); + b = Symbol("abc"); + assert(a == a); + assert(a === a); + assert(a != b); + assert(a !== b); + + b = Symbol.for("abc"); + c = Symbol.for("abc"); + assert(b === c); + assert(b !== a); + + assert(Symbol.keyFor(b), "abc"); + assert(Symbol.keyFor(a), undefined); + + a = Symbol("aaa"); + assert(a.valueOf(), a); + assert(a.toString(), "Symbol(aaa)"); + + b = Object(a); + assert(b.valueOf(), a); + assert(b.toString(), "Symbol(aaa)"); +} + +function test_map() +{ + var a, i, n, tab, o, v; + n = 1000; + a = new Map(); + tab = []; + for(i = 0; i < n; i++) { + v = { }; + o = { id: i }; + tab[i] = [o, v]; + a.set(o, v); + } + + assert(a.size, n); + for(i = 0; i < n; i++) { + assert(a.get(tab[i][0]), tab[i][1]); + } + + i = 0; + a.forEach(function (v, o) { + assert(o, tab[i++][0]); + assert(a.has(o)); + assert(a.delete(o)); + assert(!a.has(o)); + }); + + assert(a.size, 0); +} + +function test_weak_map() +{ + var a, i, n, tab, o, v, n2; + a = new WeakMap(); + n = 10; + tab = []; + for(i = 0; i < n; i++) { + v = { }; + o = { id: i }; + tab[i] = [o, v]; + a.set(o, v); + } + o = null; + + n2 = n >> 1; + for(i = 0; i < n2; i++) { + a.delete(tab[i][0]); + } + for(i = n2; i < n; i++) { + tab[i][0] = null; /* should remove the object from the WeakMap too */ + } + /* the WeakMap should be empty here */ +} + +function test_generator() +{ + function *f() { + var ret; + yield 1; + ret = yield 2; + assert(ret, "next_arg"); + return 3; + } + function *f2() { + yield 1; + yield 2; + return "ret_val"; + } + function *f1() { + var ret = yield *f2(); + assert(ret, "ret_val"); + return 3; + } + function *f3() { + var ret; + /* test stack consistency with nip_n to handle yield return + + * finally clause */ + try { + ret = 2 + (yield 1); + } catch(e) { + } finally { + ret++; + } + return ret; + } + var g, v; + g = f(); + v = g.next(); + assert(v.value === 1 && v.done === false); + v = g.next(); + assert(v.value === 2 && v.done === false); + v = g.next("next_arg"); + assert(v.value === 3 && v.done === true); + v = g.next(); + assert(v.value === undefined && v.done === true); + + g = f1(); + v = g.next(); + assert(v.value === 1 && v.done === false); + v = g.next(); + assert(v.value === 2 && v.done === false); + v = g.next(); + assert(v.value === 3 && v.done === true); + v = g.next(); + assert(v.value === undefined && v.done === true); + + g = f3(); + v = g.next(); + assert(v.value === 1 && v.done === false); + v = g.next(3); + assert(v.value === 6 && v.done === true); +} + +test(); +test_function(); +test_enum(); +test_array(); +test_string(); +test_math(); +test_number(); +test_eval(); +test_typed_array(); +test_json(); +test_date(); +test_regexp(); +test_symbol(); +test_map(); +test_weak_map(); +test_generator(); diff --git a/deps/quickjs/tests/test_closure.js b/deps/quickjs/tests/test_closure.js new file mode 100644 index 0000000..aa1d17e --- /dev/null +++ b/deps/quickjs/tests/test_closure.js @@ -0,0 +1,221 @@ +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +var log_str = ""; + +function log(str) +{ + log_str += str + ","; +} + +function f(a, b, c) +{ + var x = 10; + log("a="+a); + function g(d) { + function h() { + log("d=" + d); + log("x=" + x); + } + log("b=" + b); + log("c=" + c); + h(); + } + g(4); + return g; +} + +var g1 = f(1, 2, 3); +g1(5); + +assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1"); + +function test_closure1() +{ + function f2() + { + var val = 1; + + function set(a) { + val = a; + } + function get(a) { + return val; + } + return { "set": set, "get": get }; + } + + var obj = f2(); + obj.set(10); + var r; + r = obj.get(); + assert(r, 10, "closure2"); +} + +function test_closure2() +{ + var expr_func = function myfunc1(n) { + function myfunc2(n) { + return myfunc1(n - 1); + } + if (n == 0) + return 0; + else + return myfunc2(n); + }; + var r; + r = expr_func(1); + assert(r, 0, "expr_func"); +} + +function test_closure3() +{ + function fib(n) + { + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib(n - 1) + fib(n - 2); + } + + var fib_func = function fib1(n) + { + if (n <= 0) + return 0; + else if (n == 1) + return 1; + else + return fib1(n - 1) + fib1(n - 2); + }; + + assert(fib(6), 8, "fib"); + assert(fib_func(6), 8, "fib_func"); +} + +function test_arrow_function() +{ + "use strict"; + + function f1() { + return (() => arguments)(); + } + function f2() { + return (() => this)(); + } + function f3() { + return (() => eval("this"))(); + } + function f4() { + return (() => eval("new.target"))(); + } + var a; + + a = f1(1, 2); + assert(a.length, 2); + assert(a[0] === 1 && a[1] === 2); + + assert(f2.call("this_val") === "this_val"); + assert(f3.call("this_val") === "this_val"); + assert(new f4() === f4); + + var o1 = { f() { return this; } }; + var o2 = { f() { + return (() => eval("super.f()"))(); + } }; + o2.__proto__ = o1; + + assert(o2.f() === o2); +} + +function test_with() +{ + var o1 = { x: "o1", y: "o1" }; + var x = "local"; + eval('var z="var_obj";'); + assert(z === "var_obj"); + with (o1) { + assert(x === "o1"); + assert(eval("x") === "o1"); + var f = function () { + o2 = { x: "o2" }; + with (o2) { + assert(x === "o2"); + assert(y === "o1"); + assert(z === "var_obj"); + assert(eval("x") === "o2"); + assert(eval("y") === "o1"); + assert(eval("z") === "var_obj"); + assert(eval('eval("x")') === "o2"); + } + }; + f(); + } +} + +function test_eval_closure() +{ + var tab; + + tab = []; + for(let i = 0; i < 3; i++) { + eval("tab.push(function g1() { return i; })"); + } + for(let i = 0; i < 3; i++) { + assert(tab[i]() === i); + } + + tab = []; + for(let i = 0; i < 3; i++) { + let f = function f() { + eval("tab.push(function g2() { return i; })"); + }; + f(); + } + for(let i = 0; i < 3; i++) { + assert(tab[i]() === i); + } +} + +function test_eval_const() +{ + const a = 1; + var success = false; + var f = function () { + eval("a = 1"); + }; + try { + f(); + } catch(e) { + success = (e instanceof TypeError); + } + assert(success); +} + +test_closure1(); +test_closure2(); +test_closure3(); +test_arrow_function(); +test_with(); +test_eval_closure(); +test_eval_const(); diff --git a/deps/quickjs/tests/test_language.js b/deps/quickjs/tests/test_language.js new file mode 100644 index 0000000..65dab5f --- /dev/null +++ b/deps/quickjs/tests/test_language.js @@ -0,0 +1,606 @@ +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function assert_throws(expected_error, func) +{ + var err = false; + try { + func(); + } catch(e) { + err = true; + if (!(e instanceof expected_error)) { + throw Error("unexpected exception type"); + } + } + if (!err) { + throw Error("expected exception"); + } +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function test_op1() +{ + var r, a; + r = 1 + 2; + assert(r, 3, "1 + 2 === 3"); + + r = 1 - 2; + assert(r, -1, "1 - 2 === -1"); + + r = -1; + assert(r, -1, "-1 === -1"); + + r = +2; + assert(r, 2, "+2 === 2"); + + r = 2 * 3; + assert(r, 6, "2 * 3 === 6"); + + r = 4 / 2; + assert(r, 2, "4 / 2 === 2"); + + r = 4 % 3; + assert(r, 1, "4 % 3 === 3"); + + r = 4 << 2; + assert(r, 16, "4 << 2 === 16"); + + r = 1 << 0; + assert(r, 1, "1 << 0 === 1"); + + r = 1 << 31; + assert(r, -2147483648, "1 << 31 === -2147483648"); + + r = 1 << 32; + assert(r, 1, "1 << 32 === 1"); + + r = (1 << 31) < 0; + assert(r, true, "(1 << 31) < 0 === true"); + + r = -4 >> 1; + assert(r, -2, "-4 >> 1 === -2"); + + r = -4 >>> 1; + assert(r, 0x7ffffffe, "-4 >>> 1 === 0x7ffffffe"); + + r = 1 & 1; + assert(r, 1, "1 & 1 === 1"); + + r = 0 | 1; + assert(r, 1, "0 | 1 === 1"); + + r = 1 ^ 1; + assert(r, 0, "1 ^ 1 === 0"); + + r = ~1; + assert(r, -2, "~1 === -2"); + + r = !1; + assert(r, false, "!1 === false"); + + assert((1 < 2), true, "(1 < 2) === true"); + + assert((2 > 1), true, "(2 > 1) === true"); + + assert(('b' > 'a'), true, "('b' > 'a') === true"); + + assert(2 ** 8, 256, "2 ** 8 === 256"); +} + +function test_cvt() +{ + assert((NaN | 0) === 0); + assert((Infinity | 0) === 0); + assert(((-Infinity) | 0) === 0); + assert(("12345" | 0) === 12345); + assert(("0x12345" | 0) === 0x12345); + assert(((4294967296 * 3 - 4) | 0) === -4); + + assert(("12345" >>> 0) === 12345); + assert(("0x12345" >>> 0) === 0x12345); + assert((NaN >>> 0) === 0); + assert((Infinity >>> 0) === 0); + assert(((-Infinity) >>> 0) === 0); + assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4)); + assert((19686109595169230000).toString() === "19686109595169230000"); +} + +function test_eq() +{ + assert(null == undefined); + assert(undefined == null); + assert(true == 1); + assert(0 == false); + assert("" == 0); + assert("123" == 123); + assert("122" != 123); + assert((new Number(1)) == 1); + assert(2 == (new Number(2))); + assert((new String("abc")) == "abc"); + assert({} != "abc"); +} + +function test_inc_dec() +{ + var a, r; + + a = 1; + r = a++; + assert(r === 1 && a === 2, true, "++"); + + a = 1; + r = ++a; + assert(r === 2 && a === 2, true, "++"); + + a = 1; + r = a--; + assert(r === 1 && a === 0, true, "--"); + + a = 1; + r = --a; + assert(r === 0 && a === 0, true, "--"); + + a = {x:true}; + a.x++; + assert(a.x, 2, "++"); + + a = {x:true}; + a.x--; + assert(a.x, 0, "--"); + + a = [true]; + a[0]++; + assert(a[0], 2, "++"); + + a = {x:true}; + r = a.x++; + assert(r === 1 && a.x === 2, true, "++"); + + a = {x:true}; + r = a.x--; + assert(r === 1 && a.x === 0, true, "--"); + + a = [true]; + r = a[0]++; + assert(r === 1 && a[0] === 2, true, "++"); + + a = [true]; + r = a[0]--; + assert(r === 1 && a[0] === 0, true, "--"); +} + +function F(x) +{ + this.x = x; +} + +function test_op2() +{ + var a, b; + a = new Object; + a.x = 1; + assert(a.x, 1, "new"); + b = new F(2); + assert(b.x, 2, "new"); + + a = {x : 2}; + assert(("x" in a), true, "in"); + assert(("y" in a), false, "in"); + + a = {}; + assert((a instanceof Object), true, "instanceof"); + assert((a instanceof String), false, "instanceof"); + + assert((typeof 1), "number", "typeof"); + assert((typeof Object), "function", "typeof"); + assert((typeof null), "object", "typeof"); + assert((typeof unknown_var), "undefined", "typeof"); + + a = {x: 1, if: 2, async: 3}; + assert(a.if === 2); + assert(a.async === 3); +} + +function test_delete() +{ + var a, err; + + a = {x: 1, y: 1}; + assert((delete a.x), true, "delete"); + assert(("x" in a), false, "delete"); + + /* the following are not tested by test262 */ + assert(delete "abc"[100], true); + + err = false; + try { + delete null.a; + } catch(e) { + err = (e instanceof TypeError); + } + assert(err, true, "delete"); + + err = false; + try { + a = { f() { delete super.a; } }; + a.f(); + } catch(e) { + err = (e instanceof ReferenceError); + } + assert(err, true, "delete"); +} + +function test_prototype() +{ + var f = function f() { }; + assert(f.prototype.constructor, f, "prototype"); + + var g = function g() { }; + /* QuickJS bug */ + Object.defineProperty(g, "prototype", { writable: false }); + assert(g.prototype.constructor, g, "prototype"); +} + +function test_arguments() +{ + function f2() { + assert(arguments.length, 2, "arguments"); + assert(arguments[0], 1, "arguments"); + assert(arguments[1], 3, "arguments"); + } + f2(1, 3); +} + +function test_class() +{ + var o; + class C { + constructor() { + this.x = 10; + } + f() { + return 1; + } + static F() { + return -1; + } + get y() { + return 12; + } + }; + class D extends C { + constructor() { + super(); + this.z = 20; + } + g() { + return 2; + } + static G() { + return -2; + } + h() { + return super.f(); + } + static H() { + return super["F"](); + } + } + + assert(C.F() === -1); + assert(Object.getOwnPropertyDescriptor(C.prototype, "y").get.name === "get y"); + + o = new C(); + assert(o.f() === 1); + assert(o.x === 10); + + assert(D.F() === -1); + assert(D.G() === -2); + assert(D.H() === -1); + + o = new D(); + assert(o.f() === 1); + assert(o.g() === 2); + assert(o.x === 10); + assert(o.z === 20); + assert(o.h() === 1); + + /* test class name scope */ + var E1 = class E { static F() { return E; } }; + assert(E1 === E1.F()); + + class S { + static x = 42; + static y = S.x; + static z = this.x; + } + assert(S.x === 42); + assert(S.y === 42); + assert(S.z === 42); +}; + +function test_template() +{ + var a, b; + b = 123; + a = `abc${b}d`; + assert(a, "abc123d"); + + a = String.raw `abc${b}d`; + assert(a, "abc123d"); + + a = "aaa"; + b = "bbb"; + assert(`aaa${a, b}ccc`, "aaabbbccc"); +} + +function test_template_skip() +{ + var a = "Bar"; + var { b = `${a + `a${a}` }baz` } = {}; + assert(b, "BaraBarbaz"); +} + +function test_object_literal() +{ + var x = 0, get = 1, set = 2; async = 3; + a = { get: 2, set: 3, async: 4 }; + assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}'); + + a = { x, get, set, async }; + assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}'); +} + +function test_regexp_skip() +{ + var a, b; + [a, b = /abc\(/] = [1]; + assert(a === 1); + + [a, b =/abc\(/] = [2]; + assert(a === 2); +} + +function test_labels() +{ + do x: { break x; } while(0); + if (1) + x: { break x; } + else + x: { break x; } + with ({}) x: { break x; }; + while (0) x: { break x; }; +} + +function test_destructuring() +{ + function * g () { return 0; }; + var [x] = g(); + assert(x, void 0); +} + +function test_spread() +{ + var x; + x = [1, 2, ...[3, 4]]; + assert(x.toString(), "1,2,3,4"); + + x = [ ...[ , ] ]; + assert(Object.getOwnPropertyNames(x).toString(), "0,length"); +} + +function test_function_length() +{ + assert( ((a, b = 1, c) => {}).length, 1); + assert( (([a,b]) => {}).length, 1); + assert( (({a,b}) => {}).length, 1); + assert( ((c, [a,b] = 1, d) => {}).length, 1); +} + +function test_argument_scope() +{ + var f; + var c = "global"; + + f = function(a = eval("var arguments")) {}; + assert_throws(SyntaxError, f); + + f = function(a = eval("1"), b = arguments[0]) { return b; }; + assert(f(12), 12); + + f = function(a, b = arguments[0]) { return b; }; + assert(f(12), 12); + + f = function(a, b = () => arguments) { return b; }; + assert(f(12)()[0], 12); + + f = function(a = eval("1"), b = () => arguments) { return b; }; + assert(f(12)()[0], 12); + + (function() { + "use strict"; + f = function(a = this) { return a; }; + assert(f.call(123), 123); + + f = function f(a = f) { return a; }; + assert(f(), f); + + f = function f(a = eval("f")) { return a; }; + assert(f(), f); + })(); + + f = (a = eval("var c = 1"), probe = () => c) => { + var c = 2; + assert(c, 2); + assert(probe(), 1); + } + f(); + + f = (a = eval("var arguments = 1"), probe = () => arguments) => { + var arguments = 2; + assert(arguments, 2); + assert(probe(), 1); + } + f(); + + f = function f(a = eval("var c = 1"), b = c, probe = () => c) { + assert(b, 1); + assert(c, 1); + assert(probe(), 1) + } + f(); + + assert(c, "global"); + f = function f(a, b = c, probe = () => c) { + eval("var c = 1"); + assert(c, 1); + assert(b, "global"); + assert(probe(), "global") + } + f(); + assert(c, "global"); + + f = function f(a = eval("var c = 1"), probe = (d = eval("c")) => d) { + assert(probe(), 1) + } + f(); +} + +function test_function_expr_name() +{ + var f; + + /* non strict mode test : assignment to the function name silently + fails */ + + f = function myfunc() { + myfunc = 1; + return myfunc; + }; + assert(f(), f); + + f = function myfunc() { + myfunc = 1; + (() => { + myfunc = 1; + })(); + return myfunc; + }; + assert(f(), f); + + f = function myfunc() { + eval("myfunc = 1"); + return myfunc; + }; + assert(f(), f); + + /* strict mode test : assignment to the function name raises a + TypeError exception */ + + f = function myfunc() { + "use strict"; + myfunc = 1; + }; + assert_throws(TypeError, f); + + f = function myfunc() { + "use strict"; + (() => { + myfunc = 1; + })(); + }; + assert_throws(TypeError, f); + + f = function myfunc() { + "use strict"; + eval("myfunc = 1"); + }; + assert_throws(TypeError, f); +} + +function test_parse_semicolon() +{ + /* 'yield' or 'await' may not be considered as a token if the + previous ';' is missing */ + function *f() + { + function func() { + } + yield 1; + var h = x => x + 1 + yield 2; + } + async function g() + { + function func() { + } + await 1; + var h = x => x + 1 + await 2; + } +} + +/* optional chaining tests not present in test262 */ +function test_optional_chaining() +{ + var a, z; + z = null; + a = { b: { c: 2 } }; + assert(delete z?.b.c, true); + assert(delete a?.b.c, true); + assert(JSON.stringify(a), '{"b":{}}', "optional chaining delete"); + + a = { b: { c: 2 } }; + assert(delete z?.b["c"], true); + assert(delete a?.b["c"], true); + assert(JSON.stringify(a), '{"b":{}}'); + + a = { + b() { return this._b; }, + _b: { c: 42 } + }; + + assert((a?.b)().c, 42); + + assert((a?.["b"])().c, 42); +} + +test_op1(); +test_cvt(); +test_eq(); +test_inc_dec(); +test_op2(); +test_delete(); +test_prototype(); +test_arguments(); +test_class(); +test_template(); +test_template_skip(); +test_object_literal(); +test_regexp_skip(); +test_labels(); +test_destructuring(); +test_spread(); +test_function_length(); +test_argument_scope(); +test_function_expr_name(); +test_parse_semicolon(); +test_optional_chaining(); diff --git a/deps/quickjs/tests/test_loop.js b/deps/quickjs/tests/test_loop.js new file mode 100644 index 0000000..084d658 --- /dev/null +++ b/deps/quickjs/tests/test_loop.js @@ -0,0 +1,392 @@ +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function test_while() +{ + var i, c; + i = 0; + c = 0; + while (i < 3) { + c++; + i++; + } + assert(c === 3); +} + +function test_while_break() +{ + var i, c; + i = 0; + c = 0; + while (i < 3) { + c++; + if (i == 1) + break; + i++; + } + assert(c === 2 && i === 1); +} + +function test_do_while() +{ + var i, c; + i = 0; + c = 0; + do { + c++; + i++; + } while (i < 3); + assert(c === 3 && i === 3); +} + +function test_for() +{ + var i, c; + c = 0; + for(i = 0; i < 3; i++) { + c++; + } + assert(c === 3 && i === 3); + + c = 0; + for(var j = 0; j < 3; j++) { + c++; + } + assert(c === 3 && j === 3); +} + +function test_for_in() +{ + var i, tab, a, b; + + tab = []; + for(i in {x:1, y: 2}) { + tab.push(i); + } + assert(tab.toString(), "x,y", "for_in"); + + /* prototype chain test */ + a = {x:2, y: 2, "1": 3}; + b = {"4" : 3 }; + Object.setPrototypeOf(a, b); + tab = []; + for(i in a) { + tab.push(i); + } + assert(tab.toString(), "1,x,y,4", "for_in"); + + /* non enumerable properties hide enumerables ones in the + prototype chain */ + a = {y: 2, "1": 3}; + Object.defineProperty(a, "x", { value: 1 }); + b = {"x" : 3 }; + Object.setPrototypeOf(a, b); + tab = []; + for(i in a) { + tab.push(i); + } + assert(tab.toString(), "1,y", "for_in"); + + /* array optimization */ + a = []; + for(i = 0; i < 10; i++) + a.push(i); + tab = []; + for(i in a) { + tab.push(i); + } + assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in"); + + /* iterate with a field */ + a={x:0}; + tab = []; + for(a.x in {x:1, y: 2}) { + tab.push(a.x); + } + assert(tab.toString(), "x,y", "for_in"); + + /* iterate with a variable field */ + a=[0]; + tab = []; + for(a[0] in {x:1, y: 2}) { + tab.push(a[0]); + } + assert(tab.toString(), "x,y", "for_in"); + + /* variable definition in the for in */ + tab = []; + for(var j in {x:1, y: 2}) { + tab.push(j); + } + assert(tab.toString(), "x,y", "for_in"); + + /* variable assigment in the for in */ + tab = []; + for(var k = 2 in {x:1, y: 2}) { + tab.push(k); + } + assert(tab.toString(), "x,y", "for_in"); +} + +function test_for_in2() +{ + var i; + tab = []; + for(i in {x:1, y: 2, z:3}) { + if (i === "y") + continue; + tab.push(i); + } + assert(tab.toString() == "x,z"); + + tab = []; + for(i in {x:1, y: 2, z:3}) { + if (i === "z") + break; + tab.push(i); + } + assert(tab.toString() == "x,y"); +} + +function test_for_in_proxy() { + let removed_key = ""; + let target = {} + let proxy = new Proxy(target, { + ownKeys: function() { + return ["a", "b", "c"]; + }, + getOwnPropertyDescriptor: function(target, key) { + if (removed_key != "" && key == removed_key) + return undefined; + else + return { enumerable: true, configurable: true, value: this[key] }; + } + }); + let str = ""; + for(let o in proxy) { + str += " " + o; + if (o == "a") + removed_key = "b"; + } + assert(str == " a c"); +} + +function test_for_break() +{ + var i, c; + c = 0; + L1: for(i = 0; i < 3; i++) { + c++; + if (i == 0) + continue; + while (1) { + break L1; + } + } + assert(c === 2 && i === 1); +} + +function test_switch1() +{ + var i, a, s; + s = ""; + for(i = 0; i < 3; i++) { + a = "?"; + switch(i) { + case 0: + a = "a"; + break; + case 1: + a = "b"; + break; + default: + a = "c"; + break; + } + s += a; + } + assert(s === "abc" && i === 3); +} + +function test_switch2() +{ + var i, a, s; + s = ""; + for(i = 0; i < 4; i++) { + a = "?"; + switch(i) { + case 0: + a = "a"; + break; + case 1: + a = "b"; + break; + case 2: + continue; + default: + a = "" + i; + break; + } + s += a; + } + assert(s === "ab3" && i === 4); +} + +function test_try_catch1() +{ + try { + throw "hello"; + } catch (e) { + assert(e, "hello", "catch"); + return; + } + assert(false, "catch"); +} + +function test_try_catch2() +{ + var a; + try { + a = 1; + } catch (e) { + a = 2; + } + assert(a, 1, "catch"); +} + +function test_try_catch3() +{ + var s; + s = ""; + try { + s += "t"; + } catch (e) { + s += "c"; + } finally { + s += "f"; + } + assert(s, "tf", "catch"); +} + +function test_try_catch4() +{ + var s; + s = ""; + try { + s += "t"; + throw "c"; + } catch (e) { + s += e; + } finally { + s += "f"; + } + assert(s, "tcf", "catch"); +} + +function test_try_catch5() +{ + var s; + s = ""; + for(;;) { + try { + s += "t"; + break; + s += "b"; + } finally { + s += "f"; + } + } + assert(s, "tf", "catch"); +} + +function test_try_catch6() +{ + function f() { + try { + s += 't'; + return 1; + } finally { + s += "f"; + } + } + var s = ""; + assert(f() === 1); + assert(s, "tf", "catch6"); +} + +function test_try_catch7() +{ + var s; + s = ""; + + try { + try { + s += "t"; + throw "a"; + } finally { + s += "f"; + } + } catch(e) { + s += e; + } finally { + s += "g"; + } + assert(s, "tfag", "catch"); +} + +function test_try_catch8() +{ + var i, s; + + s = ""; + for(var i in {x:1, y:2}) { + try { + s += i; + throw "a"; + } catch (e) { + s += e; + } finally { + s += "f"; + } + } + assert(s === "xafyaf"); +} + +test_while(); +test_while_break(); +test_do_while(); +test_for(); +test_for_break(); +test_switch1(); +test_switch2(); +test_for_in(); +test_for_in2(); +test_for_in_proxy(); + +test_try_catch1(); +test_try_catch2(); +test_try_catch3(); +test_try_catch4(); +test_try_catch5(); +test_try_catch6(); +test_try_catch7(); +test_try_catch8(); diff --git a/deps/quickjs/tests/test_op_overloading.js b/deps/quickjs/tests/test_op_overloading.js new file mode 100644 index 0000000..d08a85e --- /dev/null +++ b/deps/quickjs/tests/test_op_overloading.js @@ -0,0 +1,207 @@ +"use strict"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +/* operators overloading with Operators.create() */ +function test_operators_create() { + class Vec2 + { + constructor(x, y) { + this.x = x; + this.y = y; + } + static mul_scalar(p1, a) { + var r = new Vec2(); + r.x = p1.x * a; + r.y = p1.y * a; + return r; + } + toString() { + return "Vec2(" + this.x + "," + this.y + ")"; + } + } + + Vec2.prototype[Symbol.operatorSet] = Operators.create( + { + "+"(p1, p2) { + var r = new Vec2(); + r.x = p1.x + p2.x; + r.y = p1.y + p2.y; + return r; + }, + "-"(p1, p2) { + var r = new Vec2(); + r.x = p1.x - p2.x; + r.y = p1.y - p2.y; + return r; + }, + "=="(a, b) { + return a.x == b.x && a.y == b.y; + }, + "<"(a, b) { + var r; + /* lexicographic order */ + if (a.x == b.x) + r = (a.y < b.y); + else + r = (a.x < b.x); + return r; + }, + "++"(a) { + var r = new Vec2(); + r.x = a.x + 1; + r.y = a.y + 1; + return r; + } + }, + { + left: Number, + "*"(a, b) { + return Vec2.mul_scalar(b, a); + } + }, + { + right: Number, + "*"(a, b) { + return Vec2.mul_scalar(a, b); + } + }); + + var a = new Vec2(1, 2); + var b = new Vec2(3, 4); + var r; + + r = a * 2 + 3 * b; + assert(r.x === 11 && r.y === 16); + assert(a == a, true); + assert(a == b, false); + assert(a != a, false); + assert(a < b, true); + assert(a <= b, true); + assert(b < a, false); + assert(b <= a, false); + assert(a <= a, true); + assert(a >= a, true); + a++; + assert(a.x === 2 && a.y === 3); + r = ++a; + assert(a.x === 3 && a.y === 4); + assert(r === a); +} + +/* operators overloading thru inheritance */ +function test_operators() +{ + var Vec2; + + function mul_scalar(p1, a) { + var r = new Vec2(); + r.x = p1.x * a; + r.y = p1.y * a; + return r; + } + + var vec2_ops = Operators({ + "+"(p1, p2) { + var r = new Vec2(); + r.x = p1.x + p2.x; + r.y = p1.y + p2.y; + return r; + }, + "-"(p1, p2) { + var r = new Vec2(); + r.x = p1.x - p2.x; + r.y = p1.y - p2.y; + return r; + }, + "=="(a, b) { + return a.x == b.x && a.y == b.y; + }, + "<"(a, b) { + var r; + /* lexicographic order */ + if (a.x == b.x) + r = (a.y < b.y); + else + r = (a.x < b.x); + return r; + }, + "++"(a) { + var r = new Vec2(); + r.x = a.x + 1; + r.y = a.y + 1; + return r; + } + }, + { + left: Number, + "*"(a, b) { + return mul_scalar(b, a); + } + }, + { + right: Number, + "*"(a, b) { + return mul_scalar(a, b); + } + }); + + Vec2 = class Vec2 extends vec2_ops + { + constructor(x, y) { + super(); + this.x = x; + this.y = y; + } + toString() { + return "Vec2(" + this.x + "," + this.y + ")"; + } + } + + var a = new Vec2(1, 2); + var b = new Vec2(3, 4); + var r; + + r = a * 2 + 3 * b; + assert(r.x === 11 && r.y === 16); + assert(a == a, true); + assert(a == b, false); + assert(a != a, false); + assert(a < b, true); + assert(a <= b, true); + assert(b < a, false); + assert(b <= a, false); + assert(a <= a, true); + assert(a >= a, true); + a++; + assert(a.x === 2 && a.y === 3); + r = ++a; + assert(a.x === 3 && a.y === 4); + assert(r === a); +} + +function test_default_op() +{ + assert(Object(1) + 2, 3); + assert(Object(1) + true, 2); + assert(-Object(1), -1); +} + +test_operators_create(); +test_operators(); +test_default_op(); diff --git a/deps/quickjs/tests/test_qjscalc.js b/deps/quickjs/tests/test_qjscalc.js new file mode 100644 index 0000000..1483466 --- /dev/null +++ b/deps/quickjs/tests/test_qjscalc.js @@ -0,0 +1,256 @@ +"use math"; +"use strict"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +function assertThrows(err, func) +{ + var ex; + ex = false; + try { + func(); + } catch(e) { + ex = true; + assert(e instanceof err); + } + assert(ex, true, "exception expected"); +} + +// load more elaborate version of assert if available +try { __loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function pow(a, n) +{ + var r, i; + r = 1; + for(i = 0; i < n; i++) + r *= a; + return r; +} + +function test_integer() +{ + var a, r; + a = pow(3, 100); + assert((a - 1) != a); + assert(a == 515377520732011331036461129765621272702107522001); + assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1); + assert(Integer.isInteger(1) === true); + assert(Integer.isInteger(1.0) === false); + + assert(Integer.floorLog2(0) === -1); + assert(Integer.floorLog2(7) === 2); + + r = 1 << 31; + assert(r, 2147483648, "1 << 31 === 2147483648"); + + r = 1 << 32; + assert(r, 4294967296, "1 << 32 === 4294967296"); + + r = (1 << 31) < 0; + assert(r, false, "(1 << 31) < 0 === false"); + + assert(typeof 1 === "number"); + assert(typeof 9007199254740991 === "number"); + assert(typeof 9007199254740992 === "bigint"); +} + +function test_float() +{ + assert(typeof 1.0 === "bigfloat"); + assert(1 == 1.0); + assert(1 !== 1.0); +} + +/* jscalc tests */ + +function test_modulo() +{ + var i, p, a, b; + + /* Euclidian modulo operator */ + assert((-3) % 2 == 1); + assert(3 % (-2) == 1); + + p = 101; + for(i = 1; i < p; i++) { + a = Integer.invmod(i, p); + assert(a >= 0 && a < p); + assert((i * a) % p == 1); + } + + assert(Integer.isPrime(2^107-1)); + assert(!Integer.isPrime((2^107-1) * (2^89-1))); + a = Integer.factor((2^89-1)*2^3*11*13^2*1009); + assert(a == [ 2,2,2,11,13,13,1009,618970019642690137449562111 ]); +} + +function test_fraction() +{ + assert((1/3 + 1).toString(), "4/3") + assert((2/3)^30, 1073741824/205891132094649); + assert(1/3 < 2/3); + assert(1/3 < 1); + assert(1/3 == 1.0/3); + assert(1.0/3 < 2/3); +} + +function test_mod() +{ + var a, b, p; + + a = Mod(3, 101); + b = Mod(-1, 101); + assert((a + b) == Mod(2, 101)); + assert(a ^ 100 == Mod(1, 101)); + + p = 2 ^ 607 - 1; /* mersenne prime */ + a = Mod(3, p) ^ (p - 1); + assert(a == Mod(1, p)); +} + +function test_polynomial() +{ + var a, b, q, r, t, i; + a = (1 + X) ^ 4; + assert(a == X^4+4*X^3+6*X^2+4*X+1); + + r = (1 + X); + q = (1+X+X^2); + b = (1 - X^2); + a = q * b + r; + t = Polynomial.divrem(a, b); + assert(t[0] == q); + assert(t[1] == r); + + a = 1 + 2*X + 3*X^2; + assert(a.apply(0.1) == 1.23); + + a = 1-2*X^2+2*X^3; + assert(deriv(a) == (6*X^2-4*X)); + assert(deriv(integ(a)) == a); + + a = (X-1)*(X-2)*(X-3)*(X-4)*(X-0.1); + r = polroots(a); + for(i = 0; i < r.length; i++) { + b = abs(a.apply(r[i])); + assert(b <= 1e-13); + } +} + +function test_poly_mod() +{ + var a, p; + + /* modulo using polynomials */ + p = X^2 + X + 1; + a = PolyMod(3+X, p) ^ 10; + assert(a == PolyMod(-3725*X-18357, p)); + + a = PolyMod(1/X, 1+X^2); + assert(a == PolyMod(-X, X^2+1)); +} + +function test_rfunc() +{ + var a; + a = (X+1)/((X+1)*(X-1)); + assert(a == 1/(X-1)); + a = (X + 2) / (X - 2); + assert(a.apply(1/3) == -7/5); + + assert(deriv((X^2-X+1)/(X-1)) == (X^2-2*X)/(X^2-2*X+1)); +} + +function test_series() +{ + var a, b; + a = 1+X+O(X^5); + b = a.inverse(); + assert(b == 1-X+X^2-X^3+X^4+O(X^5)); + assert(deriv(b) == -1+2*X-3*X^2+4*X^3+O(X^4)); + assert(deriv(integ(b)) == b); + + a = Series(1/(1-X), 5); + assert(a == 1+X+X^2+X^3+X^4+O(X^5)); + b = a.apply(0.1); + assert(b == 1.1111); + + assert(exp(3*X^2+O(X^10)) == 1+3*X^2+9/2*X^4+9/2*X^6+27/8*X^8+O(X^10)); + assert(sin(X+O(X^6)) == X-1/6*X^3+1/120*X^5+O(X^6)); + assert(cos(X+O(X^6)) == 1-1/2*X^2+1/24*X^4+O(X^6)); + assert(tan(X+O(X^8)) == X+1/3*X^3+2/15*X^5+17/315*X^7+O(X^8)); + assert((1+X+O(X^6))^(2+X) == 1+2*X+2*X^2+3/2*X^3+5/6*X^4+5/12*X^5+O(X^6)); +} + +function test_matrix() +{ + var a, b, r; + a = [[1, 2],[3, 4]]; + b = [3, 4]; + r = a * b; + assert(r == [11, 25]); + r = (a^-1) * 2; + assert(r == [[-4, 2],[3, -1]]); + + assert(norm2([1,2,3]) == 14); + + assert(diag([1,2,3]) == [ [ 1, 0, 0 ], [ 0, 2, 0 ], [ 0, 0, 3 ] ]); + assert(trans(a) == [ [ 1, 3 ], [ 2, 4 ] ]); + assert(trans([1,2,3]) == [[1,2,3]]); + assert(trace(a) == 5); + + assert(charpoly(Matrix.hilbert(4)) == X^4-176/105*X^3+3341/12600*X^2-41/23625*X+1/6048000); + assert(det(Matrix.hilbert(4)) == 1/6048000); + + a = [[1,2,1],[-2,-3,1],[3,5,0]]; + assert(rank(a) == 2); + assert(ker(a) == [ [ 5 ], [ -3 ], [ 1 ] ]); + + assert(dp([1, 2, 3], [3, -4, -7]) === -26); + assert(cp([1, 2, 3], [3, -4, -7]) == [ -2, 16, -10 ]); +} + +function assert_eq(a, ref) +{ + assert(abs(a / ref - 1.0) <= 1e-15); +} + +function test_trig() +{ + assert_eq(sin(1/2), 0.479425538604203); + assert_eq(sin(2+3*I), 9.154499146911428-4.168906959966565*I); + assert_eq(cos(2+3*I), -4.189625690968807-9.109227893755337*I); + assert_eq((2+0.5*I)^(1.1-0.5*I), 2.494363021357619-0.23076804554558092*I); + assert_eq(sqrt(2*I), 1 + I); +} + +test_integer(); +test_float(); + +test_modulo(); +test_fraction(); +test_mod(); +test_polynomial(); +test_poly_mod(); +test_rfunc(); +test_series(); +test_matrix(); +test_trig(); diff --git a/deps/quickjs/tests/test_std.js b/deps/quickjs/tests/test_std.js new file mode 100644 index 0000000..6fb94c2 --- /dev/null +++ b/deps/quickjs/tests/test_std.js @@ -0,0 +1,304 @@ +#! (shebang test) +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +// load more elaborate version of assert if available +try { std.loadScript("test_assert.js"); } catch(e) {} + +/*----------------*/ + +function test_printf() +{ + assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc"); + assert(std.sprintf("%010d", 123), "0000000123"); + assert(std.sprintf("%x", -2), "fffffffe"); + assert(std.sprintf("%lx", -2), "fffffffffffffffe"); + assert(std.sprintf("%10.1f", 2.1), " 2.1"); + assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13"); + assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff"); +} + +function test_file1() +{ + var f, len, str, size, buf, ret, i, str1; + + f = std.tmpfile(); + str = "hello world\n"; + f.puts(str); + + f.seek(0, std.SEEK_SET); + str1 = f.readAsString(); + assert(str1 === str); + + f.seek(0, std.SEEK_END); + size = f.tell(); + assert(size === str.length); + + f.seek(0, std.SEEK_SET); + + buf = new Uint8Array(size); + ret = f.read(buf.buffer, 0, size); + assert(ret === size); + for(i = 0; i < size; i++) + assert(buf[i] === str.charCodeAt(i)); + + f.close(); +} + +function test_file2() +{ + var f, str, i, size; + f = std.tmpfile(); + str = "hello world\n"; + size = str.length; + for(i = 0; i < size; i++) + f.putByte(str.charCodeAt(i)); + f.seek(0, std.SEEK_SET); + for(i = 0; i < size; i++) { + assert(str.charCodeAt(i) === f.getByte()); + } + assert(f.getByte() === -1); + f.close(); +} + +function test_getline() +{ + var f, line, line_count, lines, i; + + lines = ["hello world", "line 1", "line 2" ]; + f = std.tmpfile(); + for(i = 0; i < lines.length; i++) { + f.puts(lines[i], "\n"); + } + + f.seek(0, std.SEEK_SET); + assert(!f.eof()); + line_count = 0; + for(;;) { + line = f.getline(); + if (line === null) + break; + assert(line == lines[line_count]); + line_count++; + } + assert(f.eof()); + assert(line_count === lines.length); + + f.close(); +} + +function test_popen() +{ + var str, f, fname = "tmp_file.txt"; + var content = "hello world"; + + f = std.open(fname, "w"); + f.puts(content); + f.close(); + + /* test loadFile */ + assert(std.loadFile(fname), content); + + /* execute the 'cat' shell command */ + f = std.popen("cat " + fname, "r"); + str = f.readAsString(); + f.close(); + + assert(str, content); + + os.remove(fname); +} + +function test_ext_json() +{ + var expected, input, obj; + expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}'; + input = `{ "x":false, /*comments are allowed */ + "y":true, // also a comment + z2:null, // unquoted property names + "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal + "s":"str",} // trailing comma in objects and arrays + `; + obj = std.parseExtJSON(input); + assert(JSON.stringify(obj), expected); +} + +function test_os() +{ + var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path; + + assert(os.isatty(0)); + + fdir = "test_tmp_dir"; + fname = "tmp_file.txt"; + fpath = fdir + "/" + fname; + link_path = fdir + "/test_link"; + + os.remove(link_path); + os.remove(fpath); + os.remove(fdir); + + err = os.mkdir(fdir, 0o755); + assert(err === 0); + + fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC); + assert(fd >= 0); + + buf = new Uint8Array(10); + for(i = 0; i < buf.length; i++) + buf[i] = i; + assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length); + + assert(os.seek(fd, 0, std.SEEK_SET) === 0); + buf2 = new Uint8Array(buf.length); + assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length); + + for(i = 0; i < buf.length; i++) + assert(buf[i] == buf2[i]); + + if (typeof BigInt !== "undefined") { + assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6)); + assert(os.read(fd, buf2.buffer, 0, 1) === 1); + assert(buf[6] == buf2[0]); + } + + assert(os.close(fd) === 0); + + [files, err] = os.readdir(fdir); + assert(err, 0); + assert(files.indexOf(fname) >= 0); + + fdate = 10000; + + err = os.utimes(fpath, fdate, fdate); + assert(err, 0); + + [st, err] = os.stat(fpath); + assert(err, 0); + assert(st.mode & os.S_IFMT, os.S_IFREG); + assert(st.mtime, fdate); + + err = os.symlink(fname, link_path); + assert(err === 0); + + [st, err] = os.lstat(link_path); + assert(err, 0); + assert(st.mode & os.S_IFMT, os.S_IFLNK); + + [buf, err] = os.readlink(link_path); + assert(err, 0); + assert(buf, fname); + + assert(os.remove(link_path) === 0); + + [buf, err] = os.getcwd(); + assert(err, 0); + + [buf2, err] = os.realpath("."); + assert(err, 0); + + assert(buf, buf2); + + assert(os.remove(fpath) === 0); + + fd = os.open(fpath, os.O_RDONLY); + assert(fd < 0); + + assert(os.remove(fdir) === 0); +} + +function test_os_exec() +{ + var ret, fds, pid, f, status; + + ret = os.exec(["true"]); + assert(ret, 0); + + ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false }); + assert(ret, 1); + + fds = os.pipe(); + pid = os.exec(["sh", "-c", "echo $FOO"], { + stdout: fds[1], + block: false, + env: { FOO: "hello" }, + } ); + assert(pid >= 0); + os.close(fds[1]); /* close the write end (as it is only in the child) */ + f = std.fdopen(fds[0], "r"); + assert(f.getline(), "hello"); + assert(f.getline(), null); + f.close(); + [ret, status] = os.waitpid(pid, 0); + assert(ret, pid); + assert(status & 0x7f, 0); /* exited */ + assert(status >> 8, 0); /* exit code */ + + pid = os.exec(["cat"], { block: false } ); + assert(pid >= 0); + os.kill(pid, os.SIGQUIT); + [ret, status] = os.waitpid(pid, 0); + assert(ret, pid); + assert(status & 0x7f, os.SIGQUIT); +} + +function test_timer() +{ + var th, i; + + /* just test that a timer can be inserted and removed */ + th = []; + for(i = 0; i < 3; i++) + th[i] = os.setTimeout(function () { }, 1000); + for(i = 0; i < 3; i++) + os.clearTimeout(th[i]); +} + +/* test closure variable handling when freeing asynchronous + function */ +function test_async_gc() +{ + (async function run () { + let obj = {} + + let done = () => { + obj + std.gc(); + } + + Promise.resolve().then(done) + + const p = new Promise(() => {}) + + await p + })(); +} + +test_printf(); +test_file1(); +test_file2(); +test_getline(); +test_popen(); +test_os(); +test_os_exec(); +test_timer(); +test_ext_json(); +test_async_gc(); + diff --git a/deps/quickjs/tests/test_worker.js b/deps/quickjs/tests/test_worker.js new file mode 100644 index 0000000..4b52bf8 --- /dev/null +++ b/deps/quickjs/tests/test_worker.js @@ -0,0 +1,62 @@ +/* os.Worker API test */ +import * as std from "std"; +import * as os from "os"; + +function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +var worker; + +function test_worker() +{ + var counter; + + worker = new os.Worker("./test_worker_module.js"); + + counter = 0; + worker.onmessage = function (e) { + var ev = e.data; +// print("recv", JSON.stringify(ev)); + switch(ev.type) { + case "num": + assert(ev.num, counter); + counter++; + if (counter == 10) { + /* test SharedArrayBuffer modification */ + let sab = new SharedArrayBuffer(10); + let buf = new Uint8Array(sab); + worker.postMessage({ type: "sab", buf: buf }); + } + break; + case "sab_done": + { + let buf = ev.buf; + /* check that the SharedArrayBuffer was modified */ + assert(buf[2], 10); + worker.postMessage({ type: "abort" }); + } + break; + case "done": + /* terminate */ + worker.onmessage = null; + break; + } + }; +} + + +test_worker(); diff --git a/deps/quickjs/tests/test_worker_module.js b/deps/quickjs/tests/test_worker_module.js new file mode 100644 index 0000000..f19600a --- /dev/null +++ b/deps/quickjs/tests/test_worker_module.js @@ -0,0 +1,32 @@ +/* Worker code for test_worker.js */ +import * as std from "std"; +import * as os from "os"; + +var parent = os.Worker.parent; + +function handle_msg(e) { + var ev = e.data; + // print("child_recv", JSON.stringify(ev)); + switch(ev.type) { + case "abort": + parent.postMessage({ type: "done" }); + parent.onMessage = null; /* terminate the worker */ + break; + case "sab": + /* modify the SharedArrayBuffer */ + ev.buf[2] = 10; + parent.postMessage({ type: "sab_done", buf: ev.buf }); + break; + } +} + +function worker_main() { + var i; + + parent.onmessage = handle_msg; + for(i = 0; i < 10; i++) { + parent.postMessage({ type: "num", num: i }); + } +} + +worker_main(); diff --git a/deps/quickjs/unicode_download.sh b/deps/quickjs/unicode_download.sh new file mode 100755 index 0000000..35daf0e --- /dev/null +++ b/deps/quickjs/unicode_download.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -e + +url="ftp://ftp.unicode.org/Public/15.0.0/ucd" +emoji_url="${url}/emoji/emoji-data.txt" + +files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ +SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \ +UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \ +PropertyValueAliases.txt" + +mkdir -p unicode + +for f in $files; do + g="${url}/${f}" + wget $g -O unicode/$f +done + +wget $emoji_url -O unicode/emoji-data.txt diff --git a/deps/quickjs/unicode_gen.c b/deps/quickjs/unicode_gen.c new file mode 100644 index 0000000..54da2c1 --- /dev/null +++ b/deps/quickjs/unicode_gen.c @@ -0,0 +1,3145 @@ +/* + * Generation of Unicode tables + * + * Copyright (c) 2017-2018 Fabrice Bellard + * Copyright (c) 2017-2018 Charlie Gordon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cutils.h" + +/* define it to be able to test unicode.c */ +//#define USE_TEST +/* profile tests */ +//#define PROFILE + +//#define DUMP_CASE_CONV_TABLE +//#define DUMP_TABLE_SIZE +//#define DUMP_CC_TABLE +//#define DUMP_DECOMP_TABLE +//#define DUMP_CASE_FOLDING_SPECIAL_CASES + +/* Ideas: + - Generalize run length encoding + index for all tables + - remove redundant tables for ID_start, ID_continue, Case_Ignorable, Cased + + Case conversion: + - use a single entry for consecutive U/LF runs + - allow EXT runs of length > 1 + + Decomposition: + - Greek lower case (+1f10/1f10) ? + - allow holes in B runs + - suppress more upper / lower case redundancy +*/ + +#ifdef USE_TEST +#include "libunicode.c" +#endif + +#define CHARCODE_MAX 0x10ffff +#define CC_LEN_MAX 3 + +void *mallocz(size_t size) +{ + void *ptr; + ptr = malloc(size); + memset(ptr, 0, size); + return ptr; +} + +const char *get_field(const char *p, int n) +{ + int i; + for(i = 0; i < n; i++) { + while (*p != ';' && *p != '\0') + p++; + if (*p == '\0') + return NULL; + p++; + } + return p; +} + +const char *get_field_buf(char *buf, size_t buf_size, const char *p, int n) +{ + char *q; + p = get_field(p, n); + q = buf; + while (*p != ';' && *p != '\0') { + if ((q - buf) < buf_size - 1) + *q++ = *p; + p++; + } + *q = '\0'; + return buf; +} + +void add_char(int **pbuf, int *psize, int *plen, int c) +{ + int len, size, *buf; + buf = *pbuf; + size = *psize; + len = *plen; + if (len >= size) { + size = *psize; + size = max_int(len + 1, size * 3 / 2); + buf = realloc(buf, sizeof(buf[0]) * size); + *pbuf = buf; + *psize = size; + } + buf[len++] = c; + *plen = len; +} + +int *get_field_str(int *plen, const char *str, int n) +{ + const char *p; + int *buf, len, size; + p = get_field(str, n); + if (!p) { + *plen = 0; + return NULL; + } + len = 0; + size = 0; + buf = NULL; + for(;;) { + while (isspace(*p)) + p++; + if (!isxdigit(*p)) + break; + add_char(&buf, &size, &len, strtoul(p, (char **)&p, 16)); + } + *plen = len; + return buf; +} + +char *get_line(char *buf, int buf_size, FILE *f) +{ + int len; + if (!fgets(buf, buf_size, f)) + return NULL; + len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + return buf; +} + +#define UNICODE_GENERAL_CATEGORY + +typedef enum { +#define DEF(id, str) GCAT_ ## id, +#include "unicode_gen_def.h" +#undef DEF + GCAT_COUNT, +} UnicodeGCEnum1; + +static const char *unicode_gc_name[] = { +#define DEF(id, str) #id, +#include "unicode_gen_def.h" +#undef DEF +}; + +static const char *unicode_gc_short_name[] = { +#define DEF(id, str) str, +#include "unicode_gen_def.h" +#undef DEF +}; + +#undef UNICODE_GENERAL_CATEGORY + +#define UNICODE_SCRIPT + +typedef enum { +#define DEF(id, str) SCRIPT_ ## id, +#include "unicode_gen_def.h" +#undef DEF + SCRIPT_COUNT, +} UnicodeScriptEnum1; + +static const char *unicode_script_name[] = { +#define DEF(id, str) #id, +#include "unicode_gen_def.h" +#undef DEF +}; + +const char *unicode_script_short_name[] = { +#define DEF(id, str) str, +#include "unicode_gen_def.h" +#undef DEF +}; + +#undef UNICODE_SCRIPT + +#define UNICODE_PROP_LIST + +typedef enum { +#define DEF(id, str) PROP_ ## id, +#include "unicode_gen_def.h" +#undef DEF + PROP_COUNT, +} UnicodePropEnum1; + +static const char *unicode_prop_name[] = { +#define DEF(id, str) #id, +#include "unicode_gen_def.h" +#undef DEF +}; + +static const char *unicode_prop_short_name[] = { +#define DEF(id, str) str, +#include "unicode_gen_def.h" +#undef DEF +}; + +#undef UNICODE_PROP_LIST + +typedef struct { + /* case conv */ + uint8_t u_len; + uint8_t l_len; + uint8_t f_len; + int u_data[CC_LEN_MAX]; /* to upper case */ + int l_data[CC_LEN_MAX]; /* to lower case */ + int f_data[CC_LEN_MAX]; /* to case folding */ + + uint8_t combining_class; + uint8_t is_compat:1; + uint8_t is_excluded:1; + uint8_t general_category; + uint8_t script; + uint8_t script_ext_len; + uint8_t *script_ext; + uint32_t prop_bitmap_tab[3]; + /* decomposition */ + int decomp_len; + int *decomp_data; +} CCInfo; + +CCInfo *unicode_db; + +int find_name(const char **tab, int tab_len, const char *name) +{ + int i, len, name_len; + const char *p, *r; + + name_len = strlen(name); + for(i = 0; i < tab_len; i++) { + p = tab[i]; + for(;;) { + r = strchr(p, ','); + if (!r) + len = strlen(p); + else + len = r - p; + if (len == name_len && memcmp(p, name, len) == 0) + return i; + if (!r) + break; + p = r + 1; + } + } + return -1; +} + +static int get_prop(uint32_t c, int prop_idx) +{ + return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1; +} + +static void set_prop(uint32_t c, int prop_idx, int val) +{ + uint32_t mask; + mask = 1U << (prop_idx & 0x1f); + if (val) + unicode_db[c].prop_bitmap_tab[prop_idx >> 5] |= mask; + else + unicode_db[c].prop_bitmap_tab[prop_idx >> 5] &= ~mask; +} + +void parse_unicode_data(const char *filename) +{ + FILE *f; + char line[1024]; + char buf1[256]; + const char *p; + int code, lc, uc, last_code; + CCInfo *ci, *tab = unicode_db; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + last_code = 0; + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#') + continue; + + p = get_field(line, 0); + if (!p) + continue; + code = strtoul(p, NULL, 16); + lc = 0; + uc = 0; + + p = get_field(line, 12); + if (p && *p != ';') { + uc = strtoul(p, NULL, 16); + } + + p = get_field(line, 13); + if (p && *p != ';') { + lc = strtoul(p, NULL, 16); + } + ci = &tab[code]; + if (uc > 0 || lc > 0) { + assert(code <= CHARCODE_MAX); + if (uc > 0) { + assert(ci->u_len == 0); + ci->u_len = 1; + ci->u_data[0] = uc; + } + if (lc > 0) { + assert(ci->l_len == 0); + ci->l_len = 1; + ci->l_data[0] = lc; + } + } + + { + int i; + get_field_buf(buf1, sizeof(buf1), line, 2); + i = find_name(unicode_gc_name, countof(unicode_gc_name), buf1); + if (i < 0) { + fprintf(stderr, "General category '%s' not found\n", + buf1); + exit(1); + } + ci->general_category = i; + } + + p = get_field(line, 3); + if (p && *p != ';' && *p != '\0') { + int cc; + cc = strtoul(p, NULL, 0); + if (cc != 0) { + assert(code <= CHARCODE_MAX); + ci->combining_class = cc; + // printf("%05x: %d\n", code, ci->combining_class); + } + } + + p = get_field(line, 5); + if (p && *p != ';' && *p != '\0') { + int size; + assert(code <= CHARCODE_MAX); + ci->is_compat = 0; + if (*p == '<') { + while (*p != '\0' && *p != '>') + p++; + if (*p == '>') + p++; + ci->is_compat = 1; + } + size = 0; + for(;;) { + while (isspace(*p)) + p++; + if (!isxdigit(*p)) + break; + add_char(&ci->decomp_data, &size, &ci->decomp_len, strtoul(p, (char **)&p, 16)); + } +#if 0 + { + int i; + static int count, d_count; + + printf("%05x: %c", code, ci->is_compat ? 'C': ' '); + for(i = 0; i < ci->decomp_len; i++) + printf(" %05x", ci->decomp_data[i]); + printf("\n"); + count++; + d_count += ci->decomp_len; + // printf("%d %d\n", count, d_count); + } +#endif + } + + p = get_field(line, 9); + if (p && *p == 'Y') { + set_prop(code, PROP_Bidi_Mirrored, 1); + } + + /* handle ranges */ + get_field_buf(buf1, sizeof(buf1), line, 1); + if (strstr(buf1, " Last>")) { + int i; + // printf("range: 0x%x-%0x\n", last_code, code); + assert(ci->decomp_len == 0); + assert(ci->script_ext_len == 0); + for(i = last_code + 1; i < code; i++) { + unicode_db[i] = *ci; + } + } + last_code = code; + } + + fclose(f); +} + +void parse_special_casing(CCInfo *tab, const char *filename) +{ + FILE *f; + char line[1024]; + const char *p; + int code; + CCInfo *ci; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#') + continue; + + p = get_field(line, 0); + if (!p) + continue; + code = strtoul(p, NULL, 16); + assert(code <= CHARCODE_MAX); + ci = &tab[code]; + + p = get_field(line, 4); + if (p) { + /* locale dependent casing */ + while (isspace(*p)) + p++; + if (*p != '#' && *p != '\0') + continue; + } + + + p = get_field(line, 1); + if (p && *p != ';') { + ci->l_len = 0; + for(;;) { + while (isspace(*p)) + p++; + if (*p == ';') + break; + assert(ci->l_len < CC_LEN_MAX); + ci->l_data[ci->l_len++] = strtoul(p, (char **)&p, 16); + } + + if (ci->l_len == 1 && ci->l_data[0] == code) + ci->l_len = 0; + } + + p = get_field(line, 3); + if (p && *p != ';') { + ci->u_len = 0; + for(;;) { + while (isspace(*p)) + p++; + if (*p == ';') + break; + assert(ci->u_len < CC_LEN_MAX); + ci->u_data[ci->u_len++] = strtoul(p, (char **)&p, 16); + } + + if (ci->u_len == 1 && ci->u_data[0] == code) + ci->u_len = 0; + } + } + + fclose(f); +} + +void parse_case_folding(CCInfo *tab, const char *filename) +{ + FILE *f; + char line[1024]; + const char *p; + int code, status; + CCInfo *ci; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#') + continue; + + p = get_field(line, 0); + if (!p) + continue; + code = strtoul(p, NULL, 16); + assert(code <= CHARCODE_MAX); + ci = &tab[code]; + + p = get_field(line, 1); + if (!p) + continue; + /* locale dependent casing */ + while (isspace(*p)) + p++; + status = *p; + if (status != 'C' && status != 'S' && status != 'F') + continue; + + p = get_field(line, 2); + assert(p != NULL); + if (status == 'S') { + /* we always select the simple case folding and assume it + * comes after the full case folding case */ + assert(ci->f_len >= 2); + ci->f_len = 0; + } else { + assert(ci->f_len == 0); + } + for(;;) { + while (isspace(*p)) + p++; + if (*p == ';') + break; + assert(ci->l_len < CC_LEN_MAX); + ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16); + } + } + + fclose(f); +} + +void parse_composition_exclusions(const char *filename) +{ + FILE *f; + char line[4096], *p; + uint32_t c0; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + assert(c0 > 0 && c0 <= CHARCODE_MAX); + unicode_db[c0].is_excluded = TRUE; + } + fclose(f); +} + +void parse_derived_core_properties(const char *filename) +{ + FILE *f; + char line[4096], *p, buf[256], *q; + uint32_t c0, c1, c; + int i; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + if (*p == '.' && p[1] == '.') { + p += 2; + c1 = strtoul(p, (char **)&p, 16); + } else { + c1 = c0; + } + assert(c1 <= CHARCODE_MAX); + p += strspn(p, " \t"); + if (*p == ';') { + p++; + p += strspn(p, " \t"); + q = buf; + while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + i = find_name(unicode_prop_name, + countof(unicode_prop_name), buf); + if (i < 0) { + if (!strcmp(buf, "Grapheme_Link")) + goto next; + fprintf(stderr, "Property not found: %s\n", buf); + exit(1); + } + for(c = c0; c <= c1; c++) { + set_prop(c, i, 1); + } +next: ; + } + } + fclose(f); +} + +void parse_derived_norm_properties(const char *filename) +{ + FILE *f; + char line[4096], *p, buf[256], *q; + uint32_t c0, c1, c; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + if (*p == '.' && p[1] == '.') { + p += 2; + c1 = strtoul(p, (char **)&p, 16); + } else { + c1 = c0; + } + assert(c1 <= CHARCODE_MAX); + p += strspn(p, " \t"); + if (*p == ';') { + p++; + p += strspn(p, " \t"); + q = buf; + while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + if (!strcmp(buf, "Changes_When_NFKC_Casefolded")) { + for(c = c0; c <= c1; c++) { + set_prop(c, PROP_Changes_When_NFKC_Casefolded, 1); + } + } + } + } + fclose(f); +} + +void parse_prop_list(const char *filename) +{ + FILE *f; + char line[4096], *p, buf[256], *q; + uint32_t c0, c1, c; + int i; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + if (*p == '.' && p[1] == '.') { + p += 2; + c1 = strtoul(p, (char **)&p, 16); + } else { + c1 = c0; + } + assert(c1 <= CHARCODE_MAX); + p += strspn(p, " \t"); + if (*p == ';') { + p++; + p += strspn(p, " \t"); + q = buf; + while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + i = find_name(unicode_prop_name, + countof(unicode_prop_name), buf); + if (i < 0) { + fprintf(stderr, "Property not found: %s\n", buf); + exit(1); + } + for(c = c0; c <= c1; c++) { + set_prop(c, i, 1); + } + } + } + fclose(f); +} + +void parse_scripts(const char *filename) +{ + FILE *f; + char line[4096], *p, buf[256], *q; + uint32_t c0, c1, c; + int i; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + if (*p == '.' && p[1] == '.') { + p += 2; + c1 = strtoul(p, (char **)&p, 16); + } else { + c1 = c0; + } + assert(c1 <= CHARCODE_MAX); + p += strspn(p, " \t"); + if (*p == ';') { + p++; + p += strspn(p, " \t"); + q = buf; + while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + i = find_name(unicode_script_name, + countof(unicode_script_name), buf); + if (i < 0) { + fprintf(stderr, "Unknown script: '%s'\n", buf); + exit(1); + } + for(c = c0; c <= c1; c++) + unicode_db[c].script = i; + } + } + fclose(f); +} + +void parse_script_extensions(const char *filename) +{ + FILE *f; + char line[4096], *p, buf[256], *q; + uint32_t c0, c1, c; + int i; + uint8_t script_ext[255]; + int script_ext_len; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@' || *p == '\0') + continue; + c0 = strtoul(p, (char **)&p, 16); + if (*p == '.' && p[1] == '.') { + p += 2; + c1 = strtoul(p, (char **)&p, 16); + } else { + c1 = c0; + } + assert(c1 <= CHARCODE_MAX); + p += strspn(p, " \t"); + script_ext_len = 0; + if (*p == ';') { + p++; + for(;;) { + p += strspn(p, " \t"); + q = buf; + while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') { + if ((q - buf) < sizeof(buf) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + if (buf[0] == '\0') + break; + i = find_name(unicode_script_short_name, + countof(unicode_script_short_name), buf); + if (i < 0) { + fprintf(stderr, "Script not found: %s\n", buf); + exit(1); + } + assert(script_ext_len < sizeof(script_ext)); + script_ext[script_ext_len++] = i; + } + for(c = c0; c <= c1; c++) { + CCInfo *ci = &unicode_db[c]; + ci->script_ext_len = script_ext_len; + ci->script_ext = malloc(sizeof(ci->script_ext[0]) * script_ext_len); + for(i = 0; i < script_ext_len; i++) + ci->script_ext[i] = script_ext[i]; + } + } + } + fclose(f); +} + +void dump_cc_info(CCInfo *ci, int i) +{ + int j; + printf("%05x:", i); + if (ci->u_len != 0) { + printf(" U:"); + for(j = 0; j < ci->u_len; j++) + printf(" %05x", ci->u_data[j]); + } + if (ci->l_len != 0) { + printf(" L:"); + for(j = 0; j < ci->l_len; j++) + printf(" %05x", ci->l_data[j]); + } + if (ci->f_len != 0) { + printf(" F:"); + for(j = 0; j < ci->f_len; j++) + printf(" %05x", ci->f_data[j]); + } + printf("\n"); +} + +void dump_unicode_data(CCInfo *tab) +{ + int i; + CCInfo *ci; + for(i = 0; i <= CHARCODE_MAX; i++) { + ci = &tab[i]; + if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) { + dump_cc_info(ci, i); + } + } +} + +BOOL is_complicated_case(const CCInfo *ci) +{ + return (ci->u_len > 1 || ci->l_len > 1 || + (ci->u_len > 0 && ci->l_len > 0) || + (ci->f_len != ci->l_len) || + (memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0)); +} + +#ifndef USE_TEST +enum { + RUN_TYPE_U, + RUN_TYPE_L, + RUN_TYPE_UF, + RUN_TYPE_LF, + RUN_TYPE_UL, + RUN_TYPE_LSU, + RUN_TYPE_U2L_399_EXT2, + RUN_TYPE_UF_D20, + RUN_TYPE_UF_D1_EXT, + RUN_TYPE_U_EXT, + RUN_TYPE_LF_EXT, + RUN_TYPE_UF_EXT2, + RUN_TYPE_LF_EXT2, + RUN_TYPE_UF_EXT3, +}; +#endif + +const char *run_type_str[] = { + "U", + "L", + "UF", + "LF", + "UL", + "LSU", + "U2L_399_EXT2", + "UF_D20", + "UF_D1_EXT", + "U_EXT", + "LF_EXT", + "UF_EXT2", + "LF_EXT2", + "UF_EXT3", +}; + +typedef struct { + int code; + int len; + int type; + int data; + int ext_len; + int ext_data[3]; + int data_index; /* 'data' coming from the table */ +} TableEntry; + +static int simple_to_lower(CCInfo *tab, int c) +{ + if (tab[c].l_len != 1) + return c; + return tab[c].l_data[0]; +} + +/* code (17), len (7), type (4) */ + +void find_run_type(TableEntry *te, CCInfo *tab, int code) +{ + int is_lower, len; + CCInfo *ci, *ci1, *ci2; + + ci = &tab[code]; + ci1 = &tab[code + 1]; + ci2 = &tab[code + 2]; + te->code = code; + + if (ci->l_len == 1 && ci->l_data[0] == code + 2 && + ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] && + ci->u_len == 0 && + + ci1->l_len == 1 && ci1->l_data[0] == code + 2 && + ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] && + ci1->u_len == 1 && ci1->u_data[0] == code && + + ci2->l_len == 0 && + ci2->f_len == 0 && + ci2->u_len == 1 && ci2->u_data[0] == code) { + te->len = 3; + te->data = 0; + te->type = RUN_TYPE_LSU; + return; + } + + if (is_complicated_case(ci)) { + len = 1; + while (code + len <= CHARCODE_MAX) { + ci1 = &tab[code + len]; + if (ci1->u_len != 1 || + ci1->u_data[0] != ci->u_data[0] + len || + ci1->l_len != 0 || + ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0]) + break; + len++; + } + if (len > 1) { + te->len = len; + te->type = RUN_TYPE_UF; + te->data = ci->u_data[0]; + return; + } + + if (ci->l_len == 0 && + ci->u_len == 2 && ci->u_data[1] == 0x399 && + ci->f_len == 2 && ci->f_data[1] == 0x3B9 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) { + len = 1; + while (code + len <= CHARCODE_MAX) { + ci1 = &tab[code + len]; + if (!(ci1->u_len == 2 && + ci1->u_data[1] == ci->u_data[1] && + ci1->u_data[0] == ci->u_data[0] + len && + ci1->f_len == 2 && + ci1->f_data[1] == ci->f_data[1] && + ci1->f_data[0] == ci->f_data[0] + len && + ci1->l_len == 0)) + break; + len++; + } + te->len = len; + te->type = RUN_TYPE_UF_EXT2; + te->ext_data[0] = ci->u_data[0]; + te->ext_data[1] = ci->u_data[1]; + te->ext_len = 2; + return; + } + + if (ci->u_len == 2 && ci->u_data[1] == 0x399 && + ci->l_len == 1 && + ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) { + len = 1; + while (code + len <= CHARCODE_MAX) { + ci1 = &tab[code + len]; + if (!(ci1->u_len == 2 && + ci1->u_data[1] == 0x399 && + ci1->u_data[0] == ci->u_data[0] + len && + ci1->l_len == 1 && + ci1->l_data[0] == ci->l_data[0] + len && + ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0])) + break; + len++; + } + te->len = len; + te->type = RUN_TYPE_U2L_399_EXT2; + te->ext_data[0] = ci->u_data[0]; + te->ext_data[1] = ci->l_data[0]; + te->ext_len = 2; + return; + } + + if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) { + len = 1; + while (code + len <= CHARCODE_MAX) { + ci1 = &tab[code + len]; + if (!(ci1->l_len == 1 && + ci1->l_data[0] == ci->l_data[0] + len && + ci1->u_len == 0 && ci1->f_len == 0)) + break; + len++; + } + te->len = len; + te->type = RUN_TYPE_L; + te->data = ci->l_data[0]; + return; + } + + if (ci->l_len == 0 && + ci->u_len == 1 && + ci->u_data[0] < 0x1000 && + ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) { + te->len = 1; + te->type = RUN_TYPE_UF_D20; + te->data = ci->u_data[0]; + } else if (ci->l_len == 0 && + ci->u_len == 1 && + ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) { + te->len = 1; + te->type = RUN_TYPE_UF_D1_EXT; + te->ext_data[0] = ci->u_data[0]; + te->ext_len = 1; + } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 && + ci->l_data[0] == ci->f_data[0] && + ci->l_data[1] == ci->f_data[1]) { + te->len = 1; + te->type = RUN_TYPE_LF_EXT2; + te->ext_data[0] = ci->l_data[0]; + te->ext_data[1] = ci->l_data[1]; + te->ext_len = 2; + } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && + ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) { + te->len = 1; + te->type = RUN_TYPE_UF_EXT2; + te->ext_data[0] = ci->u_data[0]; + te->ext_data[1] = ci->u_data[1]; + te->ext_len = 2; + } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 && + ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) && + ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) && + ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) { + te->len = 1; + te->type = RUN_TYPE_UF_EXT3; + te->ext_data[0] = ci->u_data[0]; + te->ext_data[1] = ci->u_data[1]; + te->ext_data[2] = ci->u_data[2]; + te->ext_len = 3; + } else { + printf("unsupported encoding case:\n"); + dump_cc_info(ci, code); + abort(); + } + } else { + /* look for a run of identical conversions */ + len = 0; + for(;;) { + if (code >= CHARCODE_MAX || len >= 126) + break; + ci = &tab[code + len]; + ci1 = &tab[code + len + 1]; + if (is_complicated_case(ci) || is_complicated_case(ci1)) { + break; + } + if (ci->l_len != 1 || ci->l_data[0] != code + len + 1) + break; + if (ci1->u_len != 1 || ci1->u_data[0] != code + len) + break; + len += 2; + } + if (len > 0) { + te->len = len; + te->type = RUN_TYPE_UL; + te->data = 0; + return; + } + + ci = &tab[code]; + is_lower = ci->l_len > 0; + len = 1; + while (code + len <= CHARCODE_MAX) { + ci1 = &tab[code + len]; + if (is_complicated_case(ci1)) + break; + if (is_lower) { + if (ci1->l_len != 1 || + ci1->l_data[0] != ci->l_data[0] + len) + break; + } else { + if (ci1->u_len != 1 || + ci1->u_data[0] != ci->u_data[0] + len) + break; + } + len++; + } + te->len = len; + if (is_lower) { + te->type = RUN_TYPE_LF; + te->data = ci->l_data[0]; + } else { + te->type = RUN_TYPE_U; + te->data = ci->u_data[0]; + } + } +} + +TableEntry conv_table[1000]; +int conv_table_len; +int ext_data[1000]; +int ext_data_len; + +void dump_case_conv_table1(void) +{ + int i, j; + const TableEntry *te; + + for(i = 0; i < conv_table_len; i++) { + te = &conv_table[i]; + printf("%05x %02x %-10s %05x", + te->code, te->len, run_type_str[te->type], te->data); + for(j = 0; j < te->ext_len; j++) { + printf(" %05x", te->ext_data[j]); + } + printf("\n"); + } + printf("table_len=%d ext_len=%d\n", conv_table_len, ext_data_len); +} + +int find_data_index(const TableEntry *conv_table, int len, int data) +{ + int i; + const TableEntry *te; + for(i = 0; i < len; i++) { + te = &conv_table[i]; + if (te->code == data) + return i; + } + return -1; +} + +int find_ext_data_index(int data) +{ + int i; + for(i = 0; i < ext_data_len; i++) { + if (ext_data[i] == data) + return i; + } + assert(ext_data_len < countof(ext_data)); + ext_data[ext_data_len++] = data; + return ext_data_len - 1; +} + +void build_conv_table(CCInfo *tab) +{ + int code, i, j; + CCInfo *ci; + TableEntry *te; + + te = conv_table; + for(code = 0; code <= CHARCODE_MAX; code++) { + ci = &tab[code]; + if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0) + continue; + assert(te - conv_table < countof(conv_table)); + find_run_type(te, tab, code); +#if 0 + if (te->type == RUN_TYPE_TODO) { + printf("TODO: "); + dump_cc_info(ci, code); + } +#endif + assert(te->len <= 127); + code += te->len - 1; + te++; + } + conv_table_len = te - conv_table; + + /* find the data index */ + for(i = 0; i < conv_table_len; i++) { + int data_index; + te = &conv_table[i]; + + switch(te->type) { + case RUN_TYPE_U: + case RUN_TYPE_L: + case RUN_TYPE_UF: + case RUN_TYPE_LF: + data_index = find_data_index(conv_table, conv_table_len, te->data); + if (data_index < 0) { + switch(te->type) { + case RUN_TYPE_U: + te->type = RUN_TYPE_U_EXT; + te->ext_len = 1; + te->ext_data[0] = te->data; + break; + case RUN_TYPE_LF: + te->type = RUN_TYPE_LF_EXT; + te->ext_len = 1; + te->ext_data[0] = te->data; + break; + default: + printf("%05x: index not found\n", te->code); + exit(1); + } + } else { + te->data_index = data_index; + } + break; + case RUN_TYPE_UF_D20: + te->data_index = te->data; + break; + } + } + + /* find the data index for ext_data */ + for(i = 0; i < conv_table_len; i++) { + te = &conv_table[i]; + if (te->type == RUN_TYPE_UF_EXT3) { + int p, v; + v = 0; + for(j = 0; j < 3; j++) { + p = find_ext_data_index(te->ext_data[j]); + assert(p < 16); + v = (v << 4) | p; + } + te->data_index = v; + } + } + + for(i = 0; i < conv_table_len; i++) { + te = &conv_table[i]; + if (te->type == RUN_TYPE_LF_EXT2 || + te->type == RUN_TYPE_UF_EXT2 || + te->type == RUN_TYPE_U2L_399_EXT2) { + int p, v; + v = 0; + for(j = 0; j < 2; j++) { + p = find_ext_data_index(te->ext_data[j]); + assert(p < 64); + v = (v << 6) | p; + } + te->data_index = v; + } + } + + for(i = 0; i < conv_table_len; i++) { + te = &conv_table[i]; + if (te->type == RUN_TYPE_UF_D1_EXT || + te->type == RUN_TYPE_U_EXT || + te->type == RUN_TYPE_LF_EXT) { + te->data_index = find_ext_data_index(te->ext_data[0]); + } + } +#ifdef DUMP_CASE_CONV_TABLE + dump_case_conv_table1(); +#endif +} + +void dump_case_conv_table(FILE *f) +{ + int i; + uint32_t v; + const TableEntry *te; + + fprintf(f, "static const uint32_t case_conv_table1[%u] = {", conv_table_len); + for(i = 0; i < conv_table_len; i++) { + if (i % 4 == 0) + fprintf(f, "\n "); + te = &conv_table[i]; + v = te->code << (32 - 17); + v |= te->len << (32 - 17 - 7); + v |= te->type << (32 - 17 - 7 - 4); + v |= te->data_index >> 8; + fprintf(f, " 0x%08x,", v); + } + fprintf(f, "\n};\n\n"); + + fprintf(f, "static const uint8_t case_conv_table2[%u] = {", conv_table_len); + for(i = 0; i < conv_table_len; i++) { + if (i % 8 == 0) + fprintf(f, "\n "); + te = &conv_table[i]; + fprintf(f, " 0x%02x,", te->data_index & 0xff); + } + fprintf(f, "\n};\n\n"); + + fprintf(f, "static const uint16_t case_conv_ext[%u] = {", ext_data_len); + for(i = 0; i < ext_data_len; i++) { + if (i % 8 == 0) + fprintf(f, "\n "); + fprintf(f, " 0x%04x,", ext_data[i]); + } + fprintf(f, "\n};\n\n"); +} + + +static CCInfo *global_tab; + +static int sp_cc_cmp(const void *p1, const void *p2) +{ + CCInfo *c1 = &global_tab[*(const int *)p1]; + CCInfo *c2 = &global_tab[*(const int *)p2]; + if (c1->f_len < c2->f_len) { + return -1; + } else if (c2->f_len < c1->f_len) { + return 1; + } else { + return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len); + } +} + +/* dump the case special cases (multi character results which are + identical and need specific handling in lre_canonicalize() */ +void dump_case_folding_special_cases(CCInfo *tab) +{ + int i, len, j; + int *perm; + + perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1)); + for(i = 0; i <= CHARCODE_MAX; i++) + perm[i] = i; + global_tab = tab; + qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp); + for(i = 0; i <= CHARCODE_MAX;) { + if (tab[perm[i]].f_len <= 1) { + i++; + } else { + len = 1; + while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len])) + len++; + + if (len > 1) { + for(j = i; j < i + len; j++) + dump_cc_info(&tab[perm[j]], perm[j]); + } + i += len; + } + } + free(perm); + global_tab = NULL; +} + + +int tabcmp(const int *tab1, const int *tab2, int n) +{ + int i; + for(i = 0; i < n; i++) { + if (tab1[i] != tab2[i]) + return -1; + } + return 0; +} + +void dump_str(const char *str, const int *buf, int len) +{ + int i; + printf("%s=", str); + for(i = 0; i < len; i++) + printf(" %05x", buf[i]); + printf("\n"); +} + +void compute_internal_props(void) +{ + int i; + BOOL has_ul; + + for(i = 0; i <= CHARCODE_MAX; i++) { + CCInfo *ci = &unicode_db[i]; + has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0); + if (has_ul) { + assert(get_prop(i, PROP_Cased)); + } else { + set_prop(i, PROP_Cased1, get_prop(i, PROP_Cased)); + } + set_prop(i, PROP_ID_Continue1, + get_prop(i, PROP_ID_Continue) & (get_prop(i, PROP_ID_Start) ^ 1)); + set_prop(i, PROP_XID_Start1, + get_prop(i, PROP_ID_Start) ^ get_prop(i, PROP_XID_Start)); + set_prop(i, PROP_XID_Continue1, + get_prop(i, PROP_ID_Continue) ^ get_prop(i, PROP_XID_Continue)); + set_prop(i, PROP_Changes_When_Titlecased1, + get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0)); + set_prop(i, PROP_Changes_When_Casefolded1, + get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0)); + /* XXX: reduce table size (438 bytes) */ + set_prop(i, PROP_Changes_When_NFKC_Casefolded1, + get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0)); +#if 0 + /* TEST */ +#define M(x) (1U << GCAT_ ## x) + { + int b; + b = ((M(Mn) | M(Cf) | M(Lm) | M(Sk)) >> + unicode_db[i].general_category) & 1; + set_prop(i, PROP_Cased1, + get_prop(i, PROP_Case_Ignorable) ^ b); + } +#undef M +#endif + } +} + +void dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len) +{ + int i; + fprintf(f, "static const uint8_t %s[%d] = {", cname, len); + for(i = 0; i < len; i++) { + if (i % 8 == 0) + fprintf(f, "\n "); + fprintf(f, " 0x%02x,", tab[i]); + } + fprintf(f, "\n};\n\n"); +} + +#define PROP_BLOCK_LEN 32 + +void build_prop_table(FILE *f, int prop_index, BOOL add_index) +{ + int i, j, n, v, offset, code; + DynBuf dbuf_s, *dbuf = &dbuf_s; + DynBuf dbuf1_s, *dbuf1 = &dbuf1_s; + DynBuf dbuf2_s, *dbuf2 = &dbuf2_s; + const uint32_t *buf; + int buf_len, block_end_pos, bit; + char cname[128]; + + dbuf_init(dbuf1); + + for(i = 0; i <= CHARCODE_MAX;) { + v = get_prop(i, prop_index); + j = i + 1; + while (j <= CHARCODE_MAX && get_prop(j, prop_index) == v) { + j++; + } + n = j - i; + if (j == (CHARCODE_MAX + 1) && v == 0) + break; /* no need to encode last zero run */ + //printf("%05x: %d %d\n", i, n, v); + dbuf_put_u32(dbuf1, n - 1); + i += n; + } + + dbuf_init(dbuf); + dbuf_init(dbuf2); + buf = (uint32_t *)dbuf1->buf; + buf_len = dbuf1->size / sizeof(buf[0]); + + /* the first value is assumed to be 0 */ + assert(get_prop(0, prop_index) == 0); + + block_end_pos = PROP_BLOCK_LEN; + i = 0; + code = 0; + bit = 0; + while (i < buf_len) { + if (add_index && dbuf->size >= block_end_pos && bit == 0) { + offset = (dbuf->size - block_end_pos); + /* XXX: offset could be larger in case of runs of small + lengths. Could add code to change the encoding to + prevent it at the expense of one byte loss */ + assert(offset <= 7); + v = code | (offset << 21); + dbuf_putc(dbuf2, v); + dbuf_putc(dbuf2, v >> 8); + dbuf_putc(dbuf2, v >> 16); + block_end_pos += PROP_BLOCK_LEN; + } + + v = buf[i]; + code += v + 1; + bit ^= 1; + if (v < 8 && (i + 1) < buf_len && buf[i + 1] < 8) { + code += buf[i + 1] + 1; + bit ^= 1; + dbuf_putc(dbuf, (v << 3) | buf[i + 1]); + i += 2; + } else if (v < 128) { + dbuf_putc(dbuf, 0x80 + v); + i++; + } else if (v < (1 << 13)) { + dbuf_putc(dbuf, 0x40 + (v >> 8)); + dbuf_putc(dbuf, v); + i++; + } else { + assert(v < (1 << 21)); + dbuf_putc(dbuf, 0x60 + (v >> 16)); + dbuf_putc(dbuf, v >> 8); + dbuf_putc(dbuf, v); + i++; + } + } + + if (add_index) { + /* last index entry */ + v = code; + dbuf_putc(dbuf2, v); + dbuf_putc(dbuf2, v >> 8); + dbuf_putc(dbuf2, v >> 16); + } + +#ifdef DUMP_TABLE_SIZE + printf("prop %s: length=%d bytes\n", unicode_prop_name[prop_index], + (int)(dbuf->size + dbuf2->size)); +#endif + snprintf(cname, sizeof(cname), "unicode_prop_%s_table", unicode_prop_name[prop_index]); + dump_byte_table(f, cname, dbuf->buf, dbuf->size); + if (add_index) { + snprintf(cname, sizeof(cname), "unicode_prop_%s_index", unicode_prop_name[prop_index]); + dump_byte_table(f, cname, dbuf2->buf, dbuf2->size); + } + + dbuf_free(dbuf); + dbuf_free(dbuf1); + dbuf_free(dbuf2); +} + +void build_flags_tables(FILE *f) +{ + build_prop_table(f, PROP_Cased1, TRUE); + build_prop_table(f, PROP_Case_Ignorable, TRUE); + build_prop_table(f, PROP_ID_Start, TRUE); + build_prop_table(f, PROP_ID_Continue1, TRUE); +} + +void dump_name_table(FILE *f, const char *cname, const char **tab_name, int len, + const char **tab_short_name) +{ + int i, w, maxw; + + maxw = 0; + for(i = 0; i < len; i++) { + w = strlen(tab_name[i]); + if (tab_short_name[i][0] != '\0') { + w += 1 + strlen(tab_short_name[i]); + } + if (maxw < w) + maxw = w; + } + + /* generate a sequence of strings terminated by an empty string */ + fprintf(f, "static const char %s[] =\n", cname); + for(i = 0; i < len; i++) { + fprintf(f, " \""); + w = fprintf(f, "%s", tab_name[i]); + if (tab_short_name[i][0] != '\0') { + w += fprintf(f, ",%s", tab_short_name[i]); + } + fprintf(f, "\"%*s\"\\0\"\n", 1 + maxw - w, ""); + } + fprintf(f, ";\n\n"); +} + +void build_general_category_table(FILE *f) +{ + int i, v, j, n, n1; + DynBuf dbuf_s, *dbuf = &dbuf_s; + int cw_count, cw_len_count[4], cw_start; + + fprintf(f, "typedef enum {\n"); + for(i = 0; i < GCAT_COUNT; i++) + fprintf(f, " UNICODE_GC_%s,\n", unicode_gc_name[i]); + fprintf(f, " UNICODE_GC_COUNT,\n"); + fprintf(f, "} UnicodeGCEnum;\n\n"); + + dump_name_table(f, "unicode_gc_name_table", + unicode_gc_name, GCAT_COUNT, + unicode_gc_short_name); + + + dbuf_init(dbuf); + cw_count = 0; + for(i = 0; i < 4; i++) + cw_len_count[i] = 0; + for(i = 0; i <= CHARCODE_MAX;) { + v = unicode_db[i].general_category; + j = i + 1; + while (j <= CHARCODE_MAX && unicode_db[j].general_category == v) + j++; + n = j - i; + /* compress Lu/Ll runs */ + if (v == GCAT_Lu) { + n1 = 1; + while ((i + n1) <= CHARCODE_MAX && unicode_db[i + n1].general_category == (v + (n1 & 1))) { + n1++; + } + if (n1 > n) { + v = 31; + n = n1; + } + } + // printf("%05x %05x %d\n", i, n, v); + cw_count++; + n--; + cw_start = dbuf->size; + if (n < 7) { + dbuf_putc(dbuf, (n << 5) | v); + } else if (n < 7 + 128) { + n1 = n - 7; + assert(n1 < 128); + dbuf_putc(dbuf, (0xf << 5) | v); + dbuf_putc(dbuf, n1); + } else if (n < 7 + 128 + (1 << 14)) { + n1 = n - (7 + 128); + assert(n1 < (1 << 14)); + dbuf_putc(dbuf, (0xf << 5) | v); + dbuf_putc(dbuf, (n1 >> 8) + 128); + dbuf_putc(dbuf, n1); + } else { + n1 = n - (7 + 128 + (1 << 14)); + assert(n1 < (1 << 22)); + dbuf_putc(dbuf, (0xf << 5) | v); + dbuf_putc(dbuf, (n1 >> 16) + 128 + 64); + dbuf_putc(dbuf, n1 >> 8); + dbuf_putc(dbuf, n1); + } + cw_len_count[dbuf->size - cw_start - 1]++; + i += n + 1; + } +#ifdef DUMP_TABLE_SIZE + printf("general category: %d entries [", + cw_count); + for(i = 0; i < 4; i++) + printf(" %d", cw_len_count[i]); + printf(" ], length=%d bytes\n", (int)dbuf->size); +#endif + + dump_byte_table(f, "unicode_gc_table", dbuf->buf, dbuf->size); + + dbuf_free(dbuf); +} + +void build_script_table(FILE *f) +{ + int i, v, j, n, n1, type; + DynBuf dbuf_s, *dbuf = &dbuf_s; + int cw_count, cw_len_count[4], cw_start; + + fprintf(f, "typedef enum {\n"); + for(i = 0; i < SCRIPT_COUNT; i++) + fprintf(f, " UNICODE_SCRIPT_%s,\n", unicode_script_name[i]); + fprintf(f, " UNICODE_SCRIPT_COUNT,\n"); + fprintf(f, "} UnicodeScriptEnum;\n\n"); + + i = 1; + dump_name_table(f, "unicode_script_name_table", + unicode_script_name + i, SCRIPT_COUNT - i, + unicode_script_short_name + i); + + dbuf_init(dbuf); + cw_count = 0; + for(i = 0; i < 4; i++) + cw_len_count[i] = 0; + for(i = 0; i <= CHARCODE_MAX;) { + v = unicode_db[i].script; + j = i + 1; + while (j <= CHARCODE_MAX && unicode_db[j].script == v) + j++; + n = j - i; + if (v == 0 && j == (CHARCODE_MAX + 1)) + break; + // printf("%05x %05x %d\n", i, n, v); + cw_count++; + n--; + cw_start = dbuf->size; + if (v == 0) + type = 0; + else + type = 1; + if (n < 96) { + dbuf_putc(dbuf, n | (type << 7)); + } else if (n < 96 + (1 << 12)) { + n1 = n - 96; + assert(n1 < (1 << 12)); + dbuf_putc(dbuf, ((n1 >> 8) + 96) | (type << 7)); + dbuf_putc(dbuf, n1); + } else { + n1 = n - (96 + (1 << 12)); + assert(n1 < (1 << 20)); + dbuf_putc(dbuf, ((n1 >> 16) + 112) | (type << 7)); + dbuf_putc(dbuf, n1 >> 8); + dbuf_putc(dbuf, n1); + } + if (type != 0) + dbuf_putc(dbuf, v); + + cw_len_count[dbuf->size - cw_start - 1]++; + i += n + 1; + } +#if defined(DUMP_TABLE_SIZE) + printf("script: %d entries [", + cw_count); + for(i = 0; i < 4; i++) + printf(" %d", cw_len_count[i]); + printf(" ], length=%d bytes\n", (int)dbuf->size); +#endif + + dump_byte_table(f, "unicode_script_table", dbuf->buf, dbuf->size); + + dbuf_free(dbuf); +} + +void build_script_ext_table(FILE *f) +{ + int i, j, n, n1, script_ext_len; + DynBuf dbuf_s, *dbuf = &dbuf_s; + int cw_count; + + dbuf_init(dbuf); + cw_count = 0; + for(i = 0; i <= CHARCODE_MAX;) { + script_ext_len = unicode_db[i].script_ext_len; + j = i + 1; + while (j <= CHARCODE_MAX && + unicode_db[j].script_ext_len == script_ext_len && + !memcmp(unicode_db[j].script_ext, unicode_db[i].script_ext, + script_ext_len)) { + j++; + } + n = j - i; + cw_count++; + n--; + if (n < 128) { + dbuf_putc(dbuf, n); + } else if (n < 128 + (1 << 14)) { + n1 = n - 128; + assert(n1 < (1 << 14)); + dbuf_putc(dbuf, (n1 >> 8) + 128); + dbuf_putc(dbuf, n1); + } else { + n1 = n - (128 + (1 << 14)); + assert(n1 < (1 << 22)); + dbuf_putc(dbuf, (n1 >> 16) + 128 + 64); + dbuf_putc(dbuf, n1 >> 8); + dbuf_putc(dbuf, n1); + } + dbuf_putc(dbuf, script_ext_len); + for(j = 0; j < script_ext_len; j++) + dbuf_putc(dbuf, unicode_db[i].script_ext[j]); + i += n + 1; + } +#ifdef DUMP_TABLE_SIZE + printf("script_ext: %d entries", + cw_count); + printf(", length=%d bytes\n", (int)dbuf->size); +#endif + + dump_byte_table(f, "unicode_script_ext_table", dbuf->buf, dbuf->size); + + dbuf_free(dbuf); +} + +/* the following properties are synthetized so no table is necessary */ +#define PROP_TABLE_COUNT PROP_ASCII + +void build_prop_list_table(FILE *f) +{ + int i; + + for(i = 0; i < PROP_TABLE_COUNT; i++) { + if (i == PROP_ID_Start || + i == PROP_Case_Ignorable || + i == PROP_ID_Continue1) { + /* already generated */ + } else { + build_prop_table(f, i, FALSE); + } + } + + fprintf(f, "typedef enum {\n"); + for(i = 0; i < PROP_COUNT; i++) + fprintf(f, " UNICODE_PROP_%s,\n", unicode_prop_name[i]); + fprintf(f, " UNICODE_PROP_COUNT,\n"); + fprintf(f, "} UnicodePropertyEnum;\n\n"); + + i = PROP_ASCII_Hex_Digit; + dump_name_table(f, "unicode_prop_name_table", + unicode_prop_name + i, PROP_XID_Start - i + 1, + unicode_prop_short_name + i); + + fprintf(f, "static const uint8_t * const unicode_prop_table[] = {\n"); + for(i = 0; i < PROP_TABLE_COUNT; i++) { + fprintf(f, " unicode_prop_%s_table,\n", unicode_prop_name[i]); + } + fprintf(f, "};\n\n"); + + fprintf(f, "static const uint16_t unicode_prop_len_table[] = {\n"); + for(i = 0; i < PROP_TABLE_COUNT; i++) { + fprintf(f, " countof(unicode_prop_%s_table),\n", unicode_prop_name[i]); + } + fprintf(f, "};\n\n"); +} + +#ifdef USE_TEST +int check_conv(uint32_t *res, uint32_t c, int conv_type) +{ + return lre_case_conv(res, c, conv_type); +} + +void check_case_conv(void) +{ + CCInfo *tab = unicode_db; + uint32_t res[3]; + int l, error; + CCInfo ci_s, *ci1, *ci = &ci_s; + int code; + + for(code = 0; code <= CHARCODE_MAX; code++) { + ci1 = &tab[code]; + *ci = *ci1; + if (ci->l_len == 0) { + ci->l_len = 1; + ci->l_data[0] = code; + } + if (ci->u_len == 0) { + ci->u_len = 1; + ci->u_data[0] = code; + } + if (ci->f_len == 0) { + ci->f_len = 1; + ci->f_data[0] = code; + } + + error = 0; + l = check_conv(res, code, 0); + if (l != ci->u_len || tabcmp((int *)res, ci->u_data, l)) { + printf("ERROR: L\n"); + error++; + } + l = check_conv(res, code, 1); + if (l != ci->l_len || tabcmp((int *)res, ci->l_data, l)) { + printf("ERROR: U\n"); + error++; + } + l = check_conv(res, code, 2); + if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) { + printf("ERROR: F\n"); + error++; + } + if (error) { + dump_cc_info(ci, code); + exit(1); + } + } +} + +#ifdef PROFILE +static int64_t get_time_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec; +} +#endif + + +void check_flags(void) +{ + int c; + BOOL flag_ref, flag; + for(c = 0; c <= CHARCODE_MAX; c++) { + flag_ref = get_prop(c, PROP_Cased); + flag = lre_is_cased(c); + if (flag != flag_ref) { + printf("ERROR: c=%05x cased=%d ref=%d\n", + c, flag, flag_ref); + exit(1); + } + + flag_ref = get_prop(c, PROP_Case_Ignorable); + flag = lre_is_case_ignorable(c); + if (flag != flag_ref) { + printf("ERROR: c=%05x case_ignorable=%d ref=%d\n", + c, flag, flag_ref); + exit(1); + } + + flag_ref = get_prop(c, PROP_ID_Start); + flag = lre_is_id_start(c); + if (flag != flag_ref) { + printf("ERROR: c=%05x id_start=%d ref=%d\n", + c, flag, flag_ref); + exit(1); + } + + flag_ref = get_prop(c, PROP_ID_Continue); + flag = lre_is_id_continue(c); + if (flag != flag_ref) { + printf("ERROR: c=%05x id_cont=%d ref=%d\n", + c, flag, flag_ref); + exit(1); + } + } +#ifdef PROFILE + { + int64_t ti, count; + ti = get_time_ns(); + count = 0; + for(c = 0x20; c <= 0xffff; c++) { + flag_ref = get_prop(c, PROP_ID_Start); + flag = lre_is_id_start(c); + assert(flag == flag_ref); + count++; + } + ti = get_time_ns() - ti; + printf("flags time=%0.1f ns/char\n", + (double)ti / count); + } +#endif +} + +#endif + +#define CC_BLOCK_LEN 32 + +void build_cc_table(FILE *f) +{ + int i, cc, n, cc_table_len, type, n1; + DynBuf dbuf_s, *dbuf = &dbuf_s; + DynBuf dbuf1_s, *dbuf1 = &dbuf1_s; + int cw_len_tab[3], cw_start, block_end_pos; + uint32_t v; + + dbuf_init(dbuf); + dbuf_init(dbuf1); + cc_table_len = 0; + for(i = 0; i < countof(cw_len_tab); i++) + cw_len_tab[i] = 0; + block_end_pos = CC_BLOCK_LEN; + for(i = 0; i <= CHARCODE_MAX;) { + cc = unicode_db[i].combining_class; + assert(cc <= 255); + /* check increasing values */ + n = 1; + while ((i + n) <= CHARCODE_MAX && + unicode_db[i + n].combining_class == (cc + n)) + n++; + if (n >= 2) { + type = 1; + } else { + type = 0; + n = 1; + while ((i + n) <= CHARCODE_MAX && + unicode_db[i + n].combining_class == cc) + n++; + } + /* no need to encode the last run */ + if (cc == 0 && (i + n - 1) == CHARCODE_MAX) + break; +#ifdef DUMP_CC_TABLE + printf("%05x %6d %d %d\n", i, n, type, cc); +#endif + if (type == 0) { + if (cc == 0) + type = 2; + else if (cc == 230) + type = 3; + } + n1 = n - 1; + + /* add an entry to the index if necessary */ + if (dbuf->size >= block_end_pos) { + v = i | ((dbuf->size - block_end_pos) << 21); + dbuf_putc(dbuf1, v); + dbuf_putc(dbuf1, v >> 8); + dbuf_putc(dbuf1, v >> 16); + block_end_pos += CC_BLOCK_LEN; + } + cw_start = dbuf->size; + if (n1 < 48) { + dbuf_putc(dbuf, n1 | (type << 6)); + } else if (n1 < 48 + (1 << 11)) { + n1 -= 48; + dbuf_putc(dbuf, ((n1 >> 8) + 48) | (type << 6)); + dbuf_putc(dbuf, n1); + } else { + n1 -= 48 + (1 << 11); + assert(n1 < (1 << 20)); + dbuf_putc(dbuf, ((n1 >> 16) + 56) | (type << 6)); + dbuf_putc(dbuf, n1 >> 8); + dbuf_putc(dbuf, n1); + } + cw_len_tab[dbuf->size - cw_start - 1]++; + if (type == 0 || type == 1) + dbuf_putc(dbuf, cc); + cc_table_len++; + i += n; + } + + /* last index entry */ + v = i; + dbuf_putc(dbuf1, v); + dbuf_putc(dbuf1, v >> 8); + dbuf_putc(dbuf1, v >> 16); + + dump_byte_table(f, "unicode_cc_table", dbuf->buf, dbuf->size); + dump_byte_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size); + +#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE) + printf("CC table: size=%d (%d entries) [", + (int)(dbuf->size + dbuf1->size), + cc_table_len); + for(i = 0; i < countof(cw_len_tab); i++) + printf(" %d", cw_len_tab[i]); + printf(" ]\n"); +#endif + dbuf_free(dbuf); + dbuf_free(dbuf1); +} + +/* maximum length of decomposition: 18 chars (1), then 8 */ +#ifndef USE_TEST +typedef enum { + DECOMP_TYPE_C1, /* 16 bit char */ + DECOMP_TYPE_L1, /* 16 bit char table */ + DECOMP_TYPE_L2, + DECOMP_TYPE_L3, + DECOMP_TYPE_L4, + DECOMP_TYPE_L5, /* XXX: not used */ + DECOMP_TYPE_L6, /* XXX: could remove */ + DECOMP_TYPE_L7, /* XXX: could remove */ + DECOMP_TYPE_LL1, /* 18 bit char table */ + DECOMP_TYPE_LL2, + DECOMP_TYPE_S1, /* 8 bit char table */ + DECOMP_TYPE_S2, + DECOMP_TYPE_S3, + DECOMP_TYPE_S4, + DECOMP_TYPE_S5, + DECOMP_TYPE_I1, /* increment 16 bit char value */ + DECOMP_TYPE_I2_0, + DECOMP_TYPE_I2_1, + DECOMP_TYPE_I3_1, + DECOMP_TYPE_I3_2, + DECOMP_TYPE_I4_1, + DECOMP_TYPE_I4_2, + DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ + DECOMP_TYPE_B2, + DECOMP_TYPE_B3, + DECOMP_TYPE_B4, + DECOMP_TYPE_B5, + DECOMP_TYPE_B6, + DECOMP_TYPE_B7, + DECOMP_TYPE_B8, + DECOMP_TYPE_B18, + DECOMP_TYPE_LS2, + DECOMP_TYPE_PAT3, + DECOMP_TYPE_S2_UL, + DECOMP_TYPE_LS2_UL, +} DecompTypeEnum; +#endif + +const char *decomp_type_str[] = { + "C1", + "L1", + "L2", + "L3", + "L4", + "L5", + "L6", + "L7", + "LL1", + "LL2", + "S1", + "S2", + "S3", + "S4", + "S5", + "I1", + "I2_0", + "I2_1", + "I3_1", + "I3_2", + "I4_1", + "I4_2", + "B1", + "B2", + "B3", + "B4", + "B5", + "B6", + "B7", + "B8", + "B18", + "LS2", + "PAT3", + "S2_UL", + "LS2_UL", +}; + +const int decomp_incr_tab[4][4] = { + { DECOMP_TYPE_I1, 0, -1 }, + { DECOMP_TYPE_I2_0, 0, 1, -1 }, + { DECOMP_TYPE_I3_1, 1, 2, -1 }, + { DECOMP_TYPE_I4_1, 1, 2, -1 }, +}; + +/* + entry size: + type bits + code 18 + len 7 + compat 1 + type 5 + index 16 + total 47 +*/ + +typedef struct { + int code; + uint8_t len; + uint8_t type; + uint8_t c_len; + uint16_t c_min; + uint16_t data_index; + int cost; /* size in bytes from this entry to the end */ +} DecompEntry; + +int get_decomp_run_size(const DecompEntry *de) +{ + int s; + s = 6; + if (de->type <= DECOMP_TYPE_C1) { + /* nothing more */ + } else if (de->type <= DECOMP_TYPE_L7) { + s += de->len * de->c_len * 2; + } else if (de->type <= DECOMP_TYPE_LL2) { + /* 18 bits per char */ + s += (de->len * de->c_len * 18 + 7) / 8; + } else if (de->type <= DECOMP_TYPE_S5) { + s += de->len * de->c_len; + } else if (de->type <= DECOMP_TYPE_I4_2) { + s += de->c_len * 2; + } else if (de->type <= DECOMP_TYPE_B18) { + s += 2 + de->len * de->c_len; + } else if (de->type <= DECOMP_TYPE_LS2) { + s += de->len * 3; + } else if (de->type <= DECOMP_TYPE_PAT3) { + s += 4 + de->len * 2; + } else if (de->type <= DECOMP_TYPE_S2_UL) { + s += de->len; + } else if (de->type <= DECOMP_TYPE_LS2_UL) { + s += (de->len / 2) * 3; + } else { + abort(); + } + return s; +} + +static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; + +/* return -1 if not found */ +int get_short_code(int c) +{ + int i; + if (c < 0x80) { + return c; + } else if (c >= 0x300 && c < 0x350) { + return c - 0x300 + 0x80; + } else { + for(i = 0; i < countof(unicode_short_table); i++) { + if (c == unicode_short_table[i]) + return i + 0x80 + 0x50; + } + return -1; + } +} + +static BOOL is_short(int code) +{ + return get_short_code(code) >= 0; +} + +static BOOL is_short_tab(const int *tab, int len) +{ + int i; + for(i = 0; i < len; i++) { + if (!is_short(tab[i])) + return FALSE; + } + return TRUE; +} + +static BOOL is_16bit(const int *tab, int len) +{ + int i; + for(i = 0; i < len; i++) { + if (tab[i] > 0xffff) + return FALSE; + } + return TRUE; +} + +static uint32_t to_lower_simple(uint32_t c) +{ + /* Latin1 and Cyrillic */ + if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) + c += 0x20; + else + c++; + return c; +} + +/* select best encoding with dynamic programming */ +void find_decomp_run(DecompEntry *tab_de, int i) +{ + DecompEntry de_s, *de = &de_s; + CCInfo *ci, *ci1, *ci2; + int l, j, n, len_max; + + ci = &unicode_db[i]; + l = ci->decomp_len; + if (l == 0) { + tab_de[i].cost = tab_de[i + 1].cost; + return; + } + + /* the offset for the compose table has only 6 bits, so we must + limit if it can be used by the compose table */ + if (!ci->is_compat && !ci->is_excluded && l == 2) + len_max = 64; + else + len_max = 127; + + tab_de[i].cost = 0x7fffffff; + + if (!is_16bit(ci->decomp_data, l)) { + assert(l <= 2); + + n = 1; + for(;;) { + de->code = i; + de->len = n; + de->type = DECOMP_TYPE_LL1 + l - 1; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + /* Note: we accept a hole */ + if (!(ci1->decomp_len == 0 || + (ci1->decomp_len == l && + ci1->is_compat == ci->is_compat))) + break; + n++; + } + return; + } + + if (l <= 7) { + n = 1; + for(;;) { + de->code = i; + de->len = n; + if (l == 1 && n == 1) { + de->type = DECOMP_TYPE_C1; + } else { + assert(l <= 8); + de->type = DECOMP_TYPE_L1 + l - 1; + } + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + /* Note: we accept a hole */ + if (!(ci1->decomp_len == 0 || + (ci1->decomp_len == l && + ci1->is_compat == ci->is_compat && + is_16bit(ci1->decomp_data, l)))) + break; + n++; + } + } + + if (l <= 8 || l == 18) { + int c_min, c_max, c; + c_min = c_max = -1; + n = 1; + for(;;) { + ci1 = &unicode_db[i + n - 1]; + for(j = 0; j < l; j++) { + c = ci1->decomp_data[j]; + if (c == 0x20) { + /* we accept space for Arabic */ + } else if (c_min == -1) { + c_min = c_max = c; + } else { + c_min = min_int(c_min, c); + c_max = max_int(c_max, c); + } + } + if ((c_max - c_min) > 254) + break; + de->code = i; + de->len = n; + if (l == 18) + de->type = DECOMP_TYPE_B18; + else + de->type = DECOMP_TYPE_B1 + l - 1; + de->c_len = l; + de->c_min = c_min; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + if (!(ci1->decomp_len == l && + ci1->is_compat == ci->is_compat)) + break; + n++; + } + } + + /* find an ascii run */ + if (l <= 5 && is_short_tab(ci->decomp_data, l)) { + n = 1; + for(;;) { + de->code = i; + de->len = n; + de->type = DECOMP_TYPE_S1 + l - 1; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + /* Note: we accept a hole */ + if (!(ci1->decomp_len == 0 || + (ci1->decomp_len == l && + ci1->is_compat == ci->is_compat && + is_short_tab(ci1->decomp_data, l)))) + break; + n++; + } + } + + /* check if a single char is increasing */ + if (l <= 4) { + int idx1, idx; + + for(idx1 = 1; (idx = decomp_incr_tab[l - 1][idx1]) >= 0; idx1++) { + n = 1; + for(;;) { + de->code = i; + de->len = n; + de->type = decomp_incr_tab[l - 1][0] + idx1 - 1; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + if (!(ci1->decomp_len == l && + ci1->is_compat == ci->is_compat)) + goto next1; + for(j = 0; j < l; j++) { + if (j == idx) { + if (ci1->decomp_data[j] != ci->decomp_data[j] + n) + goto next1; + } else { + if (ci1->decomp_data[j] != ci->decomp_data[j]) + goto next1; + } + } + n++; + } + next1: ; + } + } + + if (l == 3) { + n = 1; + for(;;) { + de->code = i; + de->len = n; + de->type = DECOMP_TYPE_PAT3; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + if (!(ci1->decomp_len == l && + ci1->is_compat == ci->is_compat && + ci1->decomp_data[1] <= 0xffff && + ci1->decomp_data[0] == ci->decomp_data[0] && + ci1->decomp_data[l - 1] == ci->decomp_data[l - 1])) + break; + n++; + } + } + + if (l == 2 && is_short(ci->decomp_data[1])) { + n = 1; + for(;;) { + de->code = i; + de->len = n; + de->type = DECOMP_TYPE_LS2; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + if (!((i + n) <= CHARCODE_MAX && n < len_max)) + break; + ci1 = &unicode_db[i + n]; + if (!(ci1->decomp_len == 0 || + (ci1->decomp_len == l && + ci1->is_compat == ci->is_compat && + ci1->decomp_data[0] <= 0xffff && + is_short(ci1->decomp_data[1])))) + break; + n++; + } + } + + if (l == 2) { + BOOL is_16bit; + + n = 0; + is_16bit = FALSE; + for(;;) { + if (!((i + n + 1) <= CHARCODE_MAX && n + 2 <= len_max)) + break; + ci1 = &unicode_db[i + n]; + if (!(ci1->decomp_len == l && + ci1->is_compat == ci->is_compat && + is_short(ci1->decomp_data[1]))) + break; + if (!is_16bit && !is_short(ci1->decomp_data[0])) + is_16bit = TRUE; + ci2 = &unicode_db[i + n + 1]; + if (!(ci2->decomp_len == l && + ci2->is_compat == ci->is_compat && + ci2->decomp_data[0] == to_lower_simple(ci1->decomp_data[0]) && + ci2->decomp_data[1] == ci1->decomp_data[1])) + break; + n += 2; + de->code = i; + de->len = n; + de->type = DECOMP_TYPE_S2_UL + is_16bit; + de->c_len = l; + de->cost = get_decomp_run_size(de) + tab_de[i + n].cost; + if (de->cost < tab_de[i].cost) { + tab_de[i] = *de; + } + } + } +} + +void put16(uint8_t *data_buf, int *pidx, uint16_t c) +{ + int idx; + idx = *pidx; + data_buf[idx++] = c; + data_buf[idx++] = c >> 8; + *pidx = idx; +} + +void add_decomp_data(uint8_t *data_buf, int *pidx, DecompEntry *de) +{ + int i, j, idx, c; + CCInfo *ci; + + idx = *pidx; + de->data_index = idx; + if (de->type <= DECOMP_TYPE_C1) { + ci = &unicode_db[de->code]; + assert(ci->decomp_len == 1); + de->data_index = ci->decomp_data[0]; + } else if (de->type <= DECOMP_TYPE_L7) { + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + for(j = 0; j < de->c_len; j++) { + if (ci->decomp_len == 0) + c = 0; + else + c = ci->decomp_data[j]; + put16(data_buf, &idx, c); + } + } + } else if (de->type <= DECOMP_TYPE_LL2) { + int n, p, k; + n = (de->len * de->c_len * 18 + 7) / 8; + p = de->len * de->c_len * 2; + memset(data_buf + idx, 0, n); + k = 0; + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + for(j = 0; j < de->c_len; j++) { + if (ci->decomp_len == 0) + c = 0; + else + c = ci->decomp_data[j]; + data_buf[idx + k * 2] = c; + data_buf[idx + k * 2 + 1] = c >> 8; + data_buf[idx + p + (k / 4)] |= (c >> 16) << ((k % 4) * 2); + k++; + } + } + idx += n; + } else if (de->type <= DECOMP_TYPE_S5) { + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + for(j = 0; j < de->c_len; j++) { + if (ci->decomp_len == 0) + c = 0; + else + c = ci->decomp_data[j]; + c = get_short_code(c); + assert(c >= 0); + data_buf[idx++] = c; + } + } + } else if (de->type <= DECOMP_TYPE_I4_2) { + ci = &unicode_db[de->code]; + assert(ci->decomp_len == de->c_len); + for(j = 0; j < de->c_len; j++) + put16(data_buf, &idx, ci->decomp_data[j]); + } else if (de->type <= DECOMP_TYPE_B18) { + c = de->c_min; + data_buf[idx++] = c; + data_buf[idx++] = c >> 8; + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + for(j = 0; j < de->c_len; j++) { + assert(ci->decomp_len == de->c_len); + c = ci->decomp_data[j]; + if (c == 0x20) { + c = 0xff; + } else { + c -= de->c_min; + assert((uint32_t)c <= 254); + } + data_buf[idx++] = c; + } + } + } else if (de->type <= DECOMP_TYPE_LS2) { + assert(de->c_len == 2); + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + if (ci->decomp_len == 0) + c = 0; + else + c = ci->decomp_data[0]; + put16(data_buf, &idx, c); + + if (ci->decomp_len == 0) + c = 0; + else + c = ci->decomp_data[1]; + c = get_short_code(c); + assert(c >= 0); + data_buf[idx++] = c; + } + } else if (de->type <= DECOMP_TYPE_PAT3) { + ci = &unicode_db[de->code]; + assert(ci->decomp_len == 3); + put16(data_buf, &idx, ci->decomp_data[0]); + put16(data_buf, &idx, ci->decomp_data[2]); + for(i = 0; i < de->len; i++) { + ci = &unicode_db[de->code + i]; + assert(ci->decomp_len == 3); + put16(data_buf, &idx, ci->decomp_data[1]); + } + } else if (de->type <= DECOMP_TYPE_S2_UL) { + for(i = 0; i < de->len; i += 2) { + ci = &unicode_db[de->code + i]; + c = ci->decomp_data[0]; + c = get_short_code(c); + assert(c >= 0); + data_buf[idx++] = c; + c = ci->decomp_data[1]; + c = get_short_code(c); + assert(c >= 0); + data_buf[idx++] = c; + } + } else if (de->type <= DECOMP_TYPE_LS2_UL) { + for(i = 0; i < de->len; i += 2) { + ci = &unicode_db[de->code + i]; + c = ci->decomp_data[0]; + put16(data_buf, &idx, c); + c = ci->decomp_data[1]; + c = get_short_code(c); + assert(c >= 0); + data_buf[idx++] = c; + } + } else { + abort(); + } + *pidx = idx; +} + +#if 0 +void dump_large_char(void) +{ + int i, j; + for(i = 0; i <= CHARCODE_MAX; i++) { + CCInfo *ci = &unicode_db[i]; + for(j = 0; j < ci->decomp_len; j++) { + if (ci->decomp_data[j] > 0xffff) + printf("%05x\n", ci->decomp_data[j]); + } + } +} +#endif + +void build_compose_table(FILE *f, const DecompEntry *tab_de); + +void build_decompose_table(FILE *f) +{ + int i, array_len, code_max, data_len, count; + DecompEntry *tab_de, de_s, *de = &de_s; + uint8_t *data_buf; + + code_max = CHARCODE_MAX; + + tab_de = mallocz((code_max + 2) * sizeof(*tab_de)); + + for(i = code_max; i >= 0; i--) { + find_decomp_run(tab_de, i); + } + + /* build the data buffer */ + data_buf = malloc(100000); + data_len = 0; + array_len = 0; + for(i = 0; i <= code_max; i++) { + de = &tab_de[i]; + if (de->len != 0) { + add_decomp_data(data_buf, &data_len, de); + i += de->len - 1; + array_len++; + } + } + +#ifdef DUMP_DECOMP_TABLE + /* dump */ + { + int size, size1; + + printf("START LEN TYPE L C SIZE\n"); + size = 0; + for(i = 0; i <= code_max; i++) { + de = &tab_de[i]; + if (de->len != 0) { + size1 = get_decomp_run_size(de); + printf("%05x %3d %6s %2d %1d %4d\n", i, de->len, + decomp_type_str[de->type], de->c_len, + unicode_db[i].is_compat, size1); + i += de->len - 1; + size += size1; + } + } + + printf("array_len=%d estimated size=%d bytes actual=%d bytes\n", + array_len, size, array_len * 6 + data_len); + } +#endif + + fprintf(f, "static const uint32_t unicode_decomp_table1[%u] = {", + array_len); + count = 0; + for(i = 0; i <= code_max; i++) { + de = &tab_de[i]; + if (de->len != 0) { + uint32_t v; + if (count++ % 4 == 0) + fprintf(f, "\n "); + v = (de->code << (32 - 18)) | + (de->len << (32 - 18 - 7)) | + (de->type << (32 - 18 - 7 - 6)) | + unicode_db[de->code].is_compat; + fprintf(f, " 0x%08x,", v); + i += de->len - 1; + } + } + fprintf(f, "\n};\n\n"); + + fprintf(f, "static const uint16_t unicode_decomp_table2[%u] = {", + array_len); + count = 0; + for(i = 0; i <= code_max; i++) { + de = &tab_de[i]; + if (de->len != 0) { + if (count++ % 8 == 0) + fprintf(f, "\n "); + fprintf(f, " 0x%04x,", de->data_index); + i += de->len - 1; + } + } + fprintf(f, "\n};\n\n"); + + fprintf(f, "static const uint8_t unicode_decomp_data[%u] = {", + data_len); + for(i = 0; i < data_len; i++) { + if (i % 8 == 0) + fprintf(f, "\n "); + fprintf(f, " 0x%02x,", data_buf[i]); + } + fprintf(f, "\n};\n\n"); + + build_compose_table(f, tab_de); + + free(data_buf); + + free(tab_de); +} + +typedef struct { + uint32_t c[2]; + uint32_t p; +} ComposeEntry; + +#define COMPOSE_LEN_MAX 10000 + +static int ce_cmp(const void *p1, const void *p2) +{ + const ComposeEntry *ce1 = p1; + const ComposeEntry *ce2 = p2; + int i; + + for(i = 0; i < 2; i++) { + if (ce1->c[i] < ce2->c[i]) + return -1; + else if (ce1->c[i] > ce2->c[i]) + return 1; + } + return 0; +} + + +static int get_decomp_pos(const DecompEntry *tab_de, int c) +{ + int i, v, k; + const DecompEntry *de; + + k = 0; + for(i = 0; i <= CHARCODE_MAX; i++) { + de = &tab_de[i]; + if (de->len != 0) { + if (c >= de->code && c < de->code + de->len) { + v = c - de->code; + assert(v < 64); + v |= k << 6; + assert(v < 65536); + return v; + } + i += de->len - 1; + k++; + } + } + return -1; +} + +void build_compose_table(FILE *f, const DecompEntry *tab_de) +{ + int i, v, tab_ce_len; + ComposeEntry *ce, *tab_ce; + + tab_ce = malloc(sizeof(*tab_ce) * COMPOSE_LEN_MAX); + tab_ce_len = 0; + for(i = 0; i <= CHARCODE_MAX; i++) { + CCInfo *ci = &unicode_db[i]; + if (ci->decomp_len == 2 && !ci->is_compat && + !ci->is_excluded) { + assert(tab_ce_len < COMPOSE_LEN_MAX); + ce = &tab_ce[tab_ce_len++]; + ce->c[0] = ci->decomp_data[0]; + ce->c[1] = ci->decomp_data[1]; + ce->p = i; + } + } + qsort(tab_ce, tab_ce_len, sizeof(*tab_ce), ce_cmp); + +#if 0 + { + printf("tab_ce_len=%d\n", tab_ce_len); + for(i = 0; i < tab_ce_len; i++) { + ce = &tab_ce[i]; + printf("%05x %05x %05x\n", ce->c[0], ce->c[1], ce->p); + } + } +#endif + + fprintf(f, "static const uint16_t unicode_comp_table[%u] = {", + tab_ce_len); + for(i = 0; i < tab_ce_len; i++) { + if (i % 8 == 0) + fprintf(f, "\n "); + v = get_decomp_pos(tab_de, tab_ce[i].p); + if (v < 0) { + printf("ERROR: entry for c=%04x not found\n", + tab_ce[i].p); + exit(1); + } + fprintf(f, " 0x%04x,", v); + } + fprintf(f, "\n};\n\n"); + + free(tab_ce); +} + +#ifdef USE_TEST +void check_decompose_table(void) +{ + int c; + CCInfo *ci; + int res[UNICODE_DECOMP_LEN_MAX], *ref; + int len, ref_len, is_compat; + + for(is_compat = 0; is_compat <= 1; is_compat++) { + for(c = 0; c < CHARCODE_MAX; c++) { + ci = &unicode_db[c]; + ref_len = ci->decomp_len; + ref = ci->decomp_data; + if (!is_compat && ci->is_compat) { + ref_len = 0; + } + len = unicode_decomp_char((uint32_t *)res, c, is_compat); + if (len != ref_len || + tabcmp(res, ref, ref_len) != 0) { + printf("ERROR c=%05x compat=%d\n", c, is_compat); + dump_str("res", res, len); + dump_str("ref", ref, ref_len); + exit(1); + } + } + } +} + +void check_compose_table(void) +{ + int i, p; + /* XXX: we don't test all the cases */ + + for(i = 0; i <= CHARCODE_MAX; i++) { + CCInfo *ci = &unicode_db[i]; + if (ci->decomp_len == 2 && !ci->is_compat && + !ci->is_excluded) { + p = unicode_compose_pair(ci->decomp_data[0], ci->decomp_data[1]); + if (p != i) { + printf("ERROR compose: c=%05x %05x -> %05x ref=%05x\n", + ci->decomp_data[0], ci->decomp_data[1], p, i); + exit(1); + } + } + } + + + +} + +#endif + + + +#ifdef USE_TEST + +void check_str(const char *msg, int num, const int *in_buf, int in_len, + const int *buf1, int len1, + const int *buf2, int len2) +{ + if (len1 != len2 || tabcmp(buf1, buf2, len1) != 0) { + printf("%d: ERROR %s:\n", num, msg); + dump_str(" in", in_buf, in_len); + dump_str("res", buf1, len1); + dump_str("ref", buf2, len2); + exit(1); + } +} + +void check_cc_table(void) +{ + int cc, cc_ref, c; + + for(c = 0; c <= CHARCODE_MAX; c++) { + cc_ref = unicode_db[c].combining_class; + cc = unicode_get_cc(c); + if (cc != cc_ref) { + printf("ERROR: c=%04x cc=%d cc_ref=%d\n", + c, cc, cc_ref); + exit(1); + } + } +#ifdef PROFILE + { + int64_t ti, count; + + ti = get_time_ns(); + count = 0; + /* only do it on meaningful chars */ + for(c = 0x20; c <= 0xffff; c++) { + cc_ref = unicode_db[c].combining_class; + cc = unicode_get_cc(c); + count++; + } + ti = get_time_ns() - ti; + printf("cc time=%0.1f ns/char\n", + (double)ti / count); + } +#endif +} + +void normalization_test(const char *filename) +{ + FILE *f; + char line[4096], *p; + int *in_str, *nfc_str, *nfd_str, *nfkc_str, *nfkd_str; + int in_len, nfc_len, nfd_len, nfkc_len, nfkd_len; + int *buf, buf_len, pos; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + exit(1); + } + pos = 0; + for(;;) { + if (!get_line(line, sizeof(line), f)) + break; + pos++; + p = line; + while (isspace(*p)) + p++; + if (*p == '#' || *p == '@') + continue; + in_str = get_field_str(&in_len, p, 0); + nfc_str = get_field_str(&nfc_len, p, 1); + nfd_str = get_field_str(&nfd_len, p, 2); + nfkc_str = get_field_str(&nfkc_len, p, 3); + nfkd_str = get_field_str(&nfkd_len, p, 4); + + // dump_str("in", in_str, in_len); + + buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFD, NULL, NULL); + check_str("nfd", pos, in_str, in_len, buf, buf_len, nfd_str, nfd_len); + free(buf); + + buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKD, NULL, NULL); + check_str("nfkd", pos, in_str, in_len, buf, buf_len, nfkd_str, nfkd_len); + free(buf); + + buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFC, NULL, NULL); + check_str("nfc", pos, in_str, in_len, buf, buf_len, nfc_str, nfc_len); + free(buf); + + buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKC, NULL, NULL); + check_str("nfkc", pos, in_str, in_len, buf, buf_len, nfkc_str, nfkc_len); + free(buf); + + free(in_str); + free(nfc_str); + free(nfd_str); + free(nfkc_str); + free(nfkd_str); + } + fclose(f); +} +#endif + +int main(int argc, char **argv) +{ + const char *unicode_db_path, *outfilename; + char filename[1024]; + + if (argc < 2) { + printf("usage: %s unicode_db_path [output_file]\n" + "\n" + "If no output_file is given, a self test is done using the current unicode library\n", + argv[0]); + exit(1); + } + unicode_db_path = argv[1]; + outfilename = NULL; + if (argc >= 3) + outfilename = argv[2]; + + unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1)); + + snprintf(filename, sizeof(filename), "%s/UnicodeData.txt", unicode_db_path); + + parse_unicode_data(filename); + + snprintf(filename, sizeof(filename), "%s/SpecialCasing.txt", unicode_db_path); + parse_special_casing(unicode_db, filename); + + snprintf(filename, sizeof(filename), "%s/CaseFolding.txt", unicode_db_path); + parse_case_folding(unicode_db, filename); + + snprintf(filename, sizeof(filename), "%s/CompositionExclusions.txt", unicode_db_path); + parse_composition_exclusions(filename); + + snprintf(filename, sizeof(filename), "%s/DerivedCoreProperties.txt", unicode_db_path); + parse_derived_core_properties(filename); + + snprintf(filename, sizeof(filename), "%s/DerivedNormalizationProps.txt", unicode_db_path); + parse_derived_norm_properties(filename); + + snprintf(filename, sizeof(filename), "%s/PropList.txt", unicode_db_path); + parse_prop_list(filename); + + snprintf(filename, sizeof(filename), "%s/Scripts.txt", unicode_db_path); + parse_scripts(filename); + + snprintf(filename, sizeof(filename), "%s/ScriptExtensions.txt", + unicode_db_path); + parse_script_extensions(filename); + + snprintf(filename, sizeof(filename), "%s/emoji-data.txt", + unicode_db_path); + parse_prop_list(filename); + + // dump_unicode_data(unicode_db); + build_conv_table(unicode_db); + +#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES + dump_case_folding_special_cases(unicode_db); +#endif + + if (!outfilename) { +#ifdef USE_TEST + check_case_conv(); + check_flags(); + check_decompose_table(); + check_compose_table(); + check_cc_table(); + snprintf(filename, sizeof(filename), "%s/NormalizationTest.txt", unicode_db_path); + normalization_test(filename); +#else + fprintf(stderr, "Tests are not compiled\n"); + exit(1); +#endif + } else + { + FILE *fo = fopen(outfilename, "wb"); + + if (!fo) { + perror(outfilename); + exit(1); + } + fprintf(fo, + "/* Compressed unicode tables */\n" + "/* Automatically generated file - do not edit */\n" + "\n" + "#include \n" + "\n"); + dump_case_conv_table(fo); + compute_internal_props(); + build_flags_tables(fo); + fprintf(fo, "#ifdef CONFIG_ALL_UNICODE\n\n"); + build_cc_table(fo); + build_decompose_table(fo); + build_general_category_table(fo); + build_script_table(fo); + build_script_ext_table(fo); + build_prop_list_table(fo); + fprintf(fo, "#endif /* CONFIG_ALL_UNICODE */\n"); + fclose(fo); + } + return 0; +} diff --git a/deps/quickjs/unicode_gen_def.h b/deps/quickjs/unicode_gen_def.h new file mode 100644 index 0000000..e7c2464 --- /dev/null +++ b/deps/quickjs/unicode_gen_def.h @@ -0,0 +1,291 @@ +#ifdef UNICODE_GENERAL_CATEGORY +DEF(Cn, "Unassigned") /* must be zero */ +DEF(Lu, "Uppercase_Letter") +DEF(Ll, "Lowercase_Letter") +DEF(Lt, "Titlecase_Letter") +DEF(Lm, "Modifier_Letter") +DEF(Lo, "Other_Letter") +DEF(Mn, "Nonspacing_Mark") +DEF(Mc, "Spacing_Mark") +DEF(Me, "Enclosing_Mark") +DEF(Nd, "Decimal_Number,digit") +DEF(Nl, "Letter_Number") +DEF(No, "Other_Number") +DEF(Sm, "Math_Symbol") +DEF(Sc, "Currency_Symbol") +DEF(Sk, "Modifier_Symbol") +DEF(So, "Other_Symbol") +DEF(Pc, "Connector_Punctuation") +DEF(Pd, "Dash_Punctuation") +DEF(Ps, "Open_Punctuation") +DEF(Pe, "Close_Punctuation") +DEF(Pi, "Initial_Punctuation") +DEF(Pf, "Final_Punctuation") +DEF(Po, "Other_Punctuation") +DEF(Zs, "Space_Separator") +DEF(Zl, "Line_Separator") +DEF(Zp, "Paragraph_Separator") +DEF(Cc, "Control,cntrl") +DEF(Cf, "Format") +DEF(Cs, "Surrogate") +DEF(Co, "Private_Use") +/* synthetic properties */ +DEF(LC, "Cased_Letter") +DEF(L, "Letter") +DEF(M, "Mark,Combining_Mark") +DEF(N, "Number") +DEF(S, "Symbol") +DEF(P, "Punctuation,punct") +DEF(Z, "Separator") +DEF(C, "Other") +#endif + +#ifdef UNICODE_SCRIPT +/* scripts aliases names in PropertyValueAliases.txt */ +DEF(Unknown, "Zzzz") +DEF(Adlam, "Adlm") +DEF(Ahom, "Ahom") +DEF(Anatolian_Hieroglyphs, "Hluw") +DEF(Arabic, "Arab") +DEF(Armenian, "Armn") +DEF(Avestan, "Avst") +DEF(Balinese, "Bali") +DEF(Bamum, "Bamu") +DEF(Bassa_Vah, "Bass") +DEF(Batak, "Batk") +DEF(Bengali, "Beng") +DEF(Bhaiksuki, "Bhks") +DEF(Bopomofo, "Bopo") +DEF(Brahmi, "Brah") +DEF(Braille, "Brai") +DEF(Buginese, "Bugi") +DEF(Buhid, "Buhd") +DEF(Canadian_Aboriginal, "Cans") +DEF(Carian, "Cari") +DEF(Caucasian_Albanian, "Aghb") +DEF(Chakma, "Cakm") +DEF(Cham, "Cham") +DEF(Cherokee, "Cher") +DEF(Chorasmian, "Chrs") +DEF(Common, "Zyyy") +DEF(Coptic, "Copt,Qaac") +DEF(Cuneiform, "Xsux") +DEF(Cypriot, "Cprt") +DEF(Cyrillic, "Cyrl") +DEF(Cypro_Minoan, "Cpmn") +DEF(Deseret, "Dsrt") +DEF(Devanagari, "Deva") +DEF(Dives_Akuru, "Diak") +DEF(Dogra, "Dogr") +DEF(Duployan, "Dupl") +DEF(Egyptian_Hieroglyphs, "Egyp") +DEF(Elbasan, "Elba") +DEF(Elymaic, "Elym") +DEF(Ethiopic, "Ethi") +DEF(Georgian, "Geor") +DEF(Glagolitic, "Glag") +DEF(Gothic, "Goth") +DEF(Grantha, "Gran") +DEF(Greek, "Grek") +DEF(Gujarati, "Gujr") +DEF(Gunjala_Gondi, "Gong") +DEF(Gurmukhi, "Guru") +DEF(Han, "Hani") +DEF(Hangul, "Hang") +DEF(Hanifi_Rohingya, "Rohg") +DEF(Hanunoo, "Hano") +DEF(Hatran, "Hatr") +DEF(Hebrew, "Hebr") +DEF(Hiragana, "Hira") +DEF(Imperial_Aramaic, "Armi") +DEF(Inherited, "Zinh,Qaai") +DEF(Inscriptional_Pahlavi, "Phli") +DEF(Inscriptional_Parthian, "Prti") +DEF(Javanese, "Java") +DEF(Kaithi, "Kthi") +DEF(Kannada, "Knda") +DEF(Katakana, "Kana") +DEF(Kawi, "Kawi") +DEF(Kayah_Li, "Kali") +DEF(Kharoshthi, "Khar") +DEF(Khmer, "Khmr") +DEF(Khojki, "Khoj") +DEF(Khitan_Small_Script, "Kits") +DEF(Khudawadi, "Sind") +DEF(Lao, "Laoo") +DEF(Latin, "Latn") +DEF(Lepcha, "Lepc") +DEF(Limbu, "Limb") +DEF(Linear_A, "Lina") +DEF(Linear_B, "Linb") +DEF(Lisu, "Lisu") +DEF(Lycian, "Lyci") +DEF(Lydian, "Lydi") +DEF(Makasar, "Maka") +DEF(Mahajani, "Mahj") +DEF(Malayalam, "Mlym") +DEF(Mandaic, "Mand") +DEF(Manichaean, "Mani") +DEF(Marchen, "Marc") +DEF(Masaram_Gondi, "Gonm") +DEF(Medefaidrin, "Medf") +DEF(Meetei_Mayek, "Mtei") +DEF(Mende_Kikakui, "Mend") +DEF(Meroitic_Cursive, "Merc") +DEF(Meroitic_Hieroglyphs, "Mero") +DEF(Miao, "Plrd") +DEF(Modi, "Modi") +DEF(Mongolian, "Mong") +DEF(Mro, "Mroo") +DEF(Multani, "Mult") +DEF(Myanmar, "Mymr") +DEF(Nabataean, "Nbat") +DEF(Nag_Mundari, "Nagm") +DEF(Nandinagari, "Nand") +DEF(New_Tai_Lue, "Talu") +DEF(Newa, "Newa") +DEF(Nko, "Nkoo") +DEF(Nushu, "Nshu") +DEF(Nyiakeng_Puachue_Hmong, "Hmnp") +DEF(Ogham, "Ogam") +DEF(Ol_Chiki, "Olck") +DEF(Old_Hungarian, "Hung") +DEF(Old_Italic, "Ital") +DEF(Old_North_Arabian, "Narb") +DEF(Old_Permic, "Perm") +DEF(Old_Persian, "Xpeo") +DEF(Old_Sogdian, "Sogo") +DEF(Old_South_Arabian, "Sarb") +DEF(Old_Turkic, "Orkh") +DEF(Old_Uyghur, "Ougr") +DEF(Oriya, "Orya") +DEF(Osage, "Osge") +DEF(Osmanya, "Osma") +DEF(Pahawh_Hmong, "Hmng") +DEF(Palmyrene, "Palm") +DEF(Pau_Cin_Hau, "Pauc") +DEF(Phags_Pa, "Phag") +DEF(Phoenician, "Phnx") +DEF(Psalter_Pahlavi, "Phlp") +DEF(Rejang, "Rjng") +DEF(Runic, "Runr") +DEF(Samaritan, "Samr") +DEF(Saurashtra, "Saur") +DEF(Sharada, "Shrd") +DEF(Shavian, "Shaw") +DEF(Siddham, "Sidd") +DEF(SignWriting, "Sgnw") +DEF(Sinhala, "Sinh") +DEF(Sogdian, "Sogd") +DEF(Sora_Sompeng, "Sora") +DEF(Soyombo, "Soyo") +DEF(Sundanese, "Sund") +DEF(Syloti_Nagri, "Sylo") +DEF(Syriac, "Syrc") +DEF(Tagalog, "Tglg") +DEF(Tagbanwa, "Tagb") +DEF(Tai_Le, "Tale") +DEF(Tai_Tham, "Lana") +DEF(Tai_Viet, "Tavt") +DEF(Takri, "Takr") +DEF(Tamil, "Taml") +DEF(Tangut, "Tang") +DEF(Telugu, "Telu") +DEF(Thaana, "Thaa") +DEF(Thai, "Thai") +DEF(Tibetan, "Tibt") +DEF(Tifinagh, "Tfng") +DEF(Tirhuta, "Tirh") +DEF(Tangsa, "Tnsa") +DEF(Toto, "Toto") +DEF(Ugaritic, "Ugar") +DEF(Vai, "Vaii") +DEF(Vithkuqi, "Vith") +DEF(Wancho, "Wcho") +DEF(Warang_Citi, "Wara") +DEF(Yezidi, "Yezi") +DEF(Yi, "Yiii") +DEF(Zanabazar_Square, "Zanb") +#endif + +#ifdef UNICODE_PROP_LIST +/* Prop list not exported to regexp */ +DEF(Hyphen, "") +DEF(Other_Math, "") +DEF(Other_Alphabetic, "") +DEF(Other_Lowercase, "") +DEF(Other_Uppercase, "") +DEF(Other_Grapheme_Extend, "") +DEF(Other_Default_Ignorable_Code_Point, "") +DEF(Other_ID_Start, "") +DEF(Other_ID_Continue, "") +DEF(Prepended_Concatenation_Mark, "") +/* additional computed properties for smaller tables */ +DEF(ID_Continue1, "") +DEF(XID_Start1, "") +DEF(XID_Continue1, "") +DEF(Changes_When_Titlecased1, "") +DEF(Changes_When_Casefolded1, "") +DEF(Changes_When_NFKC_Casefolded1, "") + +/* Prop list exported to JS */ +DEF(ASCII_Hex_Digit, "AHex") +DEF(Bidi_Control, "Bidi_C") +DEF(Dash, "") +DEF(Deprecated, "Dep") +DEF(Diacritic, "Dia") +DEF(Extender, "Ext") +DEF(Hex_Digit, "Hex") +DEF(IDS_Binary_Operator, "IDSB") +DEF(IDS_Trinary_Operator, "IDST") +DEF(Ideographic, "Ideo") +DEF(Join_Control, "Join_C") +DEF(Logical_Order_Exception, "LOE") +DEF(Noncharacter_Code_Point, "NChar") +DEF(Pattern_Syntax, "Pat_Syn") +DEF(Pattern_White_Space, "Pat_WS") +DEF(Quotation_Mark, "QMark") +DEF(Radical, "") +DEF(Regional_Indicator, "RI") +DEF(Sentence_Terminal, "STerm") +DEF(Soft_Dotted, "SD") +DEF(Terminal_Punctuation, "Term") +DEF(Unified_Ideograph, "UIdeo") +DEF(Variation_Selector, "VS") +DEF(White_Space, "space") +DEF(Bidi_Mirrored, "Bidi_M") +DEF(Emoji, "") +DEF(Emoji_Component, "EComp") +DEF(Emoji_Modifier, "EMod") +DEF(Emoji_Modifier_Base, "EBase") +DEF(Emoji_Presentation, "EPres") +DEF(Extended_Pictographic, "ExtPict") +DEF(Default_Ignorable_Code_Point, "DI") +DEF(ID_Start, "IDS") +DEF(Case_Ignorable, "CI") + +/* other binary properties */ +DEF(ASCII,"") +DEF(Alphabetic, "Alpha") +DEF(Any, "") +DEF(Assigned,"") +DEF(Cased, "") +DEF(Changes_When_Casefolded, "CWCF") +DEF(Changes_When_Casemapped, "CWCM") +DEF(Changes_When_Lowercased, "CWL") +DEF(Changes_When_NFKC_Casefolded, "CWKCF") +DEF(Changes_When_Titlecased, "CWT") +DEF(Changes_When_Uppercased, "CWU") +DEF(Grapheme_Base, "Gr_Base") +DEF(Grapheme_Extend, "Gr_Ext") +DEF(ID_Continue, "IDC") +DEF(Lowercase, "Lower") +DEF(Math, "") +DEF(Uppercase, "Upper") +DEF(XID_Continue, "XIDC") +DEF(XID_Start, "XIDS") + +/* internal tables with index */ +DEF(Cased1, "") + +#endif diff --git a/include/Makefile b/include/Makefile deleted file mode 100644 index 5a9271a..0000000 --- a/include/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -STYLE := "{BasedOnStyle: Google, TabWidth: 4, IndentWidth: 4, UseTab: Never, SortIncludes: false, ColumnLimit: 120}" - -fmt: - clang-format -i -style=$(STYLE) *.c *.h - clang-format -i -style=$(STYLE) c-stdlib/*.h - clang-format -i -style=$(STYLE) c-stdlib/src/*.c - clang-format -i -style=$(STYLE) ../quickjs/qjs.c ../quickjs/std_module.c ../quickjs/std_module.h ../quickjs/ckb_module.c ../quickjs/ckb_module.h diff --git a/include/c-stdlib/README.md b/include/c-stdlib/README.md deleted file mode 100644 index 49bd744..0000000 --- a/include/c-stdlib/README.md +++ /dev/null @@ -1 +0,0 @@ -They're from C standard library but not suitable to be included in ckb-c-stdlib. diff --git a/include/c-stdlib/my_assert.h b/include/c-stdlib/my_assert.h deleted file mode 100644 index 3d24118..0000000 --- a/include/c-stdlib/my_assert.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef C_STDLIB_ASSERT_H_ -#define C_STDLIB_ASSERT_H_ - -int ckb_exit(signed char); - -#define assert(s) \ - do { \ - if (!(s)) { \ - printf("Failed at %s:%d: %s\n", __FILE__, __LINE__, (#s)); \ - ckb_exit(-1); \ - } \ - } while (0) - -#endif // C_STDLIB_ASSERT_H_ diff --git a/include/c-stdlib/my_float.h b/include/c-stdlib/my_float.h deleted file mode 100644 index e508a5c..0000000 --- a/include/c-stdlib/my_float.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef _STDLIB_FLOAT_H_ -#define _STDLIB_FLOAT_H_ - -#include - -#undef FLT_MAX -#undef DBL_MAX -#undef LDBL_MAX -#define FLT_MAX __FLT_MAX__ -#define DBL_MAX __DBL_MAX__ -#define LDBL_MAX __LDBL_MAX__ - -typedef union { - double value; - struct { - uint32_t lsw; - uint32_t msw; - } parts; - struct { - uint64_t w; - } xparts; -} ieee_double_shape_type; - -/* Get two 32 bit ints from a double. */ - -#define EXTRACT_WORDS(ix0, ix1, d) \ - do { \ - ieee_double_shape_type ew_u; \ - ew_u.value = (d); \ - (ix0) = ew_u.parts.msw; \ - (ix1) = ew_u.parts.lsw; \ - } while (0) - -/* Get the more significant 32 bit int from a double. */ - -#define GET_HIGH_WORD(i, d) \ - do { \ - ieee_double_shape_type gh_u; \ - gh_u.value = (d); \ - (i) = gh_u.parts.msw; \ - } while (0) - -/* Get the less significant 32 bit int from a double. */ - -#define GET_LOW_WORD(i, d) \ - do { \ - ieee_double_shape_type gl_u; \ - gl_u.value = (d); \ - (i) = gl_u.parts.lsw; \ - } while (0) - -/* Set the more significant 32 bits of a double from an int. */ - -#define SET_HIGH_WORD(d, v) \ - do { \ - ieee_double_shape_type sh_u; \ - sh_u.value = (d); \ - sh_u.parts.msw = (v); \ - (d) = sh_u.value; \ - } while (0) - -/* Set the less significant 32 bits of a double from an int. */ - -#define SET_LOW_WORD(d, v) \ - do { \ - ieee_double_shape_type sl_u; \ - sl_u.value = (d); \ - sl_u.parts.lsw = (v); \ - (d) = sl_u.value; \ - } while (0) - -static const double ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ - ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ - two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ - twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ - huge = 1.0e+300, tiny = 1.0e-300, Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ - Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ - Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ - Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ - Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ - Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ - Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - -static const double zero = 0.0; - -static const double bp[] = - { - 1.0, - 1.5, -}, - dp_h[] = - { - 0.0, - 5.84962487220764160156e-01, -}, /* 0x3FE2B803, 0x40000000 */ - dp_l[] = - { - 0.0, - 1.35003920212974897128e-08, -}, /* 0x3E4CFDEB, 0x43CFD006 */ - one = 1.0, two = 2.0, two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ - /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ - L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ - L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ - L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ - L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ - L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ - L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ - P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ - P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ - P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ - P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ - P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ - lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ - lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ - lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ - ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ - cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ - cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ - cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ - ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ - ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ - ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ - -#endif diff --git a/include/c-stdlib/my_locale.h b/include/c-stdlib/my_locale.h deleted file mode 100644 index 6b9848f..0000000 --- a/include/c-stdlib/my_locale.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _STDLIB_LOCALE_H_ -#define _STDLIB_LOCALE_H_ -#ifdef __cplusplus -extern "C" { -#endif - -struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; - - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - char int_p_cs_precedes; - char int_p_sep_by_space; - char int_n_cs_precedes; - char int_n_sep_by_space; - char int_p_sign_posn; - char int_n_sign_posn; -}; - -struct lconv *localeconv(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/c-stdlib/my_stddef.h b/include/c-stdlib/my_stddef.h deleted file mode 100644 index 5cbe8c4..0000000 --- a/include/c-stdlib/my_stddef.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _C_STDLIB_STDDEF_H_ -#define _C_STDLIB_STDDEF_H_ - -typedef signed long ptrdiff_t; -typedef long long intmax_t; - -#endif /* _C_STDLIB_STDDEF_H_ */ diff --git a/include/c-stdlib/my_stdint.h b/include/c-stdlib/my_stdint.h deleted file mode 100644 index 2f039f2..0000000 --- a/include/c-stdlib/my_stdint.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _STDINT_H -#define _STDINT_H 1 - -#define INTPTR_MIN (-9223372036854775807L - 1) -#define INTPTR_MAX (9223372036854775807L) -#define UINTPTR_MAX (18446744073709551615UL) - -#define INT8_C(c) c -#define INT16_C(c) c -#define INT32_C(c) c - -#define UINT8_C(c) c -#define UINT16_C(c) c -#define UINT32_C(c) c##U - -#if UINTPTR_MAX == UINT64_MAX -#define INT64_C(c) c##L -#define UINT64_C(c) c##UL -#define INTMAX_C(c) c##L -#define UINTMAX_C(c) c##UL -#else -#define INT64_C(c) c##LL -#define UINT64_C(c) c##ULL -#define INTMAX_C(c) c##LL -#define UINTMAX_C(c) c##ULL -#endif - -#endif diff --git a/include/c-stdlib/my_stdio.h b/include/c-stdlib/my_stdio.h deleted file mode 100644 index 1d7e55e..0000000 --- a/include/c-stdlib/my_stdio.h +++ /dev/null @@ -1,117 +0,0 @@ - -#ifndef _STDIO_H -#define _STDIO_H 1 - -#include -#include -#include - -#include "../../include/ckb_cell_fs.h" - -#define BUFSIZ 512 -#define EOF (-1) -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - -#define _IOFBF 0 -#define _IOLBF 1 -#define _IONBF 2 - -typedef struct FILE { - FSFile *file; - uint32_t offset; -} FILE; - -extern FILE *stdin; -extern FILE *stdout; -extern FILE *stderr; - -int remove(const char *__filename); - -int rename(const char *__old, const char *__new); - -FILE *tmpfile(void); - -char *tmpnam(char *__s); - -char *tempnam(const char *__dir, const char *__pfx); - -int fclose(FILE *__stream); -int fflush(FILE *__stream); - -FILE *fopen(const char *__filename, const char *__modes); -FILE *freopen(const char *__filename, const char *__modes, FILE *__stream); - -void setbuf(FILE *__stream, char *__buf); -int setvbuf(FILE *__stream, char *__buf, int __modes, size_t __n); - -int fprintf(FILE *__stream, const char *__format, ...); - -int printf(const char *format, ...); - -int sprintf(char *__s, const char *__format, ...); - -int vfprintf(FILE *__s, const char *__format, ...); - -int vsprintf(char *__s, const char *__format, ...); -int vsnprintf(char *__s, size_t __maxlen, const char *__format, ...); -int snprintf(char *__s, size_t __maxlen, const char *__format, ...); -int snprintf_(char *__s, size_t __maxlen, const char *__format, ...); - -int fscanf(FILE *__stream, const char *__format, ...); - -int scanf(const char *__format, ...); - -int sscanf(const char *__s, const char *__format, ...); - -int fgetc(FILE *__stream); - -int getc(FILE *__stream); - -int getchar(void); - -int fputc(int __c, FILE *__stream); - -int putc(int __c, FILE *__stream); - -int putchar(int __c); - -char *fgets(char *__s, int __n, FILE *__stream); -char *gets(char *__s); - -int getline(char **__lineptr, size_t *__n, FILE *__stream); - -int fputs(const char *__s, FILE *__stream); - -int puts(const char *__s); - -int ungetc(int __c, FILE *__stream); - -size_t fread(void *__ptr, size_t __size, size_t __n, FILE *__stream); - -size_t fwrite(const void *__ptr, size_t __size, size_t __n, FILE *__s); - -int fseek(FILE *__stream, long int __off, int __whence); - -long int ftell(FILE *__stream); - -void rewind(FILE *__stream); - -void clearerr(FILE *__stream); - -int feof(FILE *__stream); - -int ferror(FILE *__stream); - -void perror(const char *__s); - -int fileno(FILE *__stream); - -FILE *popen(const char *__command, const char *__modes); - -int pclose(FILE *__stream); - -void enable_local_access(int); - -#endif /* included. */ diff --git a/include/c-stdlib/my_stdlib.h b/include/c-stdlib/my_stdlib.h deleted file mode 100644 index ca5f292..0000000 --- a/include/c-stdlib/my_stdlib.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef C_STDLIB_STDLIB_H_ -#define C_STDLIB_STDLIB_H_ - -float strtof(const char *__restrict, char **__restrict); -double strtod(const char *__restrict, char **__restrict); -long double strtold(const char *__restrict, char **__restrict); -int atoi(const char *); - -int abs(int); -void exit(int); -void abort(void); -#define alloca __builtin_alloca - -#endif /* C_STDLIB_STDLIB_H_ */ diff --git a/include/c-stdlib/my_string.h b/include/c-stdlib/my_string.h deleted file mode 100644 index 9c551e8..0000000 --- a/include/c-stdlib/my_string.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef C_STDLIB_STRING_H_ -#define C_STDLIB_STRING_H_ - -#include - -char *strchr(const char *, int); -int strncmp(const char *_l, const char *_r, size_t n); -char *strpbrk(const char *, const char *); -size_t strcspn(const char *, const char *); -size_t strspn(const char *, const char *); -void *memchr(const void *, int, size_t); -char *strrchr(const char *str, int character); -char *strcat(char *destination, const char *source); - -int strcoll(const char *, const char *); - -char *strerror(int); - -#endif /* C_STDLIB_STRING_H_ */ diff --git a/include/c-stdlib/src/malloc_impl.c b/include/c-stdlib/src/malloc_impl.c deleted file mode 100644 index 22ed241..0000000 --- a/include/c-stdlib/src/malloc_impl.c +++ /dev/null @@ -1,398 +0,0 @@ -#define CKB_MALLOC_DECLARATION_ONLY 1 -#include -#include -#include -#include - -#ifndef CKB_BRK_MIN -extern char _end[]; /* _end is set in the linker */ -#define CKB_BRK_MIN ((uintptr_t)&_end) -#endif -#ifndef CKB_BRK_MAX -#define CKB_BRK_MAX 0x00300000 -#endif - -struct chunk { - size_t psize, csize; - struct chunk *next, *prev; -}; - -struct bin { - volatile int lock[2]; - struct chunk *head; - struct chunk *tail; -}; - -#define CKB_SIZE_ALIGN (4 * sizeof(size_t)) -#define CKB_SIZE_MASK (-CKB_SIZE_ALIGN) -#define CKB_OVERHEAD (2 * sizeof(size_t)) -#define CKB_DONTCARE 16 -#define CKB_RECLAIM 163840 -#define CKB_MMAP_THRESHOLD (0x1c00 * CKB_SIZE_ALIGN) - -#define CKB_CHUNK_SIZE(c) ((c)->csize & -2) -#define CKB_CHUNK_PSIZE(c) ((c)->psize & -2) -#define CKB_PREV_CHUNK(c) ((struct chunk *)((char *)(c)-CKB_CHUNK_PSIZE(c))) -#define CKB_NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CKB_CHUNK_SIZE(c))) -#define CKB_MEM_TO_CHUNK(p) (struct chunk *)((char *)(p)-CKB_OVERHEAD) -#define CKB_CHUNK_TO_MEM(c) (void *)((char *)(c) + CKB_OVERHEAD) -#define CKB_BIN_TO_CHUNK(i) (CKB_MEM_TO_CHUNK(&mal.bins[i].head)) -#define CKB_C_INUSE ((size_t)1) -#define CKB_IS_MMAPPED(c) !((c)->csize & (CKB_C_INUSE)) -#define CKB_PAGE_SIZE 4096 -void __bin_chunk(struct chunk *); -int ckb_exit(int8_t code); -static inline void a_crash() { ckb_exit(-1); } -void free(void *p); - -static inline void a_and_64(volatile uint64_t *p, uint64_t v) { *p &= v; } - -static inline void a_or_64(volatile uint64_t *p, uint64_t v) { *p |= v; } - -static uintptr_t s_program_break = 0; -static uintptr_t s_brk_min = CKB_BRK_MIN; -static uintptr_t s_brk_max = CKB_BRK_MAX; - -void malloc_config(uintptr_t min, uintptr_t max) { - s_brk_min = min; - s_brk_max = max; - s_program_break = 0; -} - -size_t malloc_usage() { - size_t high = (size_t)s_program_break; - size_t low = (size_t)s_brk_min; - return high - low; -} - -void *_sbrk(uintptr_t incr) { - if (!s_program_break) { - s_program_break = s_brk_min; - s_program_break += -s_program_break & (CKB_PAGE_SIZE - 1); - } - if ((s_program_break + incr) > s_brk_max) { - return (void *)-1; - } - - uintptr_t start = s_program_break; - s_program_break += incr; - return (void *)start; -} - -static struct { - volatile uint64_t binmap; - struct bin bins[64]; - volatile int split_merge_lock[2]; -} mal; - -static inline void lock_bin(int i) { - if (!mal.bins[i].head) mal.bins[i].head = mal.bins[i].tail = CKB_BIN_TO_CHUNK(i); -} - -static inline void unlock_bin(int i) {} - -#if 0 -static int first_set(uint64_t x) { - // TODO: use RISC-V asm - static const char debruijn64[64] = { - 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; - static const char debruijn32[32] = { - 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, - 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; - if (sizeof(long) < 8) { - uint32_t y = x; - if (!y) { - y = x >> 32; - return 32 + debruijn32[(y & -y) * 0x076be629 >> 27]; - } - return debruijn32[(y & -y) * 0x076be629 >> 27]; - } - return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; -} - -#else - -static int __attribute__((naked)) first_set(uint64_t x) { - __asm__(".byte 0x13, 0x15, 0x15, 0x60"); - __asm__("ret"); -} - -#endif - -static const unsigned char bin_tab[60] = { - 32, 33, 34, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, - 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, - 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, -}; - -static int bin_index(size_t x) { - x = x / CKB_SIZE_ALIGN - 1; - if (x <= 32) return x; - if (x < 512) return bin_tab[x / 8 - 4]; - if (x > 0x1c00) return 63; - return bin_tab[x / 128 - 4] + 16; -} - -static int bin_index_up(size_t x) { - x = x / CKB_SIZE_ALIGN - 1; - if (x <= 32) return x; - x--; - if (x < 512) return bin_tab[x / 8 - 4] + 1; - return bin_tab[x / 128 - 4] + 17; -} - -static void *__expand_heap(size_t *pn) { - size_t n = *pn; - n += -n & (CKB_PAGE_SIZE - 1); - - void *p = _sbrk(n); - if (p == (void *)-1) { - return 0; - } - *pn = n; - return p; -} - -static struct chunk *expand_heap(size_t n) { - static void *end; - void *p; - struct chunk *w; - - /* The argument n already accounts for the caller's chunk - * CKB_OVERHEAD needs, but if the heap can't be extended in-place, - * we need room for an extra zero-sized sentinel chunk. */ - n += CKB_SIZE_ALIGN; - - p = __expand_heap(&n); - if (!p) return 0; - /* If not just expanding existing space, we need to make a - * new sentinel chunk below the allocated space. */ - if (p != end) { - /* Valid/safe because of the prologue increment. */ - n -= CKB_SIZE_ALIGN; - p = (char *)p + CKB_SIZE_ALIGN; - w = CKB_MEM_TO_CHUNK(p); - w->psize = 0 | CKB_C_INUSE; - } - - /* Record new heap end and fill in footer. */ - end = (char *)p + n; - w = CKB_MEM_TO_CHUNK(end); - w->psize = n | CKB_C_INUSE; - w->csize = 0 | CKB_C_INUSE; - - /* Fill in header, which may be new or may be replacing a - * zero-size sentinel header at the old end-of-heap. */ - w = CKB_MEM_TO_CHUNK(p); - w->csize = n | CKB_C_INUSE; - - return w; -} - -static int adjust_size(size_t *n) { - /* Result of pointer difference must fit in ptrdiff_t. */ - if (*n - 1 > INT64_MAX - CKB_SIZE_ALIGN - CKB_PAGE_SIZE) { - if (*n) { - return -1; - } else { - *n = CKB_SIZE_ALIGN; - return 0; - } - } - *n = (*n + CKB_OVERHEAD + CKB_SIZE_ALIGN - 1) & CKB_SIZE_MASK; - return 0; -} - -static void unbin(struct chunk *c, int i) { - if (c->prev == c->next) a_and_64(&mal.binmap, ~(1ULL << i)); - c->prev->next = c->next; - c->next->prev = c->prev; - c->csize |= CKB_C_INUSE; - CKB_NEXT_CHUNK(c)->psize |= CKB_C_INUSE; -} - -static void bin_chunk(struct chunk *self, int i) { - self->next = CKB_BIN_TO_CHUNK(i); - self->prev = mal.bins[i].tail; - self->next->prev = self; - self->prev->next = self; - if (self->prev == CKB_BIN_TO_CHUNK(i)) a_or_64(&mal.binmap, 1ULL << i); -} - -static void trim(struct chunk *self, size_t n) { - size_t n1 = CKB_CHUNK_SIZE(self); - struct chunk *next, *split; - - if (n >= n1 - CKB_DONTCARE) return; - - next = CKB_NEXT_CHUNK(self); - split = (void *)((char *)self + n); - - split->psize = n | CKB_C_INUSE; - split->csize = n1 - n; - next->psize = n1 - n; - self->csize = n | CKB_C_INUSE; - - int i = bin_index(n1 - n); - lock_bin(i); - - bin_chunk(split, i); - - unlock_bin(i); -} - -void *malloc(size_t n) { - struct chunk *c; - int i, j; - uint64_t mask; - - if (adjust_size(&n) < 0) return 0; - - if (n >= CKB_MMAP_THRESHOLD) { - // TODO: don't support too large memory - return 0; - } - - i = bin_index_up(n); - if (i < 63 && (mal.binmap & (1ULL << i))) { - lock_bin(i); - c = mal.bins[i].head; - if (c != CKB_BIN_TO_CHUNK(i) && CKB_CHUNK_SIZE(c) - n <= CKB_DONTCARE) { - unbin(c, i); - unlock_bin(i); - return CKB_CHUNK_TO_MEM(c); - } - unlock_bin(i); - } - for (mask = mal.binmap & -(1ULL << i); mask; mask -= (mask & -mask)) { - j = first_set(mask); - lock_bin(j); - c = mal.bins[j].head; - if (c != CKB_BIN_TO_CHUNK(j)) { - unbin(c, j); - unlock_bin(j); - break; - } - unlock_bin(j); - } - if (!mask) { - c = expand_heap(n); - if (!c) { - return 0; - } - } - trim(c, n); - return CKB_CHUNK_TO_MEM(c); -} - -void *realloc(void *p, size_t n) { - struct chunk *self, *next; - size_t n0; - void *new; - - if (!p) return malloc(n); - - if (adjust_size(&n) < 0) return 0; - - self = CKB_MEM_TO_CHUNK(p); - n0 = CKB_CHUNK_SIZE(self); - - if (n <= n0 && n0 - n <= CKB_DONTCARE) return p; - - next = CKB_NEXT_CHUNK(self); - - /* Crash on corrupted footer (likely from buffer overflow) */ - if (next->psize != self->csize) a_crash(); - - if (n < n0) { - int i = bin_index_up(n); - int j = bin_index(n0); - if (i < j && (mal.binmap & (1ULL << i))) goto copy_realloc; - struct chunk *split = (void *)((char *)self + n); - self->csize = split->psize = n | CKB_C_INUSE; - split->csize = next->psize = (n0 - n) | CKB_C_INUSE; - __bin_chunk(split); - return CKB_CHUNK_TO_MEM(self); - } - - size_t nsize = next->csize & CKB_C_INUSE ? 0 : CKB_CHUNK_SIZE(next); - if (n0 + nsize >= n) { - int i = bin_index(nsize); - lock_bin(i); - if (!(next->csize & CKB_C_INUSE)) { - unbin(next, i); - unlock_bin(i); - next = CKB_NEXT_CHUNK(next); - self->csize = next->psize = (n0 + nsize) | CKB_C_INUSE; - trim(self, n); - return CKB_CHUNK_TO_MEM(self); - } - unlock_bin(i); - } -copy_realloc: - /* As a last resort, allocate a new chunk and copy to it. */ - new = malloc(n - CKB_OVERHEAD); - if (!new) return 0; - memcpy(new, p, (n < n0 ? n : n0) - CKB_OVERHEAD); - free(CKB_CHUNK_TO_MEM(self)); - return new; -} - -void __bin_chunk(struct chunk *self) { - struct chunk *next = CKB_NEXT_CHUNK(self); - - /* Crash on corrupted footer (likely from buffer overflow) */ - if (next->psize != self->csize) a_crash(); - - size_t osize = CKB_CHUNK_SIZE(self), size = osize; - - /* Since we hold split_merge_lock, only transition from free to - * in-use can race; in-use to free is impossible */ - size_t psize = self->psize & CKB_C_INUSE ? 0 : CKB_CHUNK_PSIZE(self); - size_t nsize = next->csize & CKB_C_INUSE ? 0 : CKB_CHUNK_SIZE(next); - - if (psize) { - int i = bin_index(psize); - lock_bin(i); - if (!(self->psize & CKB_C_INUSE)) { - struct chunk *prev = CKB_PREV_CHUNK(self); - unbin(prev, i); - self = prev; - size += psize; - } - unlock_bin(i); - } - if (nsize) { - int i = bin_index(nsize); - lock_bin(i); - if (!(next->csize & CKB_C_INUSE)) { - unbin(next, i); - next = CKB_NEXT_CHUNK(next); - size += nsize; - } - unlock_bin(i); - } - - int i = bin_index(size); - lock_bin(i); - - self->csize = size; - next->psize = size; - bin_chunk(self, i); - - unlock_bin(i); -} - -void free(void *p) { - if (!p) return; - struct chunk *self = CKB_MEM_TO_CHUNK(p); - __bin_chunk(self); -} - -size_t malloc_usable_size(void *ptr) { - struct chunk *c = CKB_MEM_TO_CHUNK(ptr); - return CKB_CHUNK_PSIZE(c); -} diff --git a/include/c-stdlib/src/math_impl.c b/include/c-stdlib/src/math_impl.c deleted file mode 100644 index ce38a64..0000000 --- a/include/c-stdlib/src/math_impl.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "../my_math.h" -#include -#include "my_stdio.h" -#include "my_assert.h" - -#ifndef DBL_EPSILON -#define DBL_EPSILON 2.22044604925031308085e-16 -#endif - -double acos(double x) { - assert(0); - return 0; -} - -double asin(double x) { - assert(0); - return 0; -} - -double atan2(double x, double y) { - assert(0); - return 0; -} - -double cos(double x) { - assert(0); - return 0; -} - -double cosh(double x) { - assert(0); - return 0; -} - -double exp(double x) { - assert(0); - return 0; -} - -#define EPS DBL_EPSILON -double floor(double x) { - static const double toint = 1 / EPS; - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff + 52 || x == 0) return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - if (u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - /* special case because of non-nearest rounding modes */ - if (e <= 0x3ff - 1) { - FORCE_EVAL(y); - return u.i >> 63 ? -1 : 0; - } - if (y > 0) return x + y - 1; - return x + y; -} - -double ceil(double x) { - static const double toint = 1 / EPS; - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - double y; - - if (e >= 0x3ff + 52 || x == 0) return x; - /* y = int(x) - x, where int(x) is an integer neighbor of x */ - if (u.i >> 63) - y = x - toint + toint - x; - else - y = x + toint - toint - x; - /* special case because of non-nearest rounding modes */ - if (e <= 0x3ff - 1) { - FORCE_EVAL(y); - return u.i >> 63 ? -0.0 : 1; - } - if (y < 0) return x + y + 1; - return x + y; -} - -double fabs(double x) { - union { - double f; - uint64_t i; - } u = {x}; - u.i &= -1ULL / 2; - return u.f; -} - -double ldexp(double x, int n) { return scalbn(x, n); } - -double log2(double x) { - assert(0); - return 0; -} - -double log10(double x) { - assert(0); - return 0; -} - -double sin(double x) { - assert(0); - return 0; -} - -double sinh(double x) { - assert(0); - return 0; -} - -double sqrt(double x) { - assert(0); - return 0; -} - -double tan(double x) { - assert(0); - return 0; -} - -double tanh(double x) { - assert(0); - return 0; -} - -double rint(double x) { - static const double toint = 1 / EPS; - union { - double f; - uint64_t i; - } u = {x}; - int e = u.i >> 52 & 0x7ff; - int s = u.i >> 63; - double y; - - if (e >= 0x3ff + 52) return x; - if (s) - y = x - toint + toint; - else - y = x + toint - toint; - if (y == 0) return s ? -0.0 : 0; - return y; -} - -long int lrint(double x) { return rint(x); } - -double cbrt(double x) { - assert(0); - return 0; -} - -double fmod(double numer, double denom); - -double fmin(double x, double y) { return x > y ? y : x; } - -double fmax(double x, double y) { return x < y ? y : x; } - -double hypot(double x, double y) { - assert(0); - return 0; -} - -int signbit(double num) { return num > 0; } - -double frexp(double x, int *e) { - union { - double d; - uint64_t i; - } y = {x}; - int ee = y.i >> 52 & 0x7ff; - - if (!ee) { - if (x) { - x = frexp(x * 0x1p64, e); - *e -= 64; - } else - *e = 0; - return x; - } else if (ee == 0x7ff) { - return x; - } - - *e = ee - 0x3fe; - y.i &= 0x800fffffffffffffull; - y.i |= 0x3fe0000000000000ull; - return y.d; -} - -double fmod(double x, double y) { - union { - double f; - uint64_t i; - } ux = {x}, uy = {y}; - int ex = ux.i >> 52 & 0x7ff; - int ey = uy.i >> 52 & 0x7ff; - int sx = ux.i >> 63; - uint64_t i; - - /* in the followings uxi should be ux.i, but then gcc wrongly adds */ - /* float load/store to inner loops ruining performance and code size */ - uint64_t uxi = ux.i; - - if (uy.i << 1 == 0 || __builtin_isnan(y) || ex == 0x7ff) return (x * y) / (x * y); - if (uxi << 1 <= uy.i << 1) { - if (uxi << 1 == uy.i << 1) return 0 * x; - return x; - } - - /* normalize x and y */ - if (!ex) { - for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) - ; - uxi <<= -ex + 1; - } else { - uxi &= -1ULL >> 12; - uxi |= 1ULL << 52; - } - if (!ey) { - for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) - ; - uy.i <<= -ey + 1; - } else { - uy.i &= -1ULL >> 12; - uy.i |= 1ULL << 52; - } - - /* x mod y */ - for (; ex > ey; ex--) { - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) return 0 * x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) return 0 * x; - uxi = i; - } - for (; uxi >> 52 == 0; uxi <<= 1, ex--) - ; - - /* scale result */ - if (ex > 0) { - uxi -= 1ULL << 52; - uxi |= (uint64_t)ex << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= (uint64_t)sx << 63; - ux.i = uxi; - return ux.f; -} - -int abs(int a) { return a > 0 ? a : -a; } diff --git a/include/c-stdlib/src/math_pow_impl.c b/include/c-stdlib/src/math_pow_impl.c deleted file mode 100644 index b9ff050..0000000 --- a/include/c-stdlib/src/math_pow_impl.c +++ /dev/null @@ -1,329 +0,0 @@ -/* @(#)e_pow.c 1.5 04/04/22 SMI */ -/* - * ==================================================== - * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. - * - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -//__FBSDID("$FreeBSD: src/lib/msun/src/e_pow.c,v 1.14 2011/10/21 06:26:07 das -// Exp $"); - -/* __ieee754_pow(x,y) return x**y - * - * n - * Method: Let x = 2 * (1+f) - * 1. Compute and return log2(x) in two pieces: - * log2(x) = w1 + w2, - * where w1 has 53-24 = 29 bit trailing zeros. - * 2. Perform y*log2(x) = n+y' by simulating muti-precision - * arithmetic, where |y'|<=0.5. - * 3. Return x**y = 2**n*exp(y'*log2) - * - * Special cases: - * 1. (anything) ** 0 is 1 - * 2. (anything) ** 1 is itself - * 3. (anything) ** NAN is NAN - * 4. NAN ** (anything except 0) is NAN - * 5. +-(|x| > 1) ** +INF is +INF - * 6. +-(|x| > 1) ** -INF is +0 - * 7. +-(|x| < 1) ** +INF is +0 - * 8. +-(|x| < 1) ** -INF is +INF - * 9. +-1 ** +-INF is NAN - * 10. +0 ** (+anything except 0, NAN) is +0 - * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - * 12. +0 ** (-anything except 0, NAN) is +INF - * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF - * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) - * 15. +INF ** (+anything except 0,NAN) is +INF - * 16. +INF ** (-anything except 0,NAN) is +0 - * 17. -INF ** (anything) = -0 ** (-anything) - * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) - * 19. (-anything except 0 and inf) ** (non-integer) is NAN - * - * Accuracy: - * pow(x,y) returns x**y nearly rounded. In particular - * pow(integer,integer) - * always returns the correct integer provided it is - * representable. - * - * Constants : - * The hexadecimal values are the intended ones for the following - * constants. The decimal values may be used, provided that the - * compiler will convert from decimal to binary accurately enough - * to produce the hexadecimal values shown. - */ -#include "my_float.h" -#include "my_math.h" -#include - -double copysign(double x, double y) { - uint32_t hx, hy; - GET_HIGH_WORD(hx, x); - GET_HIGH_WORD(hy, y); - SET_HIGH_WORD(x, (hx & 0x7fffffff) | (hy & 0x80000000)); - return x; -} - -double scalbn(double x, int n) { - int32_t k, hx, lx; - EXTRACT_WORDS(hx, lx, x); - k = (hx & 0x7ff00000) >> 20; /* extract exponent */ - if (k == 0) { /* 0 or subnormal x */ - if ((lx | (hx & 0x7fffffff)) == 0) return x; /* +-0 */ - x *= two54; - GET_HIGH_WORD(hx, x); - k = ((hx & 0x7ff00000) >> 20) - 54; - if (n < -50000) return tiny * x; /*underflow*/ - } - if (k == 0x7ff) return x + x; /* NaN or Inf */ - k = k + n; - if (k > 0x7fe) return huge * copysign(huge, x); /* overflow */ - if (k > 0) /* normal result */ - { - SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); - return x; - } - if (k <= -54) { - if (n > 50000) /* in case integer overflow in n+k */ - return huge * copysign(huge, x); /*overflow*/ - else - return tiny * copysign(tiny, x); /*underflow*/ - } - k += 54; /* subnormal result */ - SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); - return x * twom54; -} - -double pow(double x, double y) { - double z, ax, z_h, z_l, p_h, p_l; - double y1, t1, t2, r, s, t, u, v, w; - int32_t i, j, k, yisint, n; - int32_t hx, hy, ix, iy; - uint32_t lx, ly; - - EXTRACT_WORDS(hx, lx, x); - EXTRACT_WORDS(hy, ly, y); - ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; - - /* y==zero: x**0 = 1 */ - if ((iy | ly) == 0) return one; - - /* x==1: 1**y = 1, even if y is NaN */ - if (hx == 0x3ff00000 && lx == 0) return one; - - /* y!=zero: result is NaN if either arg is NaN */ - if (ix > 0x7ff00000 || ((ix == 0x7ff00000) && (lx != 0)) || iy > 0x7ff00000 || ((iy == 0x7ff00000) && (ly != 0))) - return (x + 0.0) + (y + 0.0); - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if (hx < 0) { - if (iy >= 0x43400000) - yisint = 2; /* even integer y */ - else if (iy >= 0x3ff00000) { - k = (iy >> 20) - 0x3ff; /* exponent */ - if (k > 20) { - j = ly >> (52 - k); - if ((j << (52 - k)) == (int32_t)ly) yisint = 2 - (j & 1); - } else if (ly == 0) { - j = iy >> (20 - k); - if ((j << (20 - k)) == iy) yisint = 2 - (j & 1); - } - } - } - - /* special value of y */ - if (ly == 0) { - if (iy == 0x7ff00000) { /* y is +-inf */ - if (((ix - 0x3ff00000) | lx) == 0) - return one; /* (-1)**+-inf is NaN */ - else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ - return (hy >= 0) ? y : zero; - else /* (|x|<1)**-,+inf = inf,0 */ - return (hy < 0) ? -y : zero; - } - if (iy == 0x3ff00000) { /* y is +-1 */ - if (hy < 0) - return one / x; - else - return x; - } - if (hy == 0x40000000) return x * x; /* y is 2 */ - if (hy == 0x40080000) return x * x * x; /* y is 3 */ - if (hy == 0x40100000) { /* y is 4 */ - u = x * x; - return u * u; - } - if (hy == 0x3fe00000) { /* y is 0.5 */ - if (hx >= 0) /* x >= +0 */ - return sqrt(x); - } - } - - ax = fabs(x); - /* special value of x */ - if (lx == 0) { - if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { - z = ax; /*x is +-0,+-inf,+-1*/ - if (hy < 0) z = one / z; /* z = (1/|x|) */ - if (hx < 0) { - if (((ix - 0x3ff00000) | yisint) == 0) { - z = (z - z) / (z - z); /* (-1)**non-int is NaN */ - } else if (yisint == 1) - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - return z; - } - } - - /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be - n = (hx>>31)+1; - but ANSI C says a right shift of a signed negative quantity is - implementation defined. */ - n = ((uint32_t)hx >> 31) - 1; - - /* (x<0)**(non-int) is NaN */ - if ((n | yisint) == 0) return (x - x) / (x - x); - - s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ - if ((n | (yisint - 1)) == 0) s = -one; /* (-ve)**(odd int) */ - - /* |y| is huge */ - if (iy > 0x41e00000) { /* if |y| > 2**31 */ - if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ - if (ix <= 0x3fefffff) return (hy < 0) ? huge * huge : tiny * tiny; - if (ix >= 0x3ff00000) return (hy > 0) ? huge * huge : tiny * tiny; - } - /* over/underflow if x is not close to one */ - if (ix < 0x3fefffff) return (hy < 0) ? s * huge * huge : s * tiny * tiny; - if (ix > 0x3ff00000) return (hy > 0) ? s * huge * huge : s * tiny * tiny; - /* now |1-x| is tiny <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = ax - one; /* t has 20 trailing zeros */ - w = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); - u = ivln2_h * t; /* ivln2_h has 21 sig. bits */ - v = t * ivln2_l - w * ivln2; - t1 = u + v; - SET_LOW_WORD(t1, 0); - t2 = v - (t1 - u); - } else { - double ss, s2, s_h, s_l, t_h, t_l; - n = 0; - /* take care subnormal number */ - if (ix < 0x00100000) { - ax *= two53; - n -= 53; - GET_HIGH_WORD(ix, ax); - } - n += ((ix) >> 20) - 0x3ff; - j = ix & 0x000fffff; - /* determine interval */ - ix = j | 0x3ff00000; /* normalize ix */ - if (j <= 0x3988E) - k = 0; /* |x|> 1) | 0x20000000) + 0x00080000 + (k << 18)); - t_l = ax - (t_h - bp[k]); - s_l = v * ((u - s_h * t_h) - s_h * t_l); - /* compute log(ax) */ - s2 = ss * ss; - r = s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); - r += s_l * (s_h + ss); - s2 = s_h * s_h; - t_h = 3.0 + s2 + r; - SET_LOW_WORD(t_h, 0); - t_l = r - ((t_h - 3.0) - s2); - /* u+v = ss*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * ss; - /* 2/(3log2)*(ss+...) */ - p_h = u + v; - SET_LOW_WORD(p_h, 0); - p_l = v - (p_h - u); - z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = cp_l * p_h + p_l * cp + dp_l[k]; - /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = (double)n; - t1 = (((z_h + z_l) + dp_h[k]) + t); - SET_LOW_WORD(t1, 0); - t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); - } - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - y1 = y; - SET_LOW_WORD(y1, 0); - p_l = (y - y1) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - EXTRACT_WORDS(j, i, z); - if (j >= 0x40900000) { /* z >= 1024 */ - if (((j - 0x40900000) | i) != 0) /* if z > 1024 */ - return s * huge * huge; /* overflow */ - else { - if (p_l + ovt > z - p_h) return s * huge * huge; /* overflow */ - } - } else if ((j & 0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ - if (((j - 0xc090cc00) | i) != 0) /* z < -1075 */ - return s * tiny * tiny; /* underflow */ - else { - if (p_l <= z - p_h) return s * tiny * tiny; /* underflow */ - } - } - /* - * compute 2**(p_h+p_l) - */ - i = j & 0x7fffffff; - k = (i >> 20) - 0x3ff; - n = 0; - if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ - n = j + (0x00100000 >> (k + 1)); - k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ - t = zero; - SET_HIGH_WORD(t, n & ~(0x000fffff >> k)); - n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); - if (j < 0) n = -n; - p_h -= t; - } - t = p_l + p_h; - SET_LOW_WORD(t, 0); - u = t * lg2_h; - v = (p_l - (t - p_h)) * lg2 + t * lg2_l; - z = u + v; - w = v - (z - u); - t = z * z; - t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); - r = (z * t1) / (t1 - two) - (w + z * w); - z = one - (r - z); - GET_HIGH_WORD(j, z); - j += (n << 20); - if ((j >> 20) <= 0) - z = scalbn(z, n); /* subnormal output */ - else - SET_HIGH_WORD(z, j); - return s * z; -} diff --git a/include/c-stdlib/src/printf_impl.c b/include/c-stdlib/src/printf_impl.c deleted file mode 100644 index e293b13..0000000 --- a/include/c-stdlib/src/printf_impl.c +++ /dev/null @@ -1,1020 +0,0 @@ -#undef CKB_C_STDLIB_PRINTF -#define CKB_MALLOC_DECLARATION_ONLY 1 - -// Code copied from -// https://github.com/mpaland/printf/tree/d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3e - -#include -#include -#include "my_stddef.h" -#include -#include -#include "my_float.h" - -/** - * Output a character to a custom device like UART, used by the printf() - * function This function is declared here only. You have to write your custom - * implementation somewhere \param character Character to output - */ -void _putchar(char character); - -/** - * Tiny printf implementation - * You have to implement _putchar if you use printf() - * To avoid conflicts with the regular printf() API it is overridden by macro - * defines and internal underscore-appended functions like printf_() are used - * \param format A string that specifies the format of the output - * \return The number of characters that are written into the array, not - * counting the terminating null character - */ -int printf_(const char *format, ...); - -/** - * Tiny sprintf implementation - * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING - * (V)SNPRINTF INSTEAD! \param buffer A pointer to the buffer where to store the - * formatted string. MUST be big enough to store the output! \param format A - * string that specifies the format of the output \return The number of - * characters that are WRITTEN into the buffer, not counting the terminating - * null character - */ -int sprintf(char *buffer, const char *format, ...); - -/** - * Tiny snprintf/vsnprintf implementation - * \param buffer A pointer to the buffer where to store the formatted string - * \param count The maximum number of characters to store in the buffer, - * including a terminating null character \param format A string that specifies - * the format of the output \param va A value identifying a variable arguments - * list \return The number of characters that COULD have been written into the - * buffer, not counting the terminating null character. A value equal or larger - * than count indicates truncation. Only when the returned value is non-negative - * and less than count, the string has been completely written. - */ -int snprintf_(char *buffer, size_t count, const char *format, ...); -int vsnprintf_(char *buffer, size_t count, const char *format, va_list va); - -/** - * Tiny vprintf implementation - * \param format A string that specifies the format of the output - * \param va A value identifying a variable arguments list - * \return The number of characters that are WRITTEN into the buffer, not - * counting the terminating null character - */ -#define vprintf vprintf_ -int vprintf_(const char *format, va_list va); - -/** - * printf with output function - * You may use this as dynamic alternative to printf() with its fixed _putchar() - * output \param out An output function which takes one character and an - * argument pointer \param arg An argument pointer for user data passed to - * output function \param format A string that specifies the format of the - * output \return The number of characters that are sent to the output function, - * not counting the terminating null character - */ -int fctprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...); - -/////////////////////////////////////////////////////////////////////////////// -// \author (c) Marco Paland (info@paland.com) -// 2014-2019, PALANDesign Hannover, Germany -// -// \license The MIT License (MIT) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for -// speed on -// embedded systems with a very limited resources. These routines are -// thread safe and reentrant! Use this instead of the bloated -// standard/newlib printf cause these use malloc for printf (and may not -// be thread safe). -// -/////////////////////////////////////////////////////////////////////////////// - -// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the -// printf_config.h header file -// default: undefined -#ifdef PRINTF_INCLUDE_CONFIG_H -#include "printf_config.h" -#endif - -// 'ntoa' conversion buffer size, this must be big enough to hold one converted -// numeric number including padded zeros (dynamically created on stack) -// default: 32 byte -#ifndef PRINTF_NTOA_BUFFER_SIZE -#define PRINTF_NTOA_BUFFER_SIZE 32U -#endif - -// 'ftoa' conversion buffer size, this must be big enough to hold one converted -// float number including padded zeros (dynamically created on stack) -// default: 32 byte -#ifndef PRINTF_FTOA_BUFFER_SIZE -#define PRINTF_FTOA_BUFFER_SIZE 32U -#endif - -// support for the floating point type (%f) -// default: activated -#ifndef PRINTF_DISABLE_SUPPORT_FLOAT -#define PRINTF_SUPPORT_FLOAT -#endif - -// support for exponential floating point notation (%e/%g) -// default: activated -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL -#define PRINTF_SUPPORT_EXPONENTIAL -#endif - -// define the default floating point precision -// default: 6 digits -#ifndef PRINTF_DEFAULT_FLOAT_PRECISION -#define PRINTF_DEFAULT_FLOAT_PRECISION 6U -#endif - -// define the largest float suitable to print with %f -// default: 1e9 -#ifndef PRINTF_MAX_FLOAT -#define PRINTF_MAX_FLOAT 1e9 -#endif - -// support for the long long types (%llu or %p) -// default: activated -#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG -#define PRINTF_SUPPORT_LONG_LONG -#endif - -// support for the ptrdiff_t type (%t) -// ptrdiff_t is normally defined in as long or long long type -// default: activated -#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T -#define PRINTF_SUPPORT_PTRDIFF_T -#endif - -/////////////////////////////////////////////////////////////////////////////// - -// internal flag definitions -#define FLAGS_ZEROPAD (1U << 0U) -#define FLAGS_LEFT (1U << 1U) -#define FLAGS_PLUS (1U << 2U) -#define FLAGS_SPACE (1U << 3U) -#define FLAGS_HASH (1U << 4U) -#define FLAGS_UPPERCASE (1U << 5U) -#define FLAGS_CHAR (1U << 6U) -#define FLAGS_SHORT (1U << 7U) -#define FLAGS_LONG (1U << 8U) -#define FLAGS_LONG_LONG (1U << 9U) -#define FLAGS_PRECISION (1U << 10U) -#define FLAGS_ADAPT_EXP (1U << 11U) - -// import float.h for DBL_MAX -// #if defined(PRINTF_SUPPORT_FLOAT) -// #include -// #endif - -// output function type -typedef void (*out_fct_type)(char character, void *buffer, size_t idx, size_t maxlen); - -// wrapper (used as buffer) for output function type -typedef struct { - void (*fct)(char character, void *arg); - void *arg; -} out_fct_wrap_type; - -// internal buffer output -static inline void _out_buffer(char character, void *buffer, size_t idx, size_t maxlen) { - if (idx < maxlen) { - ((char *)buffer)[idx] = character; - } -} - -// internal null output -static inline void _out_null(char character, void *buffer, size_t idx, size_t maxlen) { - (void)character; - (void)buffer; - (void)idx; - (void)maxlen; -} - -// internal _putchar wrapper -static inline void _out_char(char character, void *buffer, size_t idx, size_t maxlen) { - (void)buffer; - (void)idx; - (void)maxlen; - if (character) { - _putchar(character); - } -} - -// internal output function wrapper -static inline void _out_fct(char character, void *buffer, size_t idx, size_t maxlen) { - (void)idx; - (void)maxlen; - if (character) { - // buffer is the output fct pointer - ((out_fct_wrap_type *)buffer)->fct(character, ((out_fct_wrap_type *)buffer)->arg); - } -} - -// internal secure strlen -// \return The length of the string (excluding the terminating 0) limited by -// 'maxsize' -static inline unsigned int _strnlen_s(const char *str, size_t maxsize) { - const char *s; - for (s = str; *s && maxsize--; ++s) - ; - return (unsigned int)(s - str); -} - -// internal test if char is a digit (0-9) -// \return true if char is a digit -static inline bool _is_digit(char ch) { return (ch >= '0') && (ch <= '9'); } - -// internal ASCII string to unsigned int conversion -unsigned int _atoi(const char **str) { - unsigned int i = 0U; - while (_is_digit(**str)) { - i = i * 10U + (unsigned int)(*((*str)++) - '0'); - } - return i; -} - -int atoi(const char *str) { - if (str[0] == '+') { - const char *sub = str + 1; - return +_atoi(&sub); - } - if (str[0] == '-') { - const char *sub = str + 1; - return -_atoi(&sub); - } - return _atoi(&str); -} - -// output the specified string in reverse, taking care of any zero-padding -static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len, - unsigned int width, unsigned int flags) { - const size_t start_idx = idx; - - // pad spaces up to given width - if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { - for (size_t i = len; i < width; i++) { - out(' ', buffer, idx++, maxlen); - } - } - - // reverse string - while (len) { - out(buf[--len], buffer, idx++, maxlen); - } - - // append pad spaces up to given width - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) { - out(' ', buffer, idx++, maxlen); - } - } - - return idx; -} - -// internal itoa format -static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len, - bool negative, unsigned int base, unsigned int prec, unsigned int width, - unsigned int flags) { - // pad leading zeros - if (!(flags & FLAGS_LEFT)) { - if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - // handle hash - if (flags & FLAGS_HASH) { - if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { - len--; - if (len && (base == 16U)) { - len--; - } - } - if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'x'; - } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'X'; - } else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { - buf[len++] = 'b'; - } - if (len < PRINTF_NTOA_BUFFER_SIZE) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_NTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -// internal itoa for 'long' type -static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, - unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) { - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} - -// internal itoa for 'long long' type -#if defined(PRINTF_SUPPORT_LONG_LONG) -static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value, - bool negative, unsigned long long base, unsigned int prec, unsigned int width, - unsigned int flags) { - char buf[PRINTF_NTOA_BUFFER_SIZE]; - size_t len = 0U; - - // no hash for 0 values - if (!value) { - flags &= ~FLAGS_HASH; - } - - // write if precision != 0 and value is != 0 - if (!(flags & FLAGS_PRECISION) || value) { - do { - const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; - value /= base; - } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); - } - - return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); -} -#endif // PRINTF_SUPPORT_LONG_LONG - -#if defined(PRINTF_SUPPORT_FLOAT) - -#if defined(PRINTF_SUPPORT_EXPONENTIAL) -// forward declaration so that _ftoa can switch to exp notation for values > -// PRINTF_MAX_FLOAT -static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, - unsigned int width, unsigned int flags); -#endif - -// internal ftoa for fixed decimal floating point -static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, - unsigned int width, unsigned int flags) { - char buf[PRINTF_FTOA_BUFFER_SIZE]; - size_t len = 0U; - double diff = 0.0; - - // powers of 10 - static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; - - // test for special values - if (value != value) return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); - if (value < -DBL_MAX) return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); - if (value > DBL_MAX) - return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, - width, flags); - - // test for very large values - // standard printf behavior is to print EVERY whole number digit -- which - // could be 100s of characters overflowing your buffers == bad - if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { -#if defined(PRINTF_SUPPORT_EXPONENTIAL) - return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); -#else - return 0U; -#endif - } - - // test for negative - bool negative = false; - if (value < 0) { - negative = true; - value = 0 - value; - } - - // set default precision, if not set explicitly - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - // limit precision to 9, cause a prec >= 10 can lead to overflow errors - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { - buf[len++] = '0'; - prec--; - } - - int whole = (int)value; - double tmp = (value - whole) * pow10[prec]; - unsigned long frac = (unsigned long)tmp; - diff = tmp - frac; - - if (diff > 0.5) { - ++frac; - // handle rollover, e.g. case 0.99 with prec 1 is 1.0 - if (frac >= pow10[prec]) { - frac = 0; - ++whole; - } - } else if (diff < 0.5) { - } else if ((frac == 0U) || (frac & 1U)) { - // if halfway, round up if odd OR if last digit is 0 - ++frac; - } - - if (prec == 0U) { - diff = value - (double)whole; - if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { - // exactly 0.5 and ODD, then round up - // 1.5 -> 2, but 2.5 -> 2 - ++whole; - } - } else { - unsigned int count = prec; - // now do fractional part, as an unsigned number - while (len < PRINTF_FTOA_BUFFER_SIZE) { - --count; - buf[len++] = (char)(48U + (frac % 10U)); - if (!(frac /= 10U)) { - break; - } - } - // add extra 0s - while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { - buf[len++] = '0'; - } - if (len < PRINTF_FTOA_BUFFER_SIZE) { - // add decimal - buf[len++] = '.'; - } - } - - // do whole part, number is reversed - while (len < PRINTF_FTOA_BUFFER_SIZE) { - buf[len++] = (char)(48 + (whole % 10)); - if (!(whole /= 10)) { - break; - } - } - - // pad leading zeros - if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { - if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { - width--; - } - while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { - buf[len++] = '0'; - } - } - - if (len < PRINTF_FTOA_BUFFER_SIZE) { - if (negative) { - buf[len++] = '-'; - } else if (flags & FLAGS_PLUS) { - buf[len++] = '+'; // ignore the space if the '+' exists - } else if (flags & FLAGS_SPACE) { - buf[len++] = ' '; - } - } - - return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); -} - -#if defined(PRINTF_SUPPORT_EXPONENTIAL) -// internal ftoa variant for exponential floating-point type, contributed by -// Martijn Jasperse -static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, - unsigned int width, unsigned int flags) { - // check for NaN and special values - if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { - return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); - } - - // determine the sign - const bool negative = value < 0; - if (negative) { - value = -value; - } - - // default precision - if (!(flags & FLAGS_PRECISION)) { - prec = PRINTF_DEFAULT_FLOAT_PRECISION; - } - - // determine the decimal exponent - // based on the algorithm by David Gay - // (https://www.ampl.com/netlib/fp/dtoa.c) - union { - uint64_t U; - double F; - } conv; - - conv.F = value; - int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 - conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) - // now approximate log10 from the log2 integer part and an expansion of ln - // around 1.5 - int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); - // now we want to compute 10^expval but we want to be sure it won't overflow - exp2 = (int)(expval * 3.321928094887362 + 0.5); - const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; - const double z2 = z * z; - conv.U = (uint64_t)(exp2 + 1023) << 52U; - // compute exp(z) using continued fractions, see - // https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex - conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); - // correct for rounding errors - if (value < conv.F) { - expval--; - conv.F /= 10; - } - - // the exponent format is "%+03d" and largest value is "307", so set aside - // 4-5 characters - unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; - - // in "%g" mode, "prec" is the number of *significant figures* not decimals - if (flags & FLAGS_ADAPT_EXP) { - // do we want to fall-back to "%f" mode? - if ((value >= 1e-4) && (value < 1e6)) { - if ((int)prec > expval) { - prec = (unsigned)((int)prec - expval - 1); - } else { - prec = 0; - } - flags |= FLAGS_PRECISION; // make sure _ftoa respects precision - // no characters in exponent - minwidth = 0U; - expval = 0; - } else { - // we use one sigfig for the whole part - if ((prec > 0) && (flags & FLAGS_PRECISION)) { - --prec; - } - } - } - - // will everything fit? - unsigned int fwidth = width; - if (width > minwidth) { - // we didn't fall-back so subtract the characters required for the - // exponent - fwidth -= minwidth; - } else { - // not enough characters, so go back to default sizing - fwidth = 0U; - } - if ((flags & FLAGS_LEFT) && minwidth) { - // if we're padding on the right, DON'T pad the floating part - fwidth = 0U; - } - - // rescale the float value - if (expval) { - value /= conv.F; - } - - // output the floating part - const size_t start_idx = idx; - idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); - - // output the exponent part - if (minwidth) { - // output the exponential symbol - out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); - // output the exponent value - idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, - FLAGS_ZEROPAD | FLAGS_PLUS); - // might need to right-pad spaces - if (flags & FLAGS_LEFT) { - while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); - } - } - return idx; -} -#endif // PRINTF_SUPPORT_EXPONENTIAL -#endif // PRINTF_SUPPORT_FLOAT - -// internal vsnprintf -static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const char *format, va_list va) { - unsigned int flags, width, precision, n; - size_t idx = 0U; - - if (!buffer) { - // use null output function - out = _out_null; - } - - while (*format) { - // format specifier? %[flags][width][.precision][length] - if (*format != '%') { - // no - out(*format, buffer, idx++, maxlen); - format++; - continue; - } else { - // yes, evaluate it - format++; - } - - // evaluate flags - flags = 0U; - do { - switch (*format) { - case '0': - flags |= FLAGS_ZEROPAD; - format++; - n = 1U; - break; - case '-': - flags |= FLAGS_LEFT; - format++; - n = 1U; - break; - case '+': - flags |= FLAGS_PLUS; - format++; - n = 1U; - break; - case ' ': - flags |= FLAGS_SPACE; - format++; - n = 1U; - break; - case '#': - flags |= FLAGS_HASH; - format++; - n = 1U; - break; - default: - n = 0U; - break; - } - } while (n); - - // evaluate width field - width = 0U; - if (_is_digit(*format)) { - width = _atoi(&format); - } else if (*format == '*') { - const int w = va_arg(va, int); - if (w < 0) { - flags |= FLAGS_LEFT; // reverse padding - width = (unsigned int)-w; - } else { - width = (unsigned int)w; - } - format++; - } - - // evaluate precision field - precision = 0U; - if (*format == '.') { - flags |= FLAGS_PRECISION; - format++; - if (_is_digit(*format)) { - precision = _atoi(&format); - } else if (*format == '*') { - const int prec = (int)va_arg(va, int); - precision = prec > 0 ? (unsigned int)prec : 0U; - format++; - } - } - - // evaluate length field - switch (*format) { - case 'l': - flags |= FLAGS_LONG; - format++; - if (*format == 'l') { - flags |= FLAGS_LONG_LONG; - format++; - } - break; - case 'h': - flags |= FLAGS_SHORT; - format++; - if (*format == 'h') { - flags |= FLAGS_CHAR; - format++; - } - break; -#if defined(PRINTF_SUPPORT_PTRDIFF_T) - case 't': - flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; -#endif - case 'j': - flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - case 'z': - flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); - format++; - break; - default: - break; - } - - // evaluate specifier - switch (*format) { - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'o': - case 'b': { - // set the base - unsigned int base; - if (*format == 'x' || *format == 'X') { - base = 16U; - } else if (*format == 'o') { - base = 8U; - } else if (*format == 'b') { - base = 2U; - } else { - base = 10U; - flags &= ~FLAGS_HASH; // no hash for dec format - } - // uppercase - if (*format == 'X') { - flags |= FLAGS_UPPERCASE; - } - - // no plus or space flag for u, x, X, o, b - if ((*format != 'i') && (*format != 'd')) { - flags &= ~(FLAGS_PLUS | FLAGS_SPACE); - } - - // ignore '0' flag when precision is given - if (flags & FLAGS_PRECISION) { - flags &= ~FLAGS_ZEROPAD; - } - - // convert the integer - if ((*format == 'i') || (*format == 'd')) { - // signed - if (flags & FLAGS_LONG_LONG) { -#if defined(PRINTF_SUPPORT_LONG_LONG) - const long long value = va_arg(va, long long); - idx = _ntoa_long_long(out, buffer, idx, maxlen, - (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, - precision, width, flags); -#endif - } else if (flags & FLAGS_LONG) { - const long value = va_arg(va, long); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), - value < 0, base, precision, width, flags); - } else { - const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) - : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) - : va_arg(va, int); - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), - value < 0, base, precision, width, flags); - } - } else { - // unsigned - if (flags & FLAGS_LONG_LONG) { -#if defined(PRINTF_SUPPORT_LONG_LONG) - idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, - precision, width, flags); -#endif - } else if (flags & FLAGS_LONG) { - idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, - width, flags); - } else { - const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) - : (flags & FLAGS_SHORT) - ? (unsigned short int)va_arg(va, unsigned int) - : va_arg(va, unsigned int); - idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); - } - } - format++; - break; - } -#if defined(PRINTF_SUPPORT_FLOAT) - case 'f': - case 'F': - if (*format == 'F') flags |= FLAGS_UPPERCASE; - idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; -#if defined(PRINTF_SUPPORT_EXPONENTIAL) - case 'e': - case 'E': - case 'g': - case 'G': - if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP; - if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE; - idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); - format++; - break; -#endif // PRINTF_SUPPORT_EXPONENTIAL -#endif // PRINTF_SUPPORT_FLOAT - case 'c': { - unsigned int l = 1U; - // pre padding - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // char output - out((char)va_arg(va, int), buffer, idx++, maxlen); - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 's': { - const char *p = va_arg(va, char *); - unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); - // pre padding - if (flags & FLAGS_PRECISION) { - l = (l < precision ? l : precision); - } - if (!(flags & FLAGS_LEFT)) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - // string output - while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { - out(*(p++), buffer, idx++, maxlen); - } - // post padding - if (flags & FLAGS_LEFT) { - while (l++ < width) { - out(' ', buffer, idx++, maxlen); - } - } - format++; - break; - } - - case 'p': { - width = sizeof(void *) * 2U; - flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; -#if defined(PRINTF_SUPPORT_LONG_LONG) - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U, - precision, width, flags); - } else { -#endif - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false, - 16U, precision, width, flags); -#if defined(PRINTF_SUPPORT_LONG_LONG) - } -#endif - format++; - break; - } - - case '%': - out('%', buffer, idx++, maxlen); - format++; - break; - - default: - out(*format, buffer, idx++, maxlen); - format++; - break; - } - } - - // termination - out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); - - // return written chars without terminating \0 - return (int)idx; -} - -/////////////////////////////////////////////////////////////////////////////// - -int printf_(const char *format, ...) { - va_list va; - va_start(va, format); - char buffer[1]; - const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); - va_end(va); - return ret; -} - -int sprintf(char *buffer, const char *format, ...) { - va_list va; - va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); - va_end(va); - return ret; -} - -int snprintf(char *buffer, size_t count, const char *format, ...) { - va_list va; - va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); - va_end(va); - return ret; -} - -int vprintf_(const char *format, va_list va) { - char buffer[1]; - return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); -} - -int vsnprintf(char *buffer, size_t count, const char *format, va_list va) { - return _vsnprintf(_out_buffer, buffer, count, format, va); -} - -int fctprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) { - va_list va; - va_start(va, format); - const out_fct_wrap_type out_fct_wrap = {out, arg}; - const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); - va_end(va); - return ret; -} - -// Default PRINTF_BUFFER_SIZE -#ifndef CKB_C_STDLIB_PRINTF_BUFFER_SIZE -#define CKB_C_STDLIB_PRINTF_BUFFER_SIZE 2048 -#endif -// syscall -int ckb_debug(const char *s); - -int printf(const char *format, ...) { - static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; - va_list va; - va_start(va, format); - int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); - va_end(va); - ckb_debug(buf); - return ret; -} - -int ckb_printf(const char *format, ...) { - static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; - va_list va; - va_start(va, format); - int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); - va_end(va); - ckb_debug(buf); - return ret; -} - -int ckb_vprintf(const char *format, va_list va) { - static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; - int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); - ckb_debug(buf); - return ret; -} diff --git a/include/c-stdlib/src/stdio_impl.c b/include/c-stdlib/src/stdio_impl.c deleted file mode 100644 index c8da132..0000000 --- a/include/c-stdlib/src/stdio_impl.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "../my_stdio.h" - -#include -#include - -FILE *stdin; -FILE *stdout; -FILE *stderr; - -int ckb_exit(signed char code); - -static int s_local_access_enabled = 0; -void enable_local_access(int b) { s_local_access_enabled = b; } - -static int s_fs_access_enabled = 0; -void enable_fs_access(int b) { s_fs_access_enabled = b; } -int fs_access_enabled() { return s_fs_access_enabled; } - -#define memory_barrier() asm volatile("fence" ::: "memory") - -static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, long _a3, long _a4, long _a5) { - register long a0 asm("a0") = _a0; - register long a1 asm("a1") = _a1; - register long a2 asm("a2") = _a2; - register long a3 asm("a3") = _a3; - register long a4 asm("a4") = _a4; - register long a5 asm("a5") = _a5; - -#ifdef __riscv_32e - register long syscall_id asm("t0") = n; -#else - register long syscall_id asm("a7") = n; -#endif - - asm volatile("scall" : "+r"(a0) : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); - /* - * Syscalls might modify memory sent as pointer, adding a barrier here - * ensures gcc won't do incorrect optimization. - */ - memory_barrier(); - - return a0; -} - -#define ckb_syscall(n, a, b, c, d, e, f) \ - __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) - -#define NOT_IMPL(name) \ - do { \ - printf("The %s is not implemented in mocked_stdio.c ", #name); \ - ckb_exit(-1); \ - } while (0) - -FILE *allocfile() { - FILE *file = malloc(sizeof(FILE)); - file->file = 0; - file->offset = 0; - return file; -} - -void freefile(FILE *file) { - file->file->rc -= 1; - free((void *)file); -} - -int remove(const char *__filename) { - NOT_IMPL(remove); - return 0; -} - -int rename(const char *__old, const char *__new) { - NOT_IMPL(rename); - return 0; -} - -FILE *tmpfile(void) { - NOT_IMPL(tmpfile); - return 0; -} - -char *tmpnam(char *__s) { - NOT_IMPL(tmpnam); - return 0; -} - -char *tempnam(const char *__dir, const char *__pfx) { - NOT_IMPL(tempnam); - return 0; -} - -int fclose(FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9009, stream, 0, 0, 0, 0, 0); - } - if (!fs_access_enabled()) { - NOT_IMPL(fclose); - } - freefile(stream); - return 0; -} - -int fflush(FILE *__stream) { - NOT_IMPL(fflush); - return 0; -} - -FILE *fopen(const char *path, const char *mode) { - if (s_local_access_enabled) { - return (void *)ckb_syscall(9003, path, mode, 0, 0, 0, 0); - } - - if (!fs_access_enabled()) { - NOT_IMPL(fopen); - } - - FILE *file = allocfile(); - if (file == 0) { - return 0; - } - - int ret = ckb_get_file(path, &file->file); - if (ret != 0) { - return 0; - } - return file; -} - -FILE *freopen(const char *path, const char *mode, FILE *stream) { - if (s_local_access_enabled) { - return (void *)ckb_syscall(9004, path, mode, stream, 0, 0, 0); - } - NOT_IMPL(freopen); - return 0; -} - -void setbuf(FILE *__stream, char *__buf) { NOT_IMPL(setbuf); } - -int setvbuf(FILE *__stream, char *__buf, int __modes, size_t __n) { - NOT_IMPL(setvbuf); - return 0; -} - -int fprintf(FILE *__stream, const char *__format, ...) { - NOT_IMPL(fprintf); - return 0; -} - -int vfprintf(FILE *__s, const char *__format, ...) { - NOT_IMPL(vfprintf); - return 0; -} -int vsprintf(char *__s, const char *__format, ...) { - NOT_IMPL(vsprintf); - return 0; -} - -int fscanf(FILE *__stream, const char *__format, ...) { - NOT_IMPL(fscanf); - return 0; -} - -int scanf(const char *__format, ...) { - NOT_IMPL(scanf); - return 0; -} - -int sscanf(const char *__s, const char *__format, ...) { - NOT_IMPL(sscanf); - return 0; -}; - -int fgetc(FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9008, stream, 0, 0, 0, 0, 0); - } - if (!fs_access_enabled()) { - NOT_IMPL(fgetc); - } - if (stream == 0 || stream->file->rc == 0 || stream->offset == stream->file->size) { - return -1; // EOF - } - unsigned char *c = (unsigned char *)stream->file->content + stream->offset; - stream->offset++; - return *c; -} - -int getc(FILE *stream) { return fgetc(stream); } - -int getchar(void) { - NOT_IMPL(getchar); - return 0; -} - -int fputc(int __c, FILE *__stream) { - NOT_IMPL(fputc); - return 0; -} - -int putc(int __c, FILE *__stream) { - NOT_IMPL(putc); - return 0; -} - -int putchar(int __c) { - NOT_IMPL(putchar); - return 0; -} - -char *fgets(char *__s, int __n, FILE *__stream) { - NOT_IMPL(fgets); - return 0; -} - -char *gets(char *__s) { - NOT_IMPL(gets); - return 0; -} - -int getline(char **__lineptr, size_t *__n, FILE *__stream) { - NOT_IMPL(getline); - return 0; -} - -int fputs(const char *__s, FILE *__stream) { - NOT_IMPL(fputs); - return 0; -} - -int puts(const char *__s) { - NOT_IMPL(puts); - return 0; -} - -int ungetc(int __c, FILE *__stream) { - NOT_IMPL(ungetc); - return 0; -} - -int isvalidfile(FILE *stream) { - if (stream == 0 || stream->file->rc == 0) { - return 1; - } - return 0; -} - -void mustbevaildfile(FILE *stream) { - if (isvalidfile(stream) != 0) { - ckb_exit(1); - } -} - -size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9005, ptr, size, nitems, stream, 0, 0); - } - if (!fs_access_enabled()) { - NOT_IMPL(fread); - } - mustbevaildfile(stream); - // TODO: How do we handle error here? - if (stream->offset == stream->file->size) { - return 0; - } - // TODO: handle the case size * nitems is greater than uint32_t max - // handle size * ntimes overflowing - uint32_t bytes_to_read = (uint32_t)size * (uint32_t)nitems; - if (bytes_to_read > stream->file->size - stream->offset) { - bytes_to_read = stream->file->size - stream->offset; - } - memcpy(ptr, stream->file->content + stream->offset, bytes_to_read); - stream->offset = stream->offset + bytes_to_read; - // The return value should be the number of items written to the ptr - uint32_t s = size; - return (bytes_to_read + s - 1) / s; -} - -size_t fwrite(const void *__ptr, size_t __size, size_t __n, FILE *__s) { - NOT_IMPL(fwrite); - return 0; -} - -int fseek(FILE *stream, long int offset, int whence) { - if (s_local_access_enabled) { - return ckb_syscall(9011, stream, offset, whence, 0, 0, 0); - } - NOT_IMPL(fseek); - return 0; -} - -long int ftell(FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9010, stream, 0, 0, 0, 0, 0); - } - NOT_IMPL(ftell); - return 0; -} - -void rewind(FILE *__stream) { NOT_IMPL(rewind); } - -void clearerr(FILE *__stream) { NOT_IMPL(clearerr); } - -int feof(FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9006, stream, 0, 0, 0, 0, 0); - } - if (!fs_access_enabled()) { - NOT_IMPL(feof); - } - if (stream->offset == stream->file->size) { - return 1; - } - return 0; -} - -int ferror(FILE *stream) { - if (s_local_access_enabled) { - return ckb_syscall(9007, stream, 0, 0, 0, 0, 0); - } - if (!fs_access_enabled()) { - NOT_IMPL(ferror); - } - if (stream == 0 || stream->file->rc == 0) { - return 1; - } - return 0; -} - -void perror(const char *__s) { NOT_IMPL(perror); } - -int fileno(FILE *__stream) { - NOT_IMPL(fileno); - return 0; -} - -FILE *popen(const char *__command, const char *__modes) { - NOT_IMPL(popen); - return 0; -} - -int pclose(FILE *__stream) { - NOT_IMPL(pclose); - return 0; -} diff --git a/include/c-stdlib/src/string_impl.c b/include/c-stdlib/src/string_impl.c deleted file mode 100644 index 7df2207..0000000 --- a/include/c-stdlib/src/string_impl.c +++ /dev/null @@ -1,740 +0,0 @@ -#include -#include "my_math.h" -#include "my_setjmp.h" -#include "my_locale.h" -#include -#include -#include -#include -#include - -int ckb_exit(int8_t code); - -#define CKB_SS (sizeof(size_t)) -#define CKB_ALIGN (sizeof(size_t) - 1) -#define CKB_ONES ((size_t)-1 / UCHAR_MAX) -#define CKB_HIGHS (CKB_ONES * (UCHAR_MAX / 2 + 1)) -#define CKB_HASZERO(x) (((x)-CKB_ONES) & ~(x)&CKB_HIGHS) - -void *memchr(const void *src, int c, size_t n) { - const unsigned char *s = src; - c = (unsigned char)c; -#ifdef __GNUC__ - for (; ((uintptr_t)s & CKB_ALIGN) && n && *s != c; s++, n--) - ; - if (n && *s != c) { - typedef size_t __attribute__((__may_alias__)) word; - const word *w; - size_t k = CKB_ONES * c; - for (w = (const void *)s; n >= CKB_SS && !CKB_HASZERO(*w ^ k); w++, n -= CKB_SS) - ; - s = (const void *)w; - } -#endif - for (; n && *s != c; s++, n--) - ; - return n ? (void *)s : 0; -} - -#define BITOP(a, b, op) ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) - -char *__strchrnul(const char *s, int c) { - c = (unsigned char)c; - if (!c) return (char *)s + strlen(s); - - for (; *s && *(unsigned char *)s != c; s++) - ; - return (char *)s; -} - -char *strchr(const char *s, int c) { - char *r = __strchrnul(s, c); - return *(unsigned char *)r == (unsigned char)c ? r : 0; -} - -int strncmp(const char *_l, const char *_r, size_t n) { - const unsigned char *l = (void *)_l, *r = (void *)_r; - if (!n--) return 0; - for (; *l && *r && n && *l == *r; l++, r++, n--) - ; - return *l - *r; -} - -size_t strspn(const char *s, const char *c) { - const char *a = s; - size_t byteset[32 / sizeof(size_t)] = {0}; - - if (!c[0]) return 0; - if (!c[1]) { - for (; *s == *c; s++) - ; - return s - a; - } - - for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) - ; - for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++) - ; - return s - a; -} - -size_t strcspn(const char *s, const char *c) { - const char *a = s; - size_t byteset[32 / sizeof(size_t)]; - - if (!c[0] || !c[1]) return __strchrnul(s, *c) - a; - - memset(byteset, 0, sizeof byteset); - for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) - ; - for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++) - ; - return s - a; -} - -char *strpbrk(const char *s, const char *b) { - s += strcspn(s, b); - return *s ? (char *)s : 0; -} - -static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) { - uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; - for (h++; *h && hw != nw; hw = hw << 8 | *++h) - ; - return *h ? (char *)h - 1 : 0; -} - -static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) { - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; - for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) - ; - return *h ? (char *)h - 2 : 0; -} - -static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) { - uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; - uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; - for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) - ; - return *h ? (char *)h - 3 : 0; -} - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#define BITOP(a, b, op) ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 << ((size_t)(b) % (8 * sizeof *(a)))) - -static char *twoway_strstr(const unsigned char *h, const unsigned char *n) { - const unsigned char *z; - size_t l, ip, jp, k, p, ms, p0, mem, mem0; - size_t byteset[32 / sizeof(size_t)] = {0}; - size_t shift[256]; - - /* Computing length of needle and fill shift table */ - for (l = 0; n[l] && h[l]; l++) BITOP(byteset, n[l], |=), shift[n[l]] = l + 1; - if (n[l]) return 0; /* hit the end of h */ - - /* Compute maximal suffix */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] > n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - ms = ip; - p0 = p; - - /* And with the opposite comparison */ - ip = -1; - jp = 0; - k = p = 1; - while (jp + k < l) { - if (n[ip + k] == n[jp + k]) { - if (k == p) { - jp += p; - k = 1; - } else - k++; - } else if (n[ip + k] < n[jp + k]) { - jp += k; - k = 1; - p = jp - ip; - } else { - ip = jp++; - k = p = 1; - } - } - if (ip + 1 > ms + 1) - ms = ip; - else - p = p0; - - /* Periodic needle? */ - if (memcmp(n, n + p, ms + 1)) { - mem0 = 0; - p = MAX(ms, l - ms - 1) + 1; - } else - mem0 = l - p; - mem = 0; - - /* Initialize incremental end-of-haystack pointer */ - z = h; - - /* Search loop */ - for (;;) { - /* Update incremental end-of-haystack pointer */ - if (z - h < l) { - /* Fast estimate for MAX(l,63) */ - size_t grow = l | 63; - const unsigned char *z2 = memchr(z, 0, grow); - if (z2) { - z = z2; - if (z - h < l) return 0; - } else - z += grow; - } - - /* Check last byte first; advance by shift on mismatch */ - if (BITOP(byteset, h[l - 1], &)) { - k = l - shift[h[l - 1]]; - if (k) { - if (k < mem) k = mem; - h += k; - mem = 0; - continue; - } - } else { - h += l; - mem = 0; - continue; - } - - /* Compare right half */ - for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) - ; - if (n[k]) { - h += k - ms; - mem = 0; - continue; - } - /* Compare left half */ - for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) - ; - if (k <= mem) return (char *)h; - h += p; - mem = mem0; - } -} - -char *strstr(const char *h, const char *n) { - /* Return immediately on empty needle */ - if (!n[0]) return (char *)h; - - /* Use faster algorithms for short needles */ - h = strchr(h, *n); - if (!h || !n[1]) return (char *)h; - if (!h[1]) return 0; - if (!n[2]) return twobyte_strstr((void *)h, (void *)n); - if (!h[2]) return 0; - if (!n[3]) return threebyte_strstr((void *)h, (void *)n); - if (!h[3]) return 0; - if (!n[4]) return fourbyte_strstr((void *)h, (void *)n); - - return twoway_strstr((void *)h, (void *)n); -} - -/* Copied from - * https://github.com/bminor/musl/blob/46d1c7801bb509e1097e8fadbaf359367fa4ef0b/src/setjmp/riscv64/setjmp.S - */ -/* We need to use inline asm for easier compilation, - * https://stackoverflow.com/a/42358235. */ -/* We need __attribute__((naked)) to remove prologue and epilogue, - * https://stackoverflow.com/a/42637729 */ -__attribute__((naked)) int setjmp(jmp_buf b) { - asm volatile( - "sd s0, 0(a0)\n" - "sd s1, 8(a0)\n" - "sd s2, 16(a0)\n" - "sd s3, 24(a0)\n" - "sd s4, 32(a0)\n" - "sd s5, 40(a0)\n" - "sd s6, 48(a0)\n" - "sd s7, 56(a0)\n" - "sd s8, 64(a0)\n" - "sd s9, 72(a0)\n" - "sd s10, 80(a0)\n" - "sd s11, 88(a0)\n" - "sd sp, 96(a0)\n" - "sd ra, 104(a0)\n" - "li a0, 0\n" - "ret\n"); -} - -__attribute__((naked)) void longjmp(jmp_buf b, int n) { - asm volatile( - "ld s0, 0(a0)\n" - "ld s1, 8(a0)\n" - "ld s2, 16(a0)\n" - "ld s3, 24(a0)\n" - "ld s4, 32(a0)\n" - "ld s5, 40(a0)\n" - "ld s6, 48(a0)\n" - "ld s7, 56(a0)\n" - "ld s8, 64(a0)\n" - "ld s9, 72(a0)\n" - "ld s10, 80(a0)\n" - "ld s11, 88(a0)\n" - "ld sp, 96(a0)\n" - "ld ra, 104(a0)\n" - "seqz a0, a1\n" - "add a0, a0, a1\n" - "ret\n"); -} - -__attribute__((naked)) void _longjmp(jmp_buf b, int n) { - asm volatile( - "ld s0, 0(a0)\n" - "ld s1, 8(a0)\n" - "ld s2, 16(a0)\n" - "ld s3, 24(a0)\n" - "ld s4, 32(a0)\n" - "ld s5, 40(a0)\n" - "ld s6, 48(a0)\n" - "ld s7, 56(a0)\n" - "ld s8, 64(a0)\n" - "ld s9, 72(a0)\n" - "ld s10, 80(a0)\n" - "ld s11, 88(a0)\n" - "ld sp, 96(a0)\n" - "ld ra, 104(a0)\n" - "seqz a0, a1\n" - "add a0, a0, a1\n" - "ret\n"); -} - -int strcoll(const char *l, const char *r) { return strcmp(l, r); } - -int *__errno_location(void) { - static int error = -1; - return &error; -} - -char *strerror(int e) { - static char *errorstr = "There is an error"; - return errorstr; -} - -int islower(int c) { return (unsigned)c - 'a' < 26; } - -int isupper(int c) { return (unsigned)c - 'A' < 26; } - -int tolower(int c) { - if (isupper(c)) return c | 32; - return c; -} - -int toupper(int c) { - if (islower(c)) return c & 0x5f; - return c; -} - -#define X(x) (((x) / 256 | (x)*256) % 65536) - -const unsigned short **__ctype_b_loc(void) { - static const unsigned short table[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, X(0x200), X(0x200), X(0x200), X(0x200), - X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x320), X(0x220), X(0x220), X(0x220), X(0x220), X(0x200), - X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), - X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x160), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), - X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), - X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x4c0), - X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x8d5), X(0x8d5), X(0x8d5), X(0x8d5), X(0x8d5), - X(0x8d5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), - X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x4c0), - X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), - X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), - X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x4c0), X(0x4c0), - X(0x4c0), X(0x4c0), X(0x200), 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - static const unsigned short *const ptable = table + 128; - return (void *)&ptable; -} - -const int32_t **__ctype_toupper_loc(void) { - static const int32_t table[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 91, - 92, 93, 94, 95, 96, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', - 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 123, 124, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - static const int32_t *const ptable = table + 128; - - return (void *)&ptable; -} - -const int32_t **__ctype_tolower_loc(void) { - static const int32_t table[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'a', 'b', 'c', 'd', 'e', - 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 91, - 92, 93, 94, 95, 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', - 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123, 124, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - static const int32_t *const ptable = table + 128; - - return (void *)&ptable; -} - -char *getenv(const char *name) { return 0; } - -int isspace(int c) { return c == ' ' || (unsigned)c - '\t' < 5; } - -// Copied from dietlibc -float strtof(const char *s, char **endptr) { - register const char *p = s; - register float value = 0.; - int sign = +1; - float factor; - unsigned int expo; - - while (isspace(*p)) p++; - - switch (*p) { - case '-': - sign = -1; /* fall through */ - case '+': - p++; - default: - break; - } - - while ((unsigned int)(*p - '0') < 10u) value = value * 10 + (*p++ - '0'); - - if (*p == '.') { - factor = 1.; - - p++; - while ((unsigned int)(*p - '0') < 10u) { - factor *= 0.1; - value += (*p++ - '0') * factor; - } - } - - if ((*p | 32) == 'e') { - expo = 0; - factor = 10.L; - - switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem - // 'E' folgenden MUSS. - case '-': - factor = 0.1; /* fall through */ - case '+': - p++; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - value = 0.L; - p = s; - goto done; - } - - while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); - - while (1) { - if (expo & 1) value *= factor; - if ((expo >>= 1) == 0) break; - factor *= factor; - } - } - -done: - if (endptr != NULL) *endptr = (char *)p; - - return value * sign; -} - -// Convert char to an int in base `base`, -// `base` must be 10 or 16, return -1 on error. -int char2int(char ch, unsigned int base) { - if (ch >= '0' && ch <= '9') return ch - '0'; - if (base == 16) { - if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; - if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; - } - return -1; -} - -#define ldbltype long double -double strtod(const char *s, char **endptr) { - register const char *p = s; - register ldbltype value = 0.; - int sign = +1; - unsigned int base = 10; - ldbltype base_inverse = (ldbltype)1 / (ldbltype)base; - ldbltype factor; - unsigned int expo; - unsigned int has_digits = 0; - - while (isspace(*p)) p++; - - switch (*p) { - case '-': - sign = -1; /* fall through */ - case '+': - p++; - case '0': - p++; - if ((*p | 32) == 'x') { - base = 16; - base_inverse = (ldbltype)1 / (ldbltype)base; - p++; - } else { - p--; - } - default: - break; - } - - unsigned int current_value; - while ((current_value = char2int(*p, base)) != -1) { - p++; - value = value * base + current_value; - has_digits = 1; - } - - if (*p == '.') { - factor = 1.; - - p++; - while ((current_value = char2int(*p, base)) != -1) { - p++; - factor *= base_inverse; - value += current_value * factor; - has_digits = 1; - } - } - - if ((*p | 32) == 'e' && base == 10) { - expo = 0; - factor = 10.; - - switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem - // 'E' folgenden MUSS. - case '-': - factor = 0.1; /* fall through */ - case '+': - p++; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - value = 0.; - p = s; - goto done; - } - - while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); - - while (1) { - if (expo & 1) value *= factor; - if ((expo >>= 1) == 0) break; - factor *= factor; - } - } - - if ((*p | 32) == 'p' && base == 16) { - // TODO: add specifier p support - // https://cplusplus.com/reference/cstdlib/strtod/ - // - A 0x or 0X prefix, then a sequence of hexadecimal digits (as in - // isxdigit) optionally containing a period which separates the whole - // and fractional number parts. Optionally followed by a power of 2 - // exponent (a p or P character followed by an optional sign and a - // sequence of hexadecimal digits). - } -done: - if (endptr != NULL) { - if (has_digits) { - *endptr = (char *)p; - } else { - *endptr = (char *)s; - } - } - - return value * sign; -} - -long double strtold(const char *s, char **endptr) { - register const char *p = s; - register long double value = 0.L; - int sign = +1; - long double factor; - unsigned int expo; - - while (isspace(*p)) p++; - - switch (*p) { - case '-': - sign = -1; /* fall through */ - case '+': - p++; - default: - break; - } - - while ((unsigned int)(*p - '0') < 10u) value = value * 10 + (*p++ - '0'); - - if (*p == '.') { - factor = 1.; - - p++; - while ((unsigned int)(*p - '0') < 10u) { - factor *= 0.1; - value += (*p++ - '0') * factor; - } - } - - if ((*p | 32) == 'e') { - expo = 0; - factor = 10.L; - - switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem - // 'E' folgenden MUSS. - case '-': - factor = 0.1; /* fall through */ - case '+': - p++; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - default: - value = 0.L; - p = s; - goto done; - } - - while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); - - while (1) { - if (expo & 1) value *= factor; - if ((expo >>= 1) == 0) break; - factor *= factor; - } - } - -done: - if (endptr != NULL) *endptr = (char *)p; - - return value * sign; -} - -void exit(int status) { ckb_exit(status); } -void abort(void) { ckb_exit(-1); } - -static void *__memrchr(const void *m, int c, size_t n) { - const unsigned char *s = m; - c = (unsigned char)c; - while (n--) - if (s[n] == c) return (void *)(s + n); - return 0; -} - -char *strrchr(char *s, int c) { return __memrchr(s, c, strlen(s) + 1); } - -char *strcat(char *dest, const char *src) { - strcpy(dest + strlen(dest), src); - return dest; -} diff --git a/include/ckb_cell_fs.c b/include/ckb_cell_fs.c deleted file mode 100644 index 6a3060e..0000000 --- a/include/ckb_cell_fs.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include - -#include "ckb_cell_fs.h" - -static CellFileSystem *CELL_FILE_SYSTEM = NULL; - -int get_file(const CellFileSystem *fs, const char *filename, FSFile **f) { - if (fs == NULL) { - return -1; - } - FSFile *file = malloc(sizeof(FSFile)); - if (file == 0) { - return -1; - } - CellFileSystem *cfs = (CellFileSystem *)fs; - CellFileSystemNode *node = cfs->current; - while (node != NULL) { - for (uint32_t i = 0; i < node->count; i++) { - FSEntry entry = node->files[i]; - if (strcmp(filename, node->start + entry.filename.offset) == 0) { - // TODO: check the memory addresses are legal - file->filename = filename; - file->size = entry.content.length; - file->content = node->start + entry.content.offset; - file->rc = 1; - *f = file; - return 0; - } - } - if (cfs->next == NULL) { - break; - } - cfs = cfs->next; - node = cfs->current; - } - free(file); - return -1; -} - -int ckb_get_file(const char *filename, FSFile **file) { return get_file(CELL_FILE_SYSTEM, filename, file); } - -int load_fs(CellFileSystem **fs, void *buf, uint64_t buflen) { - if (fs == NULL || buf == NULL) { - return -1; - } - - CellFileSystemNode *node = (CellFileSystemNode *)malloc(sizeof(CellFileSystemNode)); - if (node == NULL) { - return -1; - } - - CellFileSystem *newfs = (CellFileSystem *)malloc(sizeof(CellFileSystem)); - if (newfs == NULL) { - free(node); - return -1; - } - - node->count = *(uint32_t *)buf; - if (node->count == 0) { - node->files = NULL; - node->start = NULL; - newfs->next = *fs; - newfs->current = node; - *fs = newfs; - return 0; - } - - node->files = (FSEntry *)malloc(sizeof(FSEntry) * node->count); - if (node->files == NULL) { - free(node); - free(newfs); - return -1; - } - node->start = buf + sizeof(node->count) + (sizeof(FSEntry) * node->count); - - FSEntry *entries = (FSEntry *)((char *)buf + sizeof(node->count)); - for (uint32_t i = 0; i < node->count; i++) { - FSEntry entry = entries[i]; - node->files[i] = entry; - } - - newfs->next = *fs; - newfs->current = node; - *fs = newfs; - return 0; -} - -int ckb_load_fs(void *buf, uint64_t buflen) { - int ret = load_fs(&CELL_FILE_SYSTEM, buf, buflen); - return ret; -} - -void ckb_reset_fs() { CELL_FILE_SYSTEM = NULL; } diff --git a/include/ckb_cell_fs.h b/include/ckb_cell_fs.h deleted file mode 100644 index 9f6b8d0..0000000 --- a/include/ckb_cell_fs.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _CKB_CELL_FS_H -#define _CKB_CELL_FS_H 1 - -typedef struct FSBlob { - uint32_t offset; - uint32_t length; -} FSBlob; - -typedef struct FSEntry { - FSBlob filename; - FSBlob content; -} FSEntry; - -typedef struct CellFileSystemNode { - uint32_t count; - FSEntry *files; - void *start; -} CellFileSystemNode; - -typedef struct CellFileSystem { - CellFileSystemNode *current; - struct CellFileSystem *next; -} CellFileSystem; - -typedef struct FSFile { - const char *filename; - const void *content; - uint32_t size; - // indicate how many active users there are, used to avoid excessive opening - // of the same file. - // Currently the only valid values are 1 and 0. - uint8_t rc; -} FSFile; - -int get_file(const CellFileSystem *fs, const char *filename, FSFile **f); - -int ckb_get_file(const char *filename, FSFile **file); - -int load_fs(CellFileSystem **fs, void *buf, uint64_t buflen); - -int ckb_load_fs(void *buf, uint64_t buflen); - -void ckb_reset_fs(); - -#endif diff --git a/libc/assert.h b/libc/assert.h new file mode 100644 index 0000000..931b2e3 --- /dev/null +++ b/libc/assert.h @@ -0,0 +1,14 @@ +#ifndef CKB_C_STDLIB_ASSERT_H_ +#define CKB_C_STDLIB_ASSERT_H_ + +#include "ckb_syscall_apis.h" + +#define assert(s) \ + do { \ + if (!(s)) { \ + printf("Failed at %s:%d: %s\n", __FILE__, __LINE__, (#s)); \ + ckb_exit(-1); \ + } \ + } while (0) + +#endif // CKB_C_STDLIB_ASSERT_H_ diff --git a/libc/ckb_cell_fs.h b/libc/ckb_cell_fs.h new file mode 100644 index 0000000..d1fc314 --- /dev/null +++ b/libc/ckb_cell_fs.h @@ -0,0 +1,45 @@ +#ifndef CKB_C_STDLIB_CKB_CELL_FS_H +#define CKB_C_STDLIB_CKB_CELL_FS_H 1 + +typedef struct FSBlob { + uint32_t offset; + uint32_t length; +} FSBlob; + +typedef struct FSEntry { + FSBlob filename; + FSBlob content; +} FSEntry; + +typedef struct CellFileSystemNode { + uint32_t count; + FSEntry *files; + void *start; +} CellFileSystemNode; + +typedef struct CellFileSystem { + CellFileSystemNode *current; + struct CellFileSystem *next; +} CellFileSystem; + +typedef struct FSFile { + const char *filename; + const void *content; + uint32_t size; + // indicate how many active users there are, used to avoid excessive opening + // of the same file. + // Currently the only valid values are 1 and 0. + uint8_t rc; +} FSFile; + +int get_file(const CellFileSystem *fs, const char *filename, FSFile **f); + +int ckb_get_file(const char *filename, FSFile **file); + +int load_fs(CellFileSystem **fs, void *buf, uint64_t buflen); + +int ckb_load_fs(void *buf, uint64_t buflen); + +void ckb_reset_fs(); + +#endif diff --git a/include/c-stdlib/my_ctype.h b/libc/ctype.h similarity index 71% rename from include/c-stdlib/my_ctype.h rename to libc/ctype.h index a6150a2..0b3bded 100644 --- a/include/c-stdlib/my_ctype.h +++ b/libc/ctype.h @@ -1,5 +1,5 @@ -#ifndef _STDLIB_CTYPE_H_ -#define _STDLIB_CTYPE_H_ +#ifndef CKB_C_STDLIB_CTYPE_H_ +#define CKB_C_STDLIB_CTYPE_H_ #ifdef __cplusplus extern "C" { #endif diff --git a/libc/entry.h b/libc/entry.h new file mode 100644 index 0000000..1b13464 --- /dev/null +++ b/libc/entry.h @@ -0,0 +1,31 @@ +#ifndef CKB_C_STDLIB_ENTRY_H_ +#define CKB_C_STDLIB_ENTRY_H_ + +#ifndef CKB_DECLARATION_ONLY +#include "src/impl.c" + +#ifndef __SHARED_LIBRARY__ +__attribute__((visibility("default"))) __attribute__((naked)) void _start() { + asm volatile( + ".option push\n" + ".option norelax\n" +#ifndef CKB_NO_ENTRY_GP + "1:auipc gp, %pcrel_hi(__global_pointer$)\n" + "addi gp, gp, %pcrel_lo(1b)\n" + ".option pop\n" +#endif + /* + * By default CKB VM initializes all memory to 0, there's no need + * to clear BSS segment again. + */ + "lw a0, 0(sp)\n" + "addi a1, sp, 8\n" + "li a2, 0\n" + "call main\n" + "li a7, 93\n" + "ecall"); +} +#endif /* __SHARED_LIBRARY__ */ +#endif /* CKB_DECLARATION_ONLY*/ + +#endif /* CKB_C_STDLIB_ENTRY_H_ */ diff --git a/include/c-stdlib/my_errno.h b/libc/errno.h similarity index 75% rename from include/c-stdlib/my_errno.h rename to libc/errno.h index 043b9e4..9e54e13 100644 --- a/include/c-stdlib/my_errno.h +++ b/libc/errno.h @@ -1,5 +1,5 @@ -#ifndef _STDLIB_ERRNO_H_ -#define _STDLIB_ERRNO_H_ +#ifndef CKB_C_STDLIB_ERRNO_H_ +#define CKB_C_STDLIB_ERRNO_H_ #ifdef __cplusplus extern "C" { diff --git a/include/c-stdlib/my_features.h b/libc/features.h similarity index 78% rename from include/c-stdlib/my_features.h rename to libc/features.h index a0d92fd..7e5e2f7 100644 --- a/include/c-stdlib/my_features.h +++ b/libc/features.h @@ -1,5 +1,5 @@ -#ifndef _FEATURES_H -#define _FEATURES_H +#ifndef CKB_C_STDLIB_FEATURES_H_ +#define CKB_C_STDLIB_FEATURES_H_ #if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 @@ -9,7 +9,8 @@ #define _BSD_SOURCE 1 #endif -#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) && \ +#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && \ + !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) && \ !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__) #define _BSD_SOURCE 1 #define _XOPEN_SOURCE 700 diff --git a/libc/fenv.h b/libc/fenv.h new file mode 100644 index 0000000..90b0f4f --- /dev/null +++ b/libc/fenv.h @@ -0,0 +1,8 @@ +#ifndef CKB_C_STDLIB_FENV_H_ +#define CKB_C_STDLIB_FENV_H_ +#define FE_TONEAREST 0 +#define FE_DOWNWARD 0 +#define FE_UPWARD 0 +int fesetround(int round); +int fegetround(); +#endif diff --git a/libc/float.h b/libc/float.h new file mode 100644 index 0000000..a145ba8 --- /dev/null +++ b/libc/float.h @@ -0,0 +1,129 @@ +#ifndef CKB_C_STDLIB_FLOAT_H_ +#define CKB_C_STDLIB_FLOAT_H_ + +#include + +#undef FLT_MAX +#undef DBL_MAX +#undef LDBL_MAX +#define FLT_MAX __FLT_MAX__ +#define DBL_MAX __DBL_MAX__ +#define LDBL_MAX __LDBL_MAX__ + +typedef union { + double value; + struct { + uint32_t lsw; + uint32_t msw; + } parts; + struct { + uint64_t w; + } xparts; +} ieee_double_shape_type; + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0, ix1, d) \ + do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ + } while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i, d) \ + do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ + } while (0) + +/* Get the less significant 32 bit int from a double. */ + +#define GET_LOW_WORD(i, d) \ + do { \ + ieee_double_shape_type gl_u; \ + gl_u.value = (d); \ + (i) = gl_u.parts.lsw; \ + } while (0) + +/* Set the more significant 32 bits of a double from an int. */ + +#define SET_HIGH_WORD(d, v) \ + do { \ + ieee_double_shape_type sh_u; \ + sh_u.value = (d); \ + sh_u.parts.msw = (v); \ + (d) = sh_u.value; \ + } while (0) + +/* Set the less significant 32 bits of a double from an int. */ + +#define SET_LOW_WORD(d, v) \ + do { \ + ieee_double_shape_type sl_u; \ + sl_u.value = (d); \ + sl_u.parts.lsw = (v); \ + (d) = sl_u.value; \ + } while (0) + +static const double ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ + ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ + two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */ + twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ + huge = 1.0e+300, tiny = 1.0e-300, + Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ + Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ + Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ + Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ + Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ + Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ + Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +static const double zero = 0.0; + +static const double bp[] = + { + 1.0, + 1.5, +}, + dp_h[] = + { + 0.0, + 5.84962487220764160156e-01, +}, /* 0x3FE2B803, 0x40000000 */ + dp_l[] = + { + 0.0, + 1.35003920212974897128e-08, +}, /* 0x3E4CFDEB, 0x43CFD006 */ + one = 1.0, two = 2.0, + two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ + /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ + L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ + L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ + L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ + L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ + L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ + L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ + P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ + P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ + lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ + lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ + lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ + ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ + cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ + cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ + cp_l = + -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ + ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ + ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ + ivln2_l = + 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ + +#endif diff --git a/libc/internal/atomic.h b/libc/internal/atomic.h new file mode 100644 index 0000000..6228043 --- /dev/null +++ b/libc/internal/atomic.h @@ -0,0 +1,37 @@ +#ifndef CKB_C_STDLIB_INTERNAL_ATOMIC_H_ +#define CKB_C_STDLIB_INTERNAL_ATOMIC_H_ +#include + +/* + * Modified from + * https://git.musl-libc.org/cgit/musl/tree/src/internal/atomic.h?id=33338ebc853d37c80f0f236cc7a92cb0acc6aace + */ +static inline int a_ctz_32(uint32_t x) { + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; + return debruijn32[(x & -x) * 0x076be629 >> 27]; +} + +static inline int a_ctz_64(uint64_t x) { + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x >> 32; + return 32 + a_ctz_32(y); + } + return a_ctz_32(y); + } + return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; +} + +static inline int a_ctz_l(unsigned long x) { + return (sizeof(long) < 8) ? a_ctz_32(x) : a_ctz_64(x); +} + +#endif /* CKB_C_STDLIB_INTERNAL_ATOMIC_H_ */ diff --git a/libc/internal/types.h b/libc/internal/types.h new file mode 100644 index 0000000..d205373 --- /dev/null +++ b/libc/internal/types.h @@ -0,0 +1,22 @@ +#ifndef CKB_C_STDLIB_INTERNAL_TYPES_H_ +#define CKB_C_STDLIB_INTERNAL_TYPES_H_ + +typedef unsigned long size_t; +typedef signed long ssize_t; + +typedef unsigned long uintptr_t; +typedef signed long intptr_t; + +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned long uint64_t; +typedef signed long int64_t; + +#endif /* CKB_C_STDLIB_INTERNAL_TYPES_H_ */ diff --git a/include/c-stdlib/my_inttypes.h b/libc/inttypes.h similarity index 96% rename from include/c-stdlib/my_inttypes.h rename to libc/inttypes.h index 27df674..8210d6f 100644 --- a/include/c-stdlib/my_inttypes.h +++ b/libc/inttypes.h @@ -1,8 +1,7 @@ -#ifndef _MY_INTTYPES_H_ -#define _MY_INTTYPES_H_ +#ifndef CKB_C_STDLIB_INTTYPES_H_ +#define CKB_C_STDLIB_INTTYPES_H_ #include -#include "my_stdint.h" #if UINTPTR_MAX == UINT64_MAX #define __PRI64 "l" diff --git a/libc/limits.h b/libc/limits.h new file mode 100644 index 0000000..258f6aa --- /dev/null +++ b/libc/limits.h @@ -0,0 +1,127 @@ +#ifndef HEADER__LIBC_LIMITS_H_ +#define HEADER__LIBC_LIMITS_H_ 1 + +#ifdef _MB_LEN_MAX +#define MB_LEN_MAX _MB_LEN_MAX +#else +#define MB_LEN_MAX 1 +#endif + +/* Maximum number of positional arguments, if _WANT_IO_POS_ARGS. */ +#ifndef NL_ARGMAX +#define NL_ARGMAX 32 +#endif + +/* Number of bits in a `char'. */ +#undef CHAR_BIT +#define CHAR_BIT 8 + +/* Minimum and maximum values a `signed char' can hold. */ +#undef SCHAR_MIN +#define SCHAR_MIN (-128) +#undef SCHAR_MAX +#define SCHAR_MAX 127 + +/* Maximum value an `unsigned char' can hold. (Minimum is 0). */ +#undef UCHAR_MAX +#define UCHAR_MAX 255 + +/* Minimum and maximum values a `char' can hold. */ +#ifdef __CHAR_UNSIGNED__ +#undef CHAR_MIN +#define CHAR_MIN 0 +#undef CHAR_MAX +#define CHAR_MAX 255 +#else +#undef CHAR_MIN +#define CHAR_MIN (-128) +#undef CHAR_MAX +#define CHAR_MAX 127 +#endif + +/* Minimum and maximum values a `signed short int' can hold. */ +#undef SHRT_MIN +/* For the sake of 16 bit hosts, we may not use -32768 */ +#define SHRT_MIN (-32767 - 1) +#undef SHRT_MAX +#define SHRT_MAX 32767 + +/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */ +#undef USHRT_MAX +#define USHRT_MAX 65535 + +/* Minimum and maximum values a `signed int' can hold. */ +#ifndef __INT_MAX__ +#define __INT_MAX__ 2147483647 +#endif +#undef INT_MIN +#define INT_MIN (-INT_MAX - 1) +#undef INT_MAX +#define INT_MAX __INT_MAX__ + +/* Maximum value an `unsigned int' can hold. (Minimum is 0). */ +#undef UINT_MAX +#define UINT_MAX (INT_MAX * 2U + 1) + +/* Minimum and maximum values a `signed long int' can hold. + (Same as `int'). */ +#ifndef __LONG_MAX__ +#if defined(__alpha__) || (defined(__sparc__) && defined(__arch64__)) || \ + defined(__sparcv9) +#define __LONG_MAX__ 9223372036854775807L +#else +#define __LONG_MAX__ 2147483647L +#endif /* __alpha__ || sparc64 */ +#endif +#undef LONG_MIN +#define LONG_MIN (-LONG_MAX - 1) +#undef LONG_MAX +#define LONG_MAX __LONG_MAX__ + +/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */ +#undef ULONG_MAX +#define ULONG_MAX (LONG_MAX * 2UL + 1) + +#ifndef __LONG_LONG_MAX__ +#define __LONG_LONG_MAX__ 9223372036854775807LL +#endif + +#if __ISO_C_VISIBLE >= 1999 +/* Minimum and maximum values a `signed long long int' can hold. */ +#undef LLONG_MIN +#define LLONG_MIN (-LLONG_MAX - 1) +#undef LLONG_MAX +#define LLONG_MAX __LONG_LONG_MAX__ + +/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ +#undef ULLONG_MAX +#define ULLONG_MAX (LLONG_MAX * 2ULL + 1) +#endif + +#if __GNU_VISIBLE +/* Minimum and maximum values a `signed long long int' can hold. */ +#undef LONG_LONG_MIN +#define LONG_LONG_MIN (-LONG_LONG_MAX - 1) +#undef LONG_LONG_MAX +#define LONG_LONG_MAX __LONG_LONG_MAX__ + +/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ +#undef ULONG_LONG_MAX +#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1) +#endif + +#endif /* _LIBC_LIMITS_H_ */ + +#ifndef _POSIX2_RE_DUP_MAX +/* The maximum number of repeated occurrences of a regular expression + * permitted when using the interval notation `\{M,N\}'. */ +#define _POSIX2_RE_DUP_MAX 255 +#endif /* _POSIX2_RE_DUP_MAX */ + +#ifndef ARG_MAX +#define ARG_MAX 4096 +#endif + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif diff --git a/libc/locale.h b/libc/locale.h new file mode 100644 index 0000000..8735fbd --- /dev/null +++ b/libc/locale.h @@ -0,0 +1,41 @@ +#ifndef CKB_C_STDLIB_LOCALE_H_ +#define CKB_C_STDLIB_LOCALE_H_ +#ifdef __cplusplus +extern "C" { +#endif + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +struct lconv *localeconv(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/c-stdlib/my_malloc.h b/libc/malloc.h similarity index 58% rename from include/c-stdlib/my_malloc.h rename to libc/malloc.h index 583e383..ba8ccad 100644 --- a/include/c-stdlib/my_malloc.h +++ b/libc/malloc.h @@ -1,5 +1,5 @@ -#ifndef _STDLIB_MALLOC_H_ -#define _STDLIB_MALLOC_H_ +#ifndef CKB_C_STDLIB_MALLOC_H_ +#define CKB_C_STDLIB_MALLOC_H_ #include @@ -7,4 +7,4 @@ size_t malloc_usable_size(void *ptr); void malloc_config(uintptr_t min, uintptr_t max); size_t malloc_usage(); -#endif // _STDLIB_MALLOC_H_ +#endif // CKB_C_STDLIB_MALLOC_H_ diff --git a/include/c-stdlib/my_math.h b/libc/math.h similarity index 67% rename from include/c-stdlib/my_math.h rename to libc/math.h index 40466fc..55f13e8 100644 --- a/include/c-stdlib/my_math.h +++ b/libc/math.h @@ -1,3 +1,6 @@ +#ifndef CKB_C_STDLIB_MATH_H_ +#define CKB_C_STDLIB_MATH_H_ + #ifdef __cplusplus extern "C" { #endif @@ -14,53 +17,63 @@ extern "C" { #ifndef fp_force_evalf #define fp_force_evalf fp_force_evalf static inline void fp_force_evalf(float x) { - volatile float y; - y = x; - (void)y; + volatile float y; + y = x; + (void)y; } #endif #ifndef fp_force_eval #define fp_force_eval fp_force_eval static inline void fp_force_eval(double x) { - volatile double y; - y = x; - (void)y; + volatile double y; + y = x; + (void)y; } #endif #ifndef fp_force_evall #define fp_force_evall fp_force_evall static inline void fp_force_evall(long double x) { - volatile long double y; - y = x; - (void)y; + volatile long double y; + y = x; + (void)y; } #endif -#define FORCE_EVAL(x) \ - do { \ - if (sizeof(x) == sizeof(float)) { \ - fp_force_evalf(x); \ - } else if (sizeof(x) == sizeof(double)) { \ - fp_force_eval(x); \ - } else { \ - fp_force_evall(x); \ - } \ - } while (0) +#define FORCE_EVAL(x) \ + do { \ + if (sizeof(x) == sizeof(float)) { \ + fp_force_evalf(x); \ + } else if (sizeof(x) == sizeof(double)) { \ + fp_force_eval(x); \ + } else { \ + fp_force_evall(x); \ + } \ + } while (0) double acos(double); +double acosh(double x); + double asin(double); +double asinh(double x); + +double atan(double x); + double atan2(double, double); +double atanh(double x); + double cos(double); double cosh(double); double exp(double); +double expm1(double); + double fabs(double); double log(double); @@ -69,6 +82,8 @@ double log2(double); double log10(double); +double log1p(double); + double pow(double, double); double sin(double); @@ -103,3 +118,5 @@ double ceil(double x); #ifdef __cplusplus } #endif + +#endif diff --git a/libc/memory.h b/libc/memory.h new file mode 100644 index 0000000..13b49b6 --- /dev/null +++ b/libc/memory.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/include/c-stdlib/my_setjmp.h b/libc/setjmp.h similarity index 70% rename from include/c-stdlib/my_setjmp.h rename to libc/setjmp.h index 666c35d..fe7de6c 100644 --- a/include/c-stdlib/my_setjmp.h +++ b/libc/setjmp.h @@ -1,5 +1,5 @@ -#ifndef _STDLIB_SETJMP_H_ -#define _STDLIB_SETJMP_H_ +#ifndef CKB_C_STDLIB_SETJMP_H_ +#define CKB_C_STDLIB_SETJMP_H_ #ifdef __cplusplus extern "C" { @@ -10,9 +10,9 @@ extern "C" { typedef unsigned long __jmp_buf[26]; typedef struct __jmp_buf_tag { - __jmp_buf __jb; - unsigned long __fl; - unsigned long __ss[128 / sizeof(long)]; + __jmp_buf __jb; + unsigned long __fl; + unsigned long __ss[128 / sizeof(long)]; } jmp_buf[1]; #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) @@ -21,8 +21,8 @@ typedef struct __jmp_buf_tag { #define __setjmp_attr #endif -#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || \ - defined(_BSD_SOURCE) +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \ + defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) typedef jmp_buf sigjmp_buf; int sigsetjmp(sigjmp_buf, int) __setjmp_attr; _Noreturn void siglongjmp(sigjmp_buf, int); diff --git a/libc/src/ckb_cell_fs.c b/libc/src/ckb_cell_fs.c new file mode 100644 index 0000000..1c30a69 --- /dev/null +++ b/libc/src/ckb_cell_fs.c @@ -0,0 +1,98 @@ +#include +#include +#include + +#include "ckb_cell_fs.h" + +static CellFileSystem *CELL_FILE_SYSTEM = NULL; + +int get_file(const CellFileSystem *fs, const char *filename, FSFile **f) { + if (fs == NULL) { + return -1; + } + FSFile *file = malloc(sizeof(FSFile)); + if (file == 0) { + return -1; + } + CellFileSystem *cfs = (CellFileSystem *)fs; + CellFileSystemNode *node = cfs->current; + while (node != NULL) { + for (uint32_t i = 0; i < node->count; i++) { + FSEntry entry = node->files[i]; + if (strcmp(filename, node->start + entry.filename.offset) == 0) { + // TODO: check the memory addresses are legal + file->filename = filename; + file->size = entry.content.length; + file->content = node->start + entry.content.offset; + file->rc = 1; + *f = file; + return 0; + } + } + if (cfs->next == NULL) { + break; + } + cfs = cfs->next; + node = cfs->current; + } + free(file); + return -1; +} + +int ckb_get_file(const char *filename, FSFile **file) { + return get_file(CELL_FILE_SYSTEM, filename, file); +} + +int load_fs(CellFileSystem **fs, void *buf, uint64_t buflen) { + if (fs == NULL || buf == NULL) { + return -1; + } + + CellFileSystemNode *node = + (CellFileSystemNode *)malloc(sizeof(CellFileSystemNode)); + if (node == NULL) { + return -1; + } + + CellFileSystem *newfs = (CellFileSystem *)malloc(sizeof(CellFileSystem)); + if (newfs == NULL) { + free(node); + return -1; + } + + node->count = *(uint32_t *)buf; + if (node->count == 0) { + node->files = NULL; + node->start = NULL; + newfs->next = *fs; + newfs->current = node; + *fs = newfs; + return 0; + } + + node->files = (FSEntry *)malloc(sizeof(FSEntry) * node->count); + if (node->files == NULL) { + free(node); + free(newfs); + return -1; + } + node->start = buf + sizeof(node->count) + (sizeof(FSEntry) * node->count); + + FSEntry *entries = (FSEntry *)((char *)buf + sizeof(node->count)); + for (uint32_t i = 0; i < node->count; i++) { + FSEntry entry = entries[i]; + node->files[i] = entry; + } + + newfs->next = *fs; + newfs->current = node; + *fs = newfs; + return 0; +} + +int ckb_load_fs(void *buf, uint64_t buflen) { + int ret = load_fs(&CELL_FILE_SYSTEM, buf, buflen); + return ret; +} + +void ckb_reset_fs() { CELL_FILE_SYSTEM = NULL; } diff --git a/libc/src/ctype.c b/libc/src/ctype.c new file mode 100644 index 0000000..ba313d4 --- /dev/null +++ b/libc/src/ctype.c @@ -0,0 +1,15 @@ +#include + +int islower(int c) { return (unsigned)c - 'a' < 26; } + +int isupper(int c) { return (unsigned)c - 'A' < 26; } + +int tolower(int c) { + if (isupper(c)) return c | 32; + return c; +} + +int toupper(int c) { + if (islower(c)) return c & 0x5f; + return c; +} diff --git a/libc/src/fenv.c b/libc/src/fenv.c new file mode 100644 index 0000000..6d2c8e2 --- /dev/null +++ b/libc/src/fenv.c @@ -0,0 +1,5 @@ +#include + +int fesetround(int _round) { return 0; } + +int fegetround() { return 0; } diff --git a/include/c-stdlib/src/locale_impl.c b/libc/src/locale.c similarity index 97% rename from include/c-stdlib/src/locale_impl.c rename to libc/src/locale.c index 72bf30d..1967ff1 100644 --- a/include/c-stdlib/src/locale_impl.c +++ b/libc/src/locale.c @@ -1,5 +1,5 @@ #include -#include "my_locale.h" +#include static const struct lconv posix_lconv = { .decimal_point = ".", diff --git a/libc/src/malloc.c b/libc/src/malloc.c new file mode 100644 index 0000000..73ea2cb --- /dev/null +++ b/libc/src/malloc.c @@ -0,0 +1,406 @@ +#define CKB_MALLOC_DECLARATION_ONLY 1 +#include +#include +#include +#include + +#ifndef CKB_BRK_MIN +extern char _end[]; /* _end is set in the linker */ +#define CKB_BRK_MIN ((uintptr_t)&_end) +#endif +#ifndef CKB_BRK_MAX +#define CKB_BRK_MAX 0x00300000 +#endif + +struct chunk { + size_t psize, csize; + struct chunk *next, *prev; +}; + +struct bin { + volatile int lock[2]; + struct chunk *head; + struct chunk *tail; +}; + +#define CKB_SIZE_ALIGN (4 * sizeof(size_t)) +#define CKB_SIZE_MASK (-CKB_SIZE_ALIGN) +#define CKB_OVERHEAD (2 * sizeof(size_t)) +#define CKB_DONTCARE 16 +#define CKB_RECLAIM 163840 +#define CKB_MMAP_THRESHOLD (0x1c00 * CKB_SIZE_ALIGN) + +#define CKB_CHUNK_SIZE(c) ((c)->csize & -2) +#define CKB_CHUNK_PSIZE(c) ((c)->psize & -2) +#define CKB_PREV_CHUNK(c) ((struct chunk *)((char *)(c)-CKB_CHUNK_PSIZE(c))) +#define CKB_NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CKB_CHUNK_SIZE(c))) +#define CKB_MEM_TO_CHUNK(p) (struct chunk *)((char *)(p)-CKB_OVERHEAD) +#define CKB_CHUNK_TO_MEM(c) (void *)((char *)(c) + CKB_OVERHEAD) +#define CKB_BIN_TO_CHUNK(i) (CKB_MEM_TO_CHUNK(&mal.bins[i].head)) +#define CKB_C_INUSE ((size_t)1) +#define CKB_IS_MMAPPED(c) !((c)->csize & (CKB_C_INUSE)) +#define CKB_PAGE_SIZE 4096 +void __bin_chunk(struct chunk *); +int ckb_exit(int8_t code); +static inline void a_crash() { ckb_exit(-1); } +void free(void *p); + +static inline void a_and_64(volatile uint64_t *p, uint64_t v) { *p &= v; } + +static inline void a_or_64(volatile uint64_t *p, uint64_t v) { *p |= v; } + +static uintptr_t s_program_break = 0; +static uintptr_t s_brk_min = CKB_BRK_MIN; +static uintptr_t s_brk_max = CKB_BRK_MAX; + +void malloc_config(uintptr_t min, uintptr_t max) { + s_brk_min = min; + s_brk_max = max; + s_program_break = 0; +} + +size_t malloc_usage() { + size_t high = (size_t)s_program_break; + size_t low = (size_t)s_brk_min; + return high - low; +} + +void *_sbrk(uintptr_t incr) { + if (!s_program_break) { + s_program_break = s_brk_min; + s_program_break += -s_program_break & (CKB_PAGE_SIZE - 1); + } + if ((s_program_break + incr) > s_brk_max) { + return (void *)-1; + } + + uintptr_t start = s_program_break; + s_program_break += incr; + return (void *)start; +} + +static struct { + volatile uint64_t binmap; + struct bin bins[64]; + volatile int split_merge_lock[2]; +} mal; + +static inline void lock_bin(int i) { + if (!mal.bins[i].head) + mal.bins[i].head = mal.bins[i].tail = CKB_BIN_TO_CHUNK(i); +} + +static inline void unlock_bin(int i) {} + +#if 0 +static int first_set(uint64_t x) { + // TODO: use RISC-V asm + static const char debruijn64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; + if (sizeof(long) < 8) { + uint32_t y = x; + if (!y) { + y = x >> 32; + return 32 + debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn32[(y & -y) * 0x076be629 >> 27]; + } + return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; +} + +#else + +static int __attribute__((naked)) first_set(uint64_t x) { + __asm__(".byte 0x13, 0x15, 0x15, 0x60"); + __asm__("ret"); +} + +#endif + +static const unsigned char bin_tab[60] = { + 32, 33, 34, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 40, + 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, + 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 46, + 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, +}; + +static int bin_index(size_t x) { + x = x / CKB_SIZE_ALIGN - 1; + if (x <= 32) return x; + if (x < 512) return bin_tab[x / 8 - 4]; + if (x > 0x1c00) return 63; + return bin_tab[x / 128 - 4] + 16; +} + +static int bin_index_up(size_t x) { + x = x / CKB_SIZE_ALIGN - 1; + if (x <= 32) return x; + x--; + if (x < 512) return bin_tab[x / 8 - 4] + 1; + return bin_tab[x / 128 - 4] + 17; +} + +static void *__expand_heap(size_t *pn) { + size_t n = *pn; + n += -n & (CKB_PAGE_SIZE - 1); + + void *p = _sbrk(n); + if (p == (void *)-1) { + return 0; + } + *pn = n; + return p; +} + +static struct chunk *expand_heap(size_t n) { + static void *end; + void *p; + struct chunk *w; + + /* The argument n already accounts for the caller's chunk + * CKB_OVERHEAD needs, but if the heap can't be extended in-place, + * we need room for an extra zero-sized sentinel chunk. */ + n += CKB_SIZE_ALIGN; + + p = __expand_heap(&n); + if (!p) return 0; + /* If not just expanding existing space, we need to make a + * new sentinel chunk below the allocated space. */ + if (p != end) { + /* Valid/safe because of the prologue increment. */ + n -= CKB_SIZE_ALIGN; + p = (char *)p + CKB_SIZE_ALIGN; + w = CKB_MEM_TO_CHUNK(p); + w->psize = 0 | CKB_C_INUSE; + } + + /* Record new heap end and fill in footer. */ + end = (char *)p + n; + w = CKB_MEM_TO_CHUNK(end); + w->psize = n | CKB_C_INUSE; + w->csize = 0 | CKB_C_INUSE; + + /* Fill in header, which may be new or may be replacing a + * zero-size sentinel header at the old end-of-heap. */ + w = CKB_MEM_TO_CHUNK(p); + w->csize = n | CKB_C_INUSE; + + return w; +} + +static int adjust_size(size_t *n) { + /* Result of pointer difference must fit in ptrdiff_t. */ + if (*n - 1 > INT64_MAX - CKB_SIZE_ALIGN - CKB_PAGE_SIZE) { + if (*n) { + return -1; + } else { + *n = CKB_SIZE_ALIGN; + return 0; + } + } + *n = (*n + CKB_OVERHEAD + CKB_SIZE_ALIGN - 1) & CKB_SIZE_MASK; + return 0; +} + +static void unbin(struct chunk *c, int i) { + if (c->prev == c->next) a_and_64(&mal.binmap, ~(1ULL << i)); + c->prev->next = c->next; + c->next->prev = c->prev; + c->csize |= CKB_C_INUSE; + CKB_NEXT_CHUNK(c)->psize |= CKB_C_INUSE; +} + +static void bin_chunk(struct chunk *self, int i) { + self->next = CKB_BIN_TO_CHUNK(i); + self->prev = mal.bins[i].tail; + self->next->prev = self; + self->prev->next = self; + if (self->prev == CKB_BIN_TO_CHUNK(i)) a_or_64(&mal.binmap, 1ULL << i); +} + +static void trim(struct chunk *self, size_t n) { + size_t n1 = CKB_CHUNK_SIZE(self); + struct chunk *next, *split; + + if (n >= n1 - CKB_DONTCARE) return; + + next = CKB_NEXT_CHUNK(self); + split = (void *)((char *)self + n); + + split->psize = n | CKB_C_INUSE; + split->csize = n1 - n; + next->psize = n1 - n; + self->csize = n | CKB_C_INUSE; + + int i = bin_index(n1 - n); + lock_bin(i); + + bin_chunk(split, i); + + unlock_bin(i); +} + +void *malloc(size_t n) { + struct chunk *c; + int i, j; + uint64_t mask; + + if (adjust_size(&n) < 0) return 0; + + if (n >= CKB_MMAP_THRESHOLD) { + // TODO: don't support too large memory + return 0; + } + + i = bin_index_up(n); + if (i < 63 && (mal.binmap & (1ULL << i))) { + lock_bin(i); + c = mal.bins[i].head; + if (c != CKB_BIN_TO_CHUNK(i) && CKB_CHUNK_SIZE(c) - n <= CKB_DONTCARE) { + unbin(c, i); + unlock_bin(i); + return CKB_CHUNK_TO_MEM(c); + } + unlock_bin(i); + } + for (mask = mal.binmap & -(1ULL << i); mask; mask -= (mask & -mask)) { + j = first_set(mask); + lock_bin(j); + c = mal.bins[j].head; + if (c != CKB_BIN_TO_CHUNK(j)) { + unbin(c, j); + unlock_bin(j); + break; + } + unlock_bin(j); + } + if (!mask) { + c = expand_heap(n); + if (!c) { + return 0; + } + } + trim(c, n); + return CKB_CHUNK_TO_MEM(c); +} + +void *calloc(size_t nitems, size_t size) { + void *ptr = malloc(nitems * size); + memset(ptr, 0, nitems * size); + return ptr; +} + +void *realloc(void *p, size_t n) { + struct chunk *self, *next; + size_t n0; + void *new; + + if (!p) return malloc(n); + + if (adjust_size(&n) < 0) return 0; + + self = CKB_MEM_TO_CHUNK(p); + n0 = CKB_CHUNK_SIZE(self); + + if (n <= n0 && n0 - n <= CKB_DONTCARE) return p; + + next = CKB_NEXT_CHUNK(self); + + /* Crash on corrupted footer (likely from buffer overflow) */ + if (next->psize != self->csize) a_crash(); + + if (n < n0) { + int i = bin_index_up(n); + int j = bin_index(n0); + if (i < j && (mal.binmap & (1ULL << i))) goto copy_realloc; + struct chunk *split = (void *)((char *)self + n); + self->csize = split->psize = n | CKB_C_INUSE; + split->csize = next->psize = (n0 - n) | CKB_C_INUSE; + __bin_chunk(split); + return CKB_CHUNK_TO_MEM(self); + } + + size_t nsize = next->csize & CKB_C_INUSE ? 0 : CKB_CHUNK_SIZE(next); + if (n0 + nsize >= n) { + int i = bin_index(nsize); + lock_bin(i); + if (!(next->csize & CKB_C_INUSE)) { + unbin(next, i); + unlock_bin(i); + next = CKB_NEXT_CHUNK(next); + self->csize = next->psize = (n0 + nsize) | CKB_C_INUSE; + trim(self, n); + return CKB_CHUNK_TO_MEM(self); + } + unlock_bin(i); + } +copy_realloc: + /* As a last resort, allocate a new chunk and copy to it. */ + new = malloc(n - CKB_OVERHEAD); + if (!new) return 0; + memcpy(new, p, (n < n0 ? n : n0) - CKB_OVERHEAD); + free(CKB_CHUNK_TO_MEM(self)); + return new; +} + +void __bin_chunk(struct chunk *self) { + struct chunk *next = CKB_NEXT_CHUNK(self); + + /* Crash on corrupted footer (likely from buffer overflow) */ + if (next->psize != self->csize) a_crash(); + + size_t osize = CKB_CHUNK_SIZE(self), size = osize; + + /* Since we hold split_merge_lock, only transition from free to + * in-use can race; in-use to free is impossible */ + size_t psize = self->psize & CKB_C_INUSE ? 0 : CKB_CHUNK_PSIZE(self); + size_t nsize = next->csize & CKB_C_INUSE ? 0 : CKB_CHUNK_SIZE(next); + + if (psize) { + int i = bin_index(psize); + lock_bin(i); + if (!(self->psize & CKB_C_INUSE)) { + struct chunk *prev = CKB_PREV_CHUNK(self); + unbin(prev, i); + self = prev; + size += psize; + } + unlock_bin(i); + } + if (nsize) { + int i = bin_index(nsize); + lock_bin(i); + if (!(next->csize & CKB_C_INUSE)) { + unbin(next, i); + next = CKB_NEXT_CHUNK(next); + size += nsize; + } + unlock_bin(i); + } + + int i = bin_index(size); + lock_bin(i); + + self->csize = size; + next->psize = size; + bin_chunk(self, i); + + unlock_bin(i); +} + +void free(void *p) { + if (!p) return; + struct chunk *self = CKB_MEM_TO_CHUNK(p); + __bin_chunk(self); +} + +size_t malloc_usable_size(void *ptr) { + struct chunk *c = CKB_MEM_TO_CHUNK(ptr); + return CKB_CHUNK_PSIZE(c); +} diff --git a/libc/src/math.c b/libc/src/math.c new file mode 100644 index 0000000..f1c70ce --- /dev/null +++ b/libc/src/math.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include + +#ifndef DBL_EPSILON +#define DBL_EPSILON 2.22044604925031308085e-16 +#endif + +double acos(double x) { + assert(0); + return 0; +} + +double acosh(double x) { + assert(0); + return 0; +} + +double asin(double x) { + assert(0); + return 0; +} + +double asinh(double x) { + assert(0); + return 0; +} + +double atan(double x) { + assert(0); + return 0; +} + +double atan2(double x, double y) { + assert(0); + return 0; +} + +double atanh(double x) { + assert(0); + return 0; +} + +double cos(double x) { + assert(0); + return 0; +} + +double cosh(double x) { + assert(0); + return 0; +} + +double exp(double x) { + assert(0); + return 0; +} + +double expm1(double x) { + assert(0); + return 0; +} + +#define EPS DBL_EPSILON +double floor(double x) { + static const double toint = 1 / EPS; + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff + 52 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -1 : 0; + } + if (y > 0) return x + y - 1; + return x + y; +} + +double ceil(double x) { + static const double toint = 1 / EPS; + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + double y; + + if (e >= 0x3ff + 52 || x == 0) return x; + /* y = int(x) - x, where int(x) is an integer neighbor of x */ + if (u.i >> 63) + y = x - toint + toint - x; + else + y = x + toint - toint - x; + /* special case because of non-nearest rounding modes */ + if (e <= 0x3ff - 1) { + FORCE_EVAL(y); + return u.i >> 63 ? -0.0 : 1; + } + if (y < 0) return x + y + 1; + return x + y; +} + +double fabs(double x) { + union { + double f; + uint64_t i; + } u = {x}; + u.i &= -1ULL / 2; + return u.f; +} + +double ldexp(double x, int n) { return scalbn(x, n); } + +double log2(double x) { + assert(0); + return 0; +} + +double log10(double x) { + assert(0); + return 0; +} + +double log1p(double x) { + assert(0); + return 0; +} + +double sin(double x) { + assert(0); + return 0; +} + +double sinh(double x) { + assert(0); + return 0; +} + +double sqrt(double x) { + assert(0); + return 0; +} + +double tan(double x) { + assert(0); + return 0; +} + +double tanh(double x) { + assert(0); + return 0; +} + +double rint(double x) { + static const double toint = 1 / EPS; + union { + double f; + uint64_t i; + } u = {x}; + int e = u.i >> 52 & 0x7ff; + int s = u.i >> 63; + double y; + + if (e >= 0x3ff + 52) return x; + if (s) + y = x - toint + toint; + else + y = x + toint - toint; + if (y == 0) return s ? -0.0 : 0; + return y; +} + +long int lrint(double x) { return rint(x); } + +double cbrt(double x) { + assert(0); + return 0; +} + +double fmod(double numer, double denom); + +double fmin(double x, double y) { return x > y ? y : x; } + +double fmax(double x, double y) { return x < y ? y : x; } + +double hypot(double x, double y) { + assert(0); + return 0; +} + +int signbit(double num) { return num > 0; } + +double frexp(double x, int *e) { + union { + double d; + uint64_t i; + } y = {x}; + int ee = y.i >> 52 & 0x7ff; + + if (!ee) { + if (x) { + x = frexp(x * 0x1p64, e); + *e -= 64; + } else + *e = 0; + return x; + } else if (ee == 0x7ff) { + return x; + } + + *e = ee - 0x3fe; + y.i &= 0x800fffffffffffffull; + y.i |= 0x3fe0000000000000ull; + return y.d; +} + +double fmod(double x, double y) { + union { + double f; + uint64_t i; + } ux = {x}, uy = {y}; + int ex = ux.i >> 52 & 0x7ff; + int ey = uy.i >> 52 & 0x7ff; + int sx = ux.i >> 63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i << 1 == 0 || __builtin_isnan(y) || ex == 0x7ff) + return (x * y) / (x * y); + if (uxi << 1 <= uy.i << 1) { + if (uxi << 1 == uy.i << 1) return 0 * x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi << 12; i >> 63 == 0; ex--, i <<= 1) + ; + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i << 12; i >> 63 == 0; ey--, i <<= 1) + ; + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) return 0 * x; + uxi = i; + } + for (; uxi >> 52 == 0; uxi <<= 1, ex--) + ; + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} + +int abs(int a) { return a > 0 ? a : -a; } + +int isnan(double x) { return __builtin_isnan(x); } + +int isfinite(double x) { return __builtin_isfinite(x); } + +double trunc(double x) { return __builtin_truncl(x); } diff --git a/include/c-stdlib/src/math_log_impl.c b/libc/src/math_log.c similarity index 57% rename from include/c-stdlib/src/math_log_impl.c rename to libc/src/math_log.c index 5539cca..f255e9b 100644 --- a/include/c-stdlib/src/math_log_impl.c +++ b/libc/src/math_log.c @@ -64,69 +64,69 @@ * to produce the hexadecimal values shown. */ -#include "my_math.h" +#include +#include #include -#include "my_float.h" double log(double x) { - double hfsq, f, s, z, R, w, t1, t2, dk; - int32_t k, hx, i, j; - uint32_t lx; + double hfsq, f, s, z, R, w, t1, t2, dk; + int32_t k, hx, i, j; + uint32_t lx; - EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hx, lx, x); - k = 0; - if (hx < 0x00100000) { /* x < 2**-1022 */ - if (((hx & 0x7fffffff) | lx) == 0) return -two54 / zero; /* log(+-0)=-inf */ - if (hx < 0) return (x - x) / zero; /* log(-#) = NaN */ - k -= 54; - x *= two54; /* subnormal number, scale up x */ - GET_HIGH_WORD(hx, x); + k = 0; + if (hx < 0x00100000) { /* x < 2**-1022 */ + if (((hx & 0x7fffffff) | lx) == 0) return -two54 / zero; /* log(+-0)=-inf */ + if (hx < 0) return (x - x) / zero; /* log(-#) = NaN */ + k -= 54; + x *= two54; /* subnormal number, scale up x */ + GET_HIGH_WORD(hx, x); + } + if (hx >= 0x7ff00000) return x + x; + k += (hx >> 20) - 1023; + hx &= 0x000fffff; + i = (hx + 0x95f64) & 0x100000; + SET_HIGH_WORD(x, hx | (i ^ 0x3ff00000)); /* normalize x or x/2 */ + k += (i >> 20); + f = x - 1.0; + if ((0x000fffff & (2 + hx)) < 3) { /* -2**-20 <= f < 2**-20 */ + if (f == zero) { + if (k == 0) { + return zero; + } else { + dk = (double)k; + return dk * ln2_hi + dk * ln2_lo; + } } - if (hx >= 0x7ff00000) return x + x; - k += (hx >> 20) - 1023; - hx &= 0x000fffff; - i = (hx + 0x95f64) & 0x100000; - SET_HIGH_WORD(x, hx | (i ^ 0x3ff00000)); /* normalize x or x/2 */ - k += (i >> 20); - f = x - 1.0; - if ((0x000fffff & (2 + hx)) < 3) { /* -2**-20 <= f < 2**-20 */ - if (f == zero) { - if (k == 0) { - return zero; - } else { - dk = (double)k; - return dk * ln2_hi + dk * ln2_lo; - } - } - R = f * f * (0.5 - 0.33333333333333333 * f); - if (k == 0) - return f - R; - else { - dk = (double)k; - return dk * ln2_hi - ((R - dk * ln2_lo) - f); - } - } - s = f / (2.0 + f); - dk = (double)k; - z = s * s; - i = hx - 0x6147a; - w = z * z; - j = 0x6b851 - hx; - t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); - t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); - i |= j; - R = t2 + t1; - if (i > 0) { - hfsq = 0.5 * f * f; - if (k == 0) - return f - (hfsq - s * (hfsq + R)); - else - return dk * ln2_hi - ((hfsq - (s * (hfsq + R) + dk * ln2_lo)) - f); - } else { - if (k == 0) - return f - s * (f - R); - else - return dk * ln2_hi - ((s * (f - R) - dk * ln2_lo) - f); + R = f * f * (0.5 - 0.33333333333333333 * f); + if (k == 0) + return f - R; + else { + dk = (double)k; + return dk * ln2_hi - ((R - dk * ln2_lo) - f); } + } + s = f / (2.0 + f); + dk = (double)k; + z = s * s; + i = hx - 0x6147a; + w = z * z; + j = 0x6b851 - hx; + t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); + t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); + i |= j; + R = t2 + t1; + if (i > 0) { + hfsq = 0.5 * f * f; + if (k == 0) + return f - (hfsq - s * (hfsq + R)); + else + return dk * ln2_hi - ((hfsq - (s * (hfsq + R) + dk * ln2_lo)) - f); + } else { + if (k == 0) + return f - s * (f - R); + else + return dk * ln2_hi - ((s * (f - R) - dk * ln2_lo) - f); + } } diff --git a/libc/src/math_pow.c b/libc/src/math_pow.c new file mode 100644 index 0000000..8f49c97 --- /dev/null +++ b/libc/src/math_pow.c @@ -0,0 +1,331 @@ +/* @(#)e_pow.c 1.5 04/04/22 SMI */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +//__FBSDID("$FreeBSD: src/lib/msun/src/e_pow.c,v 1.14 2011/10/21 06:26:07 das +// Exp $"); + +/* __ieee754_pow(x,y) return x**y + * + * n + * Method: Let x = 2 * (1+f) + * 1. Compute and return log2(x) in two pieces: + * log2(x) = w1 + w2, + * where w1 has 53-24 = 29 bit trailing zeros. + * 2. Perform y*log2(x) = n+y' by simulating muti-precision + * arithmetic, where |y'|<=0.5. + * 3. Return x**y = 2**n*exp(y'*log2) + * + * Special cases: + * 1. (anything) ** 0 is 1 + * 2. (anything) ** 1 is itself + * 3. (anything) ** NAN is NAN + * 4. NAN ** (anything except 0) is NAN + * 5. +-(|x| > 1) ** +INF is +INF + * 6. +-(|x| > 1) ** -INF is +0 + * 7. +-(|x| < 1) ** +INF is +0 + * 8. +-(|x| < 1) ** -INF is +INF + * 9. +-1 ** +-INF is NAN + * 10. +0 ** (+anything except 0, NAN) is +0 + * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 + * 12. +0 ** (-anything except 0, NAN) is +INF + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF + * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) + * 15. +INF ** (+anything except 0,NAN) is +INF + * 16. +INF ** (-anything except 0,NAN) is +0 + * 17. -INF ** (anything) = -0 ** (-anything) + * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * + * Accuracy: + * pow(x,y) returns x**y nearly rounded. In particular + * pow(integer,integer) + * always returns the correct integer provided it is + * representable. + * + * Constants : + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ +#include +#include +#include + +double copysign(double x, double y) { + uint32_t hx, hy; + GET_HIGH_WORD(hx, x); + GET_HIGH_WORD(hy, y); + SET_HIGH_WORD(x, (hx & 0x7fffffff) | (hy & 0x80000000)); + return x; +} + +double scalbn(double x, int n) { + int32_t k, hx, lx; + EXTRACT_WORDS(hx, lx, x); + k = (hx & 0x7ff00000) >> 20; /* extract exponent */ + if (k == 0) { /* 0 or subnormal x */ + if ((lx | (hx & 0x7fffffff)) == 0) return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx, x); + k = ((hx & 0x7ff00000) >> 20) - 54; + if (n < -50000) return tiny * x; /*underflow*/ + } + if (k == 0x7ff) return x + x; /* NaN or Inf */ + k = k + n; + if (k > 0x7fe) return huge * copysign(huge, x); /* overflow */ + if (k > 0) /* normal result */ + { + SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); + return x; + } + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge * copysign(huge, x); /*overflow*/ + else + return tiny * copysign(tiny, x); /*underflow*/ + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); + return x * twom54; +} + +double pow(double x, double y) { + double z, ax, z_h, z_l, p_h, p_l; + double y1, t1, t2, r, s, t, u, v, w; + int32_t i, j, k, yisint, n; + int32_t hx, hy, ix, iy; + uint32_t lx, ly; + + EXTRACT_WORDS(hx, lx, x); + EXTRACT_WORDS(hy, ly, y); + ix = hx & 0x7fffffff; + iy = hy & 0x7fffffff; + + /* y==zero: x**0 = 1 */ + if ((iy | ly) == 0) return one; + + /* x==1: 1**y = 1, even if y is NaN */ + if (hx == 0x3ff00000 && lx == 0) return one; + + /* y!=zero: result is NaN if either arg is NaN */ + if (ix > 0x7ff00000 || ((ix == 0x7ff00000) && (lx != 0)) || iy > 0x7ff00000 || + ((iy == 0x7ff00000) && (ly != 0))) + return (x + 0.0) + (y + 0.0); + + /* determine if y is an odd int when x < 0 + * yisint = 0 ... y is not an integer + * yisint = 1 ... y is an odd int + * yisint = 2 ... y is an even int + */ + yisint = 0; + if (hx < 0) { + if (iy >= 0x43400000) + yisint = 2; /* even integer y */ + else if (iy >= 0x3ff00000) { + k = (iy >> 20) - 0x3ff; /* exponent */ + if (k > 20) { + j = ly >> (52 - k); + if ((j << (52 - k)) == (int32_t)ly) yisint = 2 - (j & 1); + } else if (ly == 0) { + j = iy >> (20 - k); + if ((j << (20 - k)) == iy) yisint = 2 - (j & 1); + } + } + } + + /* special value of y */ + if (ly == 0) { + if (iy == 0x7ff00000) { /* y is +-inf */ + if (((ix - 0x3ff00000) | lx) == 0) + return one; /* (-1)**+-inf is NaN */ + else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ + return (hy >= 0) ? y : zero; + else /* (|x|<1)**-,+inf = inf,0 */ + return (hy < 0) ? -y : zero; + } + if (iy == 0x3ff00000) { /* y is +-1 */ + if (hy < 0) + return one / x; + else + return x; + } + if (hy == 0x40000000) return x * x; /* y is 2 */ + if (hy == 0x40080000) return x * x * x; /* y is 3 */ + if (hy == 0x40100000) { /* y is 4 */ + u = x * x; + return u * u; + } + if (hy == 0x3fe00000) { /* y is 0.5 */ + if (hx >= 0) /* x >= +0 */ + return sqrt(x); + } + } + + ax = fabs(x); + /* special value of x */ + if (lx == 0) { + if (ix == 0x7ff00000 || ix == 0 || ix == 0x3ff00000) { + z = ax; /*x is +-0,+-inf,+-1*/ + if (hy < 0) z = one / z; /* z = (1/|x|) */ + if (hx < 0) { + if (((ix - 0x3ff00000) | yisint) == 0) { + z = (z - z) / (z - z); /* (-1)**non-int is NaN */ + } else if (yisint == 1) + z = -z; /* (x<0)**odd = -(|x|**odd) */ + } + return z; + } + } + + /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be + n = (hx>>31)+1; + but ANSI C says a right shift of a signed negative quantity is + implementation defined. */ + n = ((uint32_t)hx >> 31) - 1; + + /* (x<0)**(non-int) is NaN */ + if ((n | yisint) == 0) return (x - x) / (x - x); + + s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ + if ((n | (yisint - 1)) == 0) s = -one; /* (-ve)**(odd int) */ + + /* |y| is huge */ + if (iy > 0x41e00000) { /* if |y| > 2**31 */ + if (iy > 0x43f00000) { /* if |y| > 2**64, must o/uflow */ + if (ix <= 0x3fefffff) return (hy < 0) ? huge * huge : tiny * tiny; + if (ix >= 0x3ff00000) return (hy > 0) ? huge * huge : tiny * tiny; + } + /* over/underflow if x is not close to one */ + if (ix < 0x3fefffff) return (hy < 0) ? s * huge * huge : s * tiny * tiny; + if (ix > 0x3ff00000) return (hy > 0) ? s * huge * huge : s * tiny * tiny; + /* now |1-x| is tiny <= 2**-20, suffice to compute + log(x) by x-x^2/2+x^3/3-x^4/4 */ + t = ax - one; /* t has 20 trailing zeros */ + w = (t * t) * (0.5 - t * (0.3333333333333333333333 - t * 0.25)); + u = ivln2_h * t; /* ivln2_h has 21 sig. bits */ + v = t * ivln2_l - w * ivln2; + t1 = u + v; + SET_LOW_WORD(t1, 0); + t2 = v - (t1 - u); + } else { + double ss, s2, s_h, s_l, t_h, t_l; + n = 0; + /* take care subnormal number */ + if (ix < 0x00100000) { + ax *= two53; + n -= 53; + GET_HIGH_WORD(ix, ax); + } + n += ((ix) >> 20) - 0x3ff; + j = ix & 0x000fffff; + /* determine interval */ + ix = j | 0x3ff00000; /* normalize ix */ + if (j <= 0x3988E) + k = 0; /* |x|> 1) | 0x20000000) + 0x00080000 + (k << 18)); + t_l = ax - (t_h - bp[k]); + s_l = v * ((u - s_h * t_h) - s_h * t_l); + /* compute log(ax) */ + s2 = ss * ss; + r = s2 * s2 * + (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6))))); + r += s_l * (s_h + ss); + s2 = s_h * s_h; + t_h = 3.0 + s2 + r; + SET_LOW_WORD(t_h, 0); + t_l = r - ((t_h - 3.0) - s2); + /* u+v = ss*(1+...) */ + u = s_h * t_h; + v = s_l * t_h + t_l * ss; + /* 2/(3log2)*(ss+...) */ + p_h = u + v; + SET_LOW_WORD(p_h, 0); + p_l = v - (p_h - u); + z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */ + z_l = cp_l * p_h + p_l * cp + dp_l[k]; + /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ + t = (double)n; + t1 = (((z_h + z_l) + dp_h[k]) + t); + SET_LOW_WORD(t1, 0); + t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); + } + + /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ + y1 = y; + SET_LOW_WORD(y1, 0); + p_l = (y - y1) * t1 + y * t2; + p_h = y1 * t1; + z = p_l + p_h; + EXTRACT_WORDS(j, i, z); + if (j >= 0x40900000) { /* z >= 1024 */ + if (((j - 0x40900000) | i) != 0) /* if z > 1024 */ + return s * huge * huge; /* overflow */ + else { + if (p_l + ovt > z - p_h) return s * huge * huge; /* overflow */ + } + } else if ((j & 0x7fffffff) >= 0x4090cc00) { /* z <= -1075 */ + if (((j - 0xc090cc00) | i) != 0) /* z < -1075 */ + return s * tiny * tiny; /* underflow */ + else { + if (p_l <= z - p_h) return s * tiny * tiny; /* underflow */ + } + } + /* + * compute 2**(p_h+p_l) + */ + i = j & 0x7fffffff; + k = (i >> 20) - 0x3ff; + n = 0; + if (i > 0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ + n = j + (0x00100000 >> (k + 1)); + k = ((n & 0x7fffffff) >> 20) - 0x3ff; /* new k for n */ + t = zero; + SET_HIGH_WORD(t, n & ~(0x000fffff >> k)); + n = ((n & 0x000fffff) | 0x00100000) >> (20 - k); + if (j < 0) n = -n; + p_h -= t; + } + t = p_l + p_h; + SET_LOW_WORD(t, 0); + u = t * lg2_h; + v = (p_l - (t - p_h)) * lg2 + t * lg2_l; + z = u + v; + w = v - (z - u); + t = z * z; + t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5)))); + r = (z * t1) / (t1 - two) - (w + z * w); + z = one - (r - z); + GET_HIGH_WORD(j, z); + j += (n << 20); + if ((j >> 20) <= 0) + z = scalbn(z, n); /* subnormal output */ + else + SET_HIGH_WORD(z, j); + return s * z; +} diff --git a/libc/src/printf.c b/libc/src/printf.c new file mode 100644 index 0000000..6106d15 --- /dev/null +++ b/libc/src/printf.c @@ -0,0 +1,1073 @@ +#undef CKB_C_STDLIB_PRINTF +#define CKB_MALLOC_DECLARATION_ONLY 1 + +// Code copied from +// https://github.com/mpaland/printf/tree/d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3e + +#include +#include +#include +#include +#include + +/** + * Output a character to a custom device like UART, used by the printf() + * function This function is declared here only. You have to write your custom + * implementation somewhere \param character Character to output + */ +void _putchar(char character); + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro + * defines and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not + * counting the terminating null character + */ +int printf_(const char *format, ...); + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING + * (V)SNPRINTF INSTEAD! \param buffer A pointer to the buffer where to store the + * formatted string. MUST be big enough to store the output! \param format A + * string that specifies the format of the output \return The number of + * characters that are WRITTEN into the buffer, not counting the terminating + * null character + */ +int sprintf(char *buffer, const char *format, ...); + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, + * including a terminating null character \param format A string that specifies + * the format of the output \param va A value identifying a variable arguments + * list \return The number of characters that COULD have been written into the + * buffer, not counting the terminating null character. A value equal or larger + * than count indicates truncation. Only when the returned value is non-negative + * and less than count, the string has been completely written. + */ +int snprintf_(char *buffer, size_t count, const char *format, ...); +int vsnprintf_(char *buffer, size_t count, const char *format, va_list va); + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not + * counting the terminating null character + */ +#define vprintf vprintf_ +int vprintf_(const char *format, va_list va); + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() + * output \param out An output function which takes one character and an + * argument pointer \param arg An argument pointer for user data passed to + * output function \param format A string that specifies the format of the + * output \return The number of characters that are sent to the output function, + * not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void *arg), void *arg, + const char *format, ...); + +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for +// speed on +// embedded systems with a very limited resources. These routines are +// thread safe and reentrant! Use this instead of the bloated +// standard/newlib printf cause these use malloc for printf (and may not +// be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + +// import float.h for DBL_MAX +// #if defined(PRINTF_SUPPORT_FLOAT) +// #include +// #endif + +// output function type +typedef void (*out_fct_type)(char character, void *buffer, size_t idx, + size_t maxlen); + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void *arg); + void *arg; +} out_fct_wrap_type; + +// internal buffer output +static inline void _out_buffer(char character, void *buffer, size_t idx, + size_t maxlen) { + if (idx < maxlen) { + ((char *)buffer)[idx] = character; + } +} + +// internal null output +static inline void _out_null(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; +} + +// internal _putchar wrapper +static inline void _out_char(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)buffer; + (void)idx; + (void)maxlen; + if (character) { + _putchar(character); + } +} + +// internal output function wrapper +static inline void _out_fct(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)idx; + (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type *)buffer) + ->fct(character, ((out_fct_wrap_type *)buffer)->arg); + } +} + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by +// 'maxsize' +static inline unsigned int _strnlen_s(const char *str, size_t maxsize) { + const char *s; + for (s = str; *s && maxsize--; ++s) + ; + return (unsigned int)(s - str); +} + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) { return (ch >= '0') && (ch <= '9'); } + +// internal ASCII string to unsigned int conversion +unsigned int _atoi(const char **str) { + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +int atoi(const char *str) { + if (str[0] == '+') { + const char *sub = str + 1; + return +_atoi(&sub); + } + if (str[0] == '-') { + const char *sub = str + 1; + return -_atoi(&sub); + } + return _atoi(&str); +} + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, const char *buf, size_t len, + unsigned int width, unsigned int flags) { + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, char *buf, size_t len, bool negative, + unsigned int base, unsigned int prec, + unsigned int width, unsigned int flags) { + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && + (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && + ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, unsigned long value, bool negative, + unsigned long base, unsigned int prec, + unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 + ? '0' + digit + : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, + (unsigned int)base, prec, width, flags); +} + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, unsigned long long value, + bool negative, unsigned long long base, + unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 + ? '0' + digit + : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, + (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > +// PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags); +#endif + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, + 10000, 100000, 1000000, 10000000, + 100000000, 1000000000}; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, + (flags & FLAGS_PLUS) ? "fni+" : "fni", + (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which + // could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if (diff < 0.5) { + } else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by +// Martijn Jasperse +static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags) { + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay + // (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | + (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln + // around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see + // https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside + // 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the + // exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, + flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = + _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, + expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, + const char *format, va_list va) { + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': + flags |= FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FLAGS_HASH; + format++; + n = 1U; + break; + default: + n = 0U; + break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l': + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h': + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't': + flags |= + (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j': + flags |= + (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= + (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default: + break; + } + + // evaluate specifier + switch (*format) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } else if (*format == 'o') { + base = 8U; + } else if (*format == 'b') { + base = 2U; + } else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long( + out, buffer, idx, maxlen, + (unsigned long long)(value > 0 ? value : 0 - value), value < 0, + base, precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned long)(value > 0 ? value : 0 - value), + value < 0, base, precision, width, flags); + } else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) + : (flags & FLAGS_SHORT) + ? (short int)va_arg(va, int) + : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned int)(value > 0 ? value : 0 - value), + value < 0, base, precision, width, flags); + } + } else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, + va_arg(va, unsigned long long), false, base, + precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + idx = + _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), + false, base, precision, width, flags); + } else { + const unsigned int value = + (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) + : (flags & FLAGS_SHORT) + ? (unsigned short int)va_arg(va, unsigned int) + : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, + precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f': + case 'F': + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, + width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, + width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c': { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's': { + const char *p = va_arg(va, char *); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p': { + width = sizeof(void *) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, + (uintptr_t)va_arg(va, void *), false, 16U, + precision, width, flags); + } else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned long)((uintptr_t)va_arg(va, void *)), + false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%': + out('%', buffer, idx++, maxlen); + format++; + break; + + default: + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +/////////////////////////////////////////////////////////////////////////////// + +int printf_(const char *format, ...) { + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int sprintf(char *buffer, const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int snprintf(char *buffer, size_t count, const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int vprintf_(const char *format, va_list va) { + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + +int vsnprintf(char *buffer, size_t count, const char *format, va_list va) { + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + +int fctprintf(void (*out)(char character, void *arg), void *arg, + const char *format, ...) { + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = {out, arg}; + const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap, + (size_t)-1, format, va); + va_end(va); + return ret; +} + +// Default PRINTF_BUFFER_SIZE +#ifndef CKB_C_STDLIB_PRINTF_BUFFER_SIZE +#define CKB_C_STDLIB_PRINTF_BUFFER_SIZE 2048 +#endif +// syscall +int ckb_debug(const char *s); + +int printf(const char *format, ...) { + static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; + va_list va; + va_start(va, format); + int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); + va_end(va); + ckb_debug(buf); + return ret; +} + +int ckb_printf(const char *format, ...) { + static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; + va_list va; + va_start(va, format); + int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); + va_end(va); + ckb_debug(buf); + return ret; +} + +int ckb_vprintf(const char *format, va_list va) { + static char buf[CKB_C_STDLIB_PRINTF_BUFFER_SIZE]; + int ret = vsnprintf(buf, CKB_C_STDLIB_PRINTF_BUFFER_SIZE, format, va); + ckb_debug(buf); + return ret; +} diff --git a/libc/src/stdio.c b/libc/src/stdio.c new file mode 100644 index 0000000..bfb709a --- /dev/null +++ b/libc/src/stdio.c @@ -0,0 +1,346 @@ +#include +#include +#include +#include "ckb_syscall_apis.h" + +FILE *stdin; +FILE *stdout; +FILE *stderr; + +static int s_local_access_enabled = 0; +void enable_local_access(int b) { s_local_access_enabled = b; } + +static int s_fs_access_enabled = 0; +void enable_fs_access(int b) { s_fs_access_enabled = b; } +int fs_access_enabled() { return s_fs_access_enabled; } + +#define memory_barrier() asm volatile("fence" ::: "memory") + +static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, + long _a3, long _a4, long _a5) { + register long a0 asm("a0") = _a0; + register long a1 asm("a1") = _a1; + register long a2 asm("a2") = _a2; + register long a3 asm("a3") = _a3; + register long a4 asm("a4") = _a4; + register long a5 asm("a5") = _a5; + +#ifdef __riscv_32e + register long syscall_id asm("t0") = n; +#else + register long syscall_id asm("a7") = n; +#endif + + asm volatile("scall" + : "+r"(a0) + : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); + /* + * Syscalls might modify memory sent as pointer, adding a barrier here + * ensures gcc won't do incorrect optimization. + */ + memory_barrier(); + + return a0; +} + +#define ckb_syscall(n, a, b, c, d, e, f) \ + __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ + (long)(f)) + +#define NOT_IMPL(name) \ + do { \ + printf("The %s is not implemented in stdio.c ", #name); \ + ckb_exit(-1); \ + } while (0) + +FILE *allocfile() { + FILE *file = malloc(sizeof(FILE)); + file->file = 0; + file->offset = 0; + return file; +} + +void freefile(FILE *file) { + file->file->rc -= 1; + free((void *)file); +} + +int remove(const char *__filename) { + NOT_IMPL(remove); + return 0; +} + +int rename(const char *__old, const char *__new) { + NOT_IMPL(rename); + return 0; +} + +FILE *tmpfile(void) { + NOT_IMPL(tmpfile); + return 0; +} + +char *tmpnam(char *__s) { + NOT_IMPL(tmpnam); + return 0; +} + +char *tempnam(const char *__dir, const char *__pfx) { + NOT_IMPL(tempnam); + return 0; +} + +int fclose(FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9009, stream, 0, 0, 0, 0, 0); + } + if (!fs_access_enabled()) { + NOT_IMPL(fclose); + } + freefile(stream); + return 0; +} + +int fflush(FILE *__stream) { + NOT_IMPL(fflush); + return 0; +} + +FILE *fopen(const char *path, const char *mode) { + if (s_local_access_enabled) { + return (void *)ckb_syscall(9003, path, mode, 0, 0, 0, 0); + } + + if (!fs_access_enabled()) { + NOT_IMPL(fopen); + } + + FILE *file = allocfile(); + if (file == 0) { + return 0; + } + + int ret = ckb_get_file(path, &file->file); + if (ret != 0) { + return 0; + } + return file; +} + +FILE *freopen(const char *path, const char *mode, FILE *stream) { + if (s_local_access_enabled) { + return (void *)ckb_syscall(9004, path, mode, stream, 0, 0, 0); + } + NOT_IMPL(freopen); + return 0; +} + +void setbuf(FILE *__stream, char *__buf) { NOT_IMPL(setbuf); } + +int setvbuf(FILE *__stream, char *__buf, int __modes, size_t __n) { + NOT_IMPL(setvbuf); + return 0; +} + +int fprintf(FILE *__stream, const char *__format, ...) { + NOT_IMPL(fprintf); + return 0; +} + +int vfprintf(FILE *__s, const char *__format, ...) { + NOT_IMPL(vfprintf); + return 0; +} +int vsprintf(char *__s, const char *__format, ...) { + NOT_IMPL(vsprintf); + return 0; +} + +int fscanf(FILE *__stream, const char *__format, ...) { + NOT_IMPL(fscanf); + return 0; +} + +int scanf(const char *__format, ...) { + NOT_IMPL(scanf); + return 0; +} + +int sscanf(const char *__s, const char *__format, ...) { + NOT_IMPL(sscanf); + return 0; +}; + +int fgetc(FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9008, stream, 0, 0, 0, 0, 0); + } + if (!fs_access_enabled()) { + NOT_IMPL(fgetc); + } + if (stream == 0 || stream->file->rc == 0 || + stream->offset == stream->file->size) { + return -1; // EOF + } + unsigned char *c = (unsigned char *)stream->file->content + stream->offset; + stream->offset++; + return *c; +} + +int getc(FILE *stream) { return fgetc(stream); } + +int getchar(void) { + NOT_IMPL(getchar); + return 0; +} + +int fputc(int __c, FILE *__stream) { + NOT_IMPL(fputc); + return 0; +} + +int putc(int __c, FILE *__stream) { + NOT_IMPL(putc); + return 0; +} + +int putchar(int __c) { + NOT_IMPL(putchar); + return 0; +} + +char *fgets(char *__s, int __n, FILE *__stream) { + NOT_IMPL(fgets); + return 0; +} + +char *gets(char *__s) { + NOT_IMPL(gets); + return 0; +} + +int getline(char **__lineptr, size_t *__n, FILE *__stream) { + NOT_IMPL(getline); + return 0; +} + +int fputs(const char *__s, FILE *__stream) { + NOT_IMPL(fputs); + return 0; +} + +int puts(const char *__s) { + NOT_IMPL(puts); + return 0; +} + +int ungetc(int __c, FILE *__stream) { + NOT_IMPL(ungetc); + return 0; +} + +int isvalidfile(FILE *stream) { + if (stream == 0 || stream->file->rc == 0) { + return 1; + } + return 0; +} + +void mustbevaildfile(FILE *stream) { + if (isvalidfile(stream) != 0) { + ckb_exit(1); + } +} + +size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9005, ptr, size, nitems, stream, 0, 0); + } + if (!fs_access_enabled()) { + NOT_IMPL(fread); + } + mustbevaildfile(stream); + // TODO: How do we handle error here? + if (stream->offset == stream->file->size) { + return 0; + } + // TODO: handle the case size * nitems is greater than uint32_t max + // handle size * ntimes overflowing + uint32_t bytes_to_read = (uint32_t)size * (uint32_t)nitems; + if (bytes_to_read > stream->file->size - stream->offset) { + bytes_to_read = stream->file->size - stream->offset; + } + memcpy(ptr, stream->file->content + stream->offset, bytes_to_read); + stream->offset = stream->offset + bytes_to_read; + // The return value should be the number of items written to the ptr + uint32_t s = size; + return (bytes_to_read + s - 1) / s; +} + +size_t fwrite(const void *__ptr, size_t __size, size_t __n, FILE *__s) { + NOT_IMPL(fwrite); + return 0; +} + +int fseek(FILE *stream, long int offset, int whence) { + if (s_local_access_enabled) { + return ckb_syscall(9011, stream, offset, whence, 0, 0, 0); + } + NOT_IMPL(fseek); + return 0; +} + +long int ftell(FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9010, stream, 0, 0, 0, 0, 0); + } + NOT_IMPL(ftell); + return 0; +} + +void rewind(FILE *__stream) { NOT_IMPL(rewind); } + +void clearerr(FILE *__stream) { NOT_IMPL(clearerr); } + +int feof(FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9006, stream, 0, 0, 0, 0, 0); + } + if (!fs_access_enabled()) { + NOT_IMPL(feof); + } + if (stream->offset == stream->file->size) { + return 1; + } + return 0; +} + +int ferror(FILE *stream) { + if (s_local_access_enabled) { + return ckb_syscall(9007, stream, 0, 0, 0, 0, 0); + } + if (!fs_access_enabled()) { + NOT_IMPL(ferror); + } + if (stream == 0 || stream->file->rc == 0) { + return 1; + } + return 0; +} + +void perror(const char *__s) { NOT_IMPL(perror); } + +int fileno(FILE *__stream) { + NOT_IMPL(fileno); + return 0; +} + +FILE *popen(const char *__command, const char *__modes) { + NOT_IMPL(popen); + return 0; +} + +int pclose(FILE *__stream) { + NOT_IMPL(pclose); + return 0; +} diff --git a/libc/src/stdlib.c b/libc/src/stdlib.c new file mode 100644 index 0000000..aeeaff3 --- /dev/null +++ b/libc/src/stdlib.c @@ -0,0 +1,275 @@ +#include +#include +#include "ckb_syscall_apis.h" + +int isspace(int c) { return c == ' ' || (unsigned)c - '\t' < 5; } + +// Copied from dietlibc +float strtof(const char *s, char **endptr) { + register const char *p = s; + register float value = 0.; + int sign = +1; + float factor; + unsigned int expo; + + while (isspace(*p)) p++; + + switch (*p) { + case '-': + sign = -1; /* fall through */ + case '+': + p++; + default: + break; + } + + while ((unsigned int)(*p - '0') < 10u) value = value * 10 + (*p++ - '0'); + + if (*p == '.') { + factor = 1.; + + p++; + while ((unsigned int)(*p - '0') < 10u) { + factor *= 0.1; + value += (*p++ - '0') * factor; + } + } + + if ((*p | 32) == 'e') { + expo = 0; + factor = 10.L; + + switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem + // 'E' folgenden MUSS. + case '-': + factor = 0.1; /* fall through */ + case '+': + p++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + value = 0.L; + p = s; + goto done; + } + + while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); + + while (1) { + if (expo & 1) value *= factor; + if ((expo >>= 1) == 0) break; + factor *= factor; + } + } + +done: + if (endptr != NULL) *endptr = (char *)p; + + return value * sign; +} + +// Convert char to an int in base `base`, +// `base` must be 10 or 16, return -1 on error. +int char2int(char ch, unsigned int base) { + if (ch >= '0' && ch <= '9') return ch - '0'; + if (base == 16) { + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + } + return -1; +} + +#define ldbltype long double +double strtod(const char *s, char **endptr) { + register const char *p = s; + register ldbltype value = 0.; + int sign = +1; + unsigned int base = 10; + ldbltype base_inverse = (ldbltype)1 / (ldbltype)base; + ldbltype factor; + unsigned int expo; + unsigned int has_digits = 0; + + while (isspace(*p)) p++; + + switch (*p) { + case '-': + sign = -1; /* fall through */ + case '+': + p++; + case '0': + p++; + if ((*p | 32) == 'x') { + base = 16; + base_inverse = (ldbltype)1 / (ldbltype)base; + p++; + } else { + p--; + } + default: + break; + } + + unsigned int current_value; + while ((current_value = char2int(*p, base)) != -1) { + p++; + value = value * base + current_value; + has_digits = 1; + } + + if (*p == '.') { + factor = 1.; + + p++; + while ((current_value = char2int(*p, base)) != -1) { + p++; + factor *= base_inverse; + value += current_value * factor; + has_digits = 1; + } + } + + if ((*p | 32) == 'e' && base == 10) { + expo = 0; + factor = 10.; + + switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem + // 'E' folgenden MUSS. + case '-': + factor = 0.1; /* fall through */ + case '+': + p++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + value = 0.; + p = s; + goto done; + } + + while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); + + while (1) { + if (expo & 1) value *= factor; + if ((expo >>= 1) == 0) break; + factor *= factor; + } + } + + if ((*p | 32) == 'p' && base == 16) { + // TODO: add specifier p support + // https://cplusplus.com/reference/cstdlib/strtod/ + // - A 0x or 0X prefix, then a sequence of hexadecimal digits (as in + // isxdigit) optionally containing a period which separates the whole + // and fractional number parts. Optionally followed by a power of 2 + // exponent (a p or P character followed by an optional sign and a + // sequence of hexadecimal digits). + } +done: + if (endptr != NULL) { + if (has_digits) { + *endptr = (char *)p; + } else { + *endptr = (char *)s; + } + } + + return value * sign; +} + +long double strtold(const char *s, char **endptr) { + register const char *p = s; + register long double value = 0.L; + int sign = +1; + long double factor; + unsigned int expo; + + while (isspace(*p)) p++; + + switch (*p) { + case '-': + sign = -1; /* fall through */ + case '+': + p++; + default: + break; + } + + while ((unsigned int)(*p - '0') < 10u) value = value * 10 + (*p++ - '0'); + + if (*p == '.') { + factor = 1.; + + p++; + while ((unsigned int)(*p - '0') < 10u) { + factor *= 0.1; + value += (*p++ - '0') * factor; + } + } + + if ((*p | 32) == 'e') { + expo = 0; + factor = 10.L; + + switch (*++p) { // ja hier weiß ich nicht, was mindestens nach einem + // 'E' folgenden MUSS. + case '-': + factor = 0.1; /* fall through */ + case '+': + p++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + value = 0.L; + p = s; + goto done; + } + + while ((unsigned int)(*p - '0') < 10u) expo = 10 * expo + (*p++ - '0'); + + while (1) { + if (expo & 1) value *= factor; + if ((expo >>= 1) == 0) break; + factor *= factor; + } + } + +done: + if (endptr != NULL) *endptr = (char *)p; + + return value * sign; +} + +void exit(int status) { ckb_exit(status); } + +void abort(void) { ckb_exit(-1); } diff --git a/libc/src/string.c b/libc/src/string.c new file mode 100644 index 0000000..0999241 --- /dev/null +++ b/libc/src/string.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ckb_syscall_apis.h" + +#define CKB_SS (sizeof(size_t)) +#define CKB_ALIGN (sizeof(size_t) - 1) +#define CKB_ONES ((size_t)-1 / UCHAR_MAX) +#define CKB_HIGHS (CKB_ONES * (UCHAR_MAX / 2 + 1)) +#define CKB_HASZERO(x) (((x)-CKB_ONES) & ~(x)&CKB_HIGHS) + +void *memchr(const void *src, int c, size_t n) { + const unsigned char *s = src; + c = (unsigned char)c; +#ifdef __GNUC__ + for (; ((uintptr_t)s & CKB_ALIGN) && n && *s != c; s++, n--) + ; + if (n && *s != c) { + typedef size_t __attribute__((__may_alias__)) word; + const word *w; + size_t k = CKB_ONES * c; + for (w = (const void *)s; n >= CKB_SS && !CKB_HASZERO(*w ^ k); + w++, n -= CKB_SS) + ; + s = (const void *)w; + } +#endif + for (; n && *s != c; s++, n--) + ; + return n ? (void *)s : 0; +} + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 \ + << ((size_t)(b) % (8 * sizeof *(a)))) + +char *__strchrnul(const char *s, int c) { + c = (unsigned char)c; + if (!c) return (char *)s + strlen(s); + + for (; *s && *(unsigned char *)s != c; s++) + ; + return (char *)s; +} + +char *strchr(const char *s, int c) { + char *r = __strchrnul(s, c); + return *(unsigned char *)r == (unsigned char)c ? r : 0; +} + +int strncmp(const char *_l, const char *_r, size_t n) { + const unsigned char *l = (void *)_l, *r = (void *)_r; + if (!n--) return 0; + for (; *l && *r && n && *l == *r; l++, r++, n--) + ; + return *l - *r; +} + +size_t strspn(const char *s, const char *c) { + const char *a = s; + size_t byteset[32 / sizeof(size_t)] = {0}; + + if (!c[0]) return 0; + if (!c[1]) { + for (; *s == *c; s++) + ; + return s - a; + } + + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) + ; + for (; *s && BITOP(byteset, *(unsigned char *)s, &); s++) + ; + return s - a; +} + +size_t strcspn(const char *s, const char *c) { + const char *a = s; + size_t byteset[32 / sizeof(size_t)]; + + if (!c[0] || !c[1]) return __strchrnul(s, *c) - a; + + memset(byteset, 0, sizeof byteset); + for (; *c && BITOP(byteset, *(unsigned char *)c, |=); c++) + ; + for (; *s && !BITOP(byteset, *(unsigned char *)s, &); s++) + ; + return s - a; +} + +char *strpbrk(const char *s, const char *b) { + s += strcspn(s, b); + return *s ? (char *)s : 0; +} + +static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) { + uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1]; + for (h++; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char *)h - 1 : 0; +} + +static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) { + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; + for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) + ; + return *h ? (char *)h - 2 : 0; +} + +static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) { + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) + ; + return *h ? (char *)h - 3 : 0; +} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BITOP(a, b, op) \ + ((a)[(size_t)(b) / (8 * sizeof *(a))] op(size_t) 1 \ + << ((size_t)(b) % (8 * sizeof *(a)))) + +static char *twoway_strstr(const unsigned char *h, const unsigned char *n) { + const unsigned char *z; + size_t l, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = {0}; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (l = 0; n[l] && h[l]; l++) BITOP(byteset, n[l], |=), shift[n[l]] = l + 1; + if (n[l]) return 0; /* hit the end of h */ + + /* Compute maximal suffix */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] > n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; + jp = 0; + k = p = 1; + while (jp + k < l) { + if (n[ip + k] == n[jp + k]) { + if (k == p) { + jp += p; + k = 1; + } else + k++; + } else if (n[ip + k] < n[jp + k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip + 1 > ms + 1) + ms = ip; + else + p = p0; + + /* Periodic needle? */ + if (memcmp(n, n + p, ms + 1)) { + mem0 = 0; + p = MAX(ms, l - ms - 1) + 1; + } else + mem0 = l - p; + mem = 0; + + /* Initialize incremental end-of-haystack pointer */ + z = h; + + /* Search loop */ + for (;;) { + /* Update incremental end-of-haystack pointer */ + if (z - h < l) { + /* Fast estimate for MAX(l,63) */ + size_t grow = l | 63; + const unsigned char *z2 = memchr(z, 0, grow); + if (z2) { + z = z2; + if (z - h < l) return 0; + } else + z += grow; + } + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l - 1], &)) { + k = l - shift[h[l - 1]]; + if (k) { + if (k < mem) k = mem; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++) + ; + if (n[k]) { + h += k - ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--) + ; + if (k <= mem) return (char *)h; + h += p; + mem = mem0; + } +} + +char *strstr(const char *h, const char *n) { + /* Return immediately on empty needle */ + if (!n[0]) return (char *)h; + + /* Use faster algorithms for short needles */ + h = strchr(h, *n); + if (!h || !n[1]) return (char *)h; + if (!h[1]) return 0; + if (!n[2]) return twobyte_strstr((void *)h, (void *)n); + if (!h[2]) return 0; + if (!n[3]) return threebyte_strstr((void *)h, (void *)n); + if (!h[3]) return 0; + if (!n[4]) return fourbyte_strstr((void *)h, (void *)n); + + return twoway_strstr((void *)h, (void *)n); +} + +/* Copied from + * https://github.com/bminor/musl/blob/46d1c7801bb509e1097e8fadbaf359367fa4ef0b/src/setjmp/riscv64/setjmp.S + */ +/* We need to use inline asm for easier compilation, + * https://stackoverflow.com/a/42358235. */ +/* We need __attribute__((naked)) to remove prologue and epilogue, + * https://stackoverflow.com/a/42637729 */ +__attribute__((naked)) int setjmp(jmp_buf b) { + asm volatile( + "sd s0, 0(a0)\n" + "sd s1, 8(a0)\n" + "sd s2, 16(a0)\n" + "sd s3, 24(a0)\n" + "sd s4, 32(a0)\n" + "sd s5, 40(a0)\n" + "sd s6, 48(a0)\n" + "sd s7, 56(a0)\n" + "sd s8, 64(a0)\n" + "sd s9, 72(a0)\n" + "sd s10, 80(a0)\n" + "sd s11, 88(a0)\n" + "sd sp, 96(a0)\n" + "sd ra, 104(a0)\n" + "li a0, 0\n" + "ret\n"); +} + +__attribute__((naked)) void longjmp(jmp_buf b, int n) { + asm volatile( + "ld s0, 0(a0)\n" + "ld s1, 8(a0)\n" + "ld s2, 16(a0)\n" + "ld s3, 24(a0)\n" + "ld s4, 32(a0)\n" + "ld s5, 40(a0)\n" + "ld s6, 48(a0)\n" + "ld s7, 56(a0)\n" + "ld s8, 64(a0)\n" + "ld s9, 72(a0)\n" + "ld s10, 80(a0)\n" + "ld s11, 88(a0)\n" + "ld sp, 96(a0)\n" + "ld ra, 104(a0)\n" + "seqz a0, a1\n" + "add a0, a0, a1\n" + "ret\n"); +} + +__attribute__((naked)) void _longjmp(jmp_buf b, int n) { + asm volatile( + "ld s0, 0(a0)\n" + "ld s1, 8(a0)\n" + "ld s2, 16(a0)\n" + "ld s3, 24(a0)\n" + "ld s4, 32(a0)\n" + "ld s5, 40(a0)\n" + "ld s6, 48(a0)\n" + "ld s7, 56(a0)\n" + "ld s8, 64(a0)\n" + "ld s9, 72(a0)\n" + "ld s10, 80(a0)\n" + "ld s11, 88(a0)\n" + "ld sp, 96(a0)\n" + "ld ra, 104(a0)\n" + "seqz a0, a1\n" + "add a0, a0, a1\n" + "ret\n"); +} + +int strcoll(const char *l, const char *r) { return strcmp(l, r); } + +int *__errno_location(void) { + static int error = -1; + return &error; +} + +char *strerror(int e) { + static char *errorstr = "There is an error"; + return errorstr; +} + +#define X(x) (((x) / 256 | (x)*256) % 65536) + +const unsigned short **__ctype_b_loc(void) { + static const unsigned short table[] = { + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x200), X(0x200), X(0x320), X(0x220), X(0x220), + X(0x220), X(0x220), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), + X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x200), X(0x160), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), + X(0x8d8), X(0x8d8), X(0x8d8), X(0x8d8), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x8d5), X(0x8d5), X(0x8d5), + X(0x8d5), X(0x8d5), X(0x8d5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), + X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), + X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), X(0x8c5), + X(0x8c5), X(0x8c5), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), X(0x4c0), + X(0x4c0), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), X(0x8d6), + X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), + X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), + X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x8c6), X(0x4c0), + X(0x4c0), X(0x4c0), X(0x4c0), X(0x200), 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + }; + + static const unsigned short *const ptable = table + 128; + return (void *)&ptable; +} + +const int32_t **__ctype_toupper_loc(void) { + static const int32_t table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 91, 92, 93, 94, 95, 96, + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 123, 124, 125, 126, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + static const int32_t *const ptable = table + 128; + + return (void *)&ptable; +} + +const int32_t **__ctype_tolower_loc(void) { + static const int32_t table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'a', 'b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 91, 92, 93, 94, 95, 96, + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123, 124, 125, 126, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + static const int32_t *const ptable = table + 128; + + return (void *)&ptable; +} + +char *getenv(const char *name) { return 0; } + +static void *__memrchr(const void *m, int c, size_t n) { + const unsigned char *s = m; + c = (unsigned char)c; + while (n--) + if (s[n] == c) return (void *)(s + n); + return 0; +} + +char *strrchr(const char *s, int character) { + return __memrchr(s, character, strlen(s) + 1); +} + +char *strcat(char *dest, const char *src) { + strcpy(dest + strlen(dest), src); + return dest; +} diff --git a/libc/src/sys_time.c b/libc/src/sys_time.c new file mode 100644 index 0000000..febe591 --- /dev/null +++ b/libc/src/sys_time.c @@ -0,0 +1,5 @@ +#include + +int gettimeofday(struct timeval *restrict tv, struct timezone *restrict tz) { + return 0; +}; diff --git a/libc/src/time.c b/libc/src/time.c new file mode 100644 index 0000000..45d9a32 --- /dev/null +++ b/libc/src/time.c @@ -0,0 +1,5 @@ +#include + +int clock_gettime(int c, struct timespec *ts) { return 0; } + +struct tm *localtime_r(const time_t *timer, struct tm *buf) { return 0; }; diff --git a/libc/stdarg.h b/libc/stdarg.h new file mode 100644 index 0000000..eb5e9d3 --- /dev/null +++ b/libc/stdarg.h @@ -0,0 +1,10 @@ +#ifndef CKB_C_STDLIB_STDARG_H_ +#define CKB_C_STDLIB_STDARG_H_ + +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define __va_copy(d, s) __builtin_va_copy(d, s) +#define va_list __builtin_va_list + +#endif /* CKB_C_STDLIB_STDARG_H_ */ diff --git a/libc/stdbool.h b/libc/stdbool.h new file mode 100644 index 0000000..327068b --- /dev/null +++ b/libc/stdbool.h @@ -0,0 +1,9 @@ +#ifndef CKB_C_STDLIB_STDBOOL_H_ +#define CKB_C_STDLIB_STDBOOL_H_ +#include + +#define true 1 +#define false 0 +#define bool _Bool + +#endif /* CKB_C_STDLIB_STDBOOL_H_ */ diff --git a/libc/stddef.h b/libc/stddef.h new file mode 100644 index 0000000..dbe70fc --- /dev/null +++ b/libc/stddef.h @@ -0,0 +1,11 @@ +#ifndef CKB_C_STDLIB_STDDEF_H_ +#define CKB_C_STDLIB_STDDEF_H_ + +#include "internal/types.h" +#define NULL ((void*)0) +#include + +typedef signed long ptrdiff_t; +typedef long long intmax_t; + +#endif /* CKB_C_STDLIB_STDDEF_H_ */ diff --git a/libc/stdint.h b/libc/stdint.h new file mode 100644 index 0000000..a75c90a --- /dev/null +++ b/libc/stdint.h @@ -0,0 +1,49 @@ +#ifndef CKB_C_STDLIB_STDINT_H_ +#define CKB_C_STDLIB_STDINT_H_ + +#include + +#include "internal/types.h" + +#define INT8_MIN (-1 - 0x7f) +#define INT16_MIN (-1 - 0x7fff) +#define INT32_MIN (-1 - 0x7fffffff) +#define INT64_MIN (-1 - 0x7fffffffffffffff) + +#define INT8_MAX (0x7f) +#define INT16_MAX (0x7fff) +#define INT32_MAX (0x7fffffff) +#define INT64_MAX (0x7fffffffffffffff) + +#define UINT8_MAX (0xff) +#define UINT16_MAX (0xffff) +#define UINT32_MAX (0xffffffffu) +#define UINT64_MAX (0xffffffffffffffffu) + +#define SIZE_MAX UINT64_MAX + +#define INTPTR_MIN (-9223372036854775807L - 1) +#define INTPTR_MAX (9223372036854775807L) +#define UINTPTR_MAX (18446744073709551615UL) + +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c + +#define UINT8_C(c) c +#define UINT16_C(c) c +#define UINT32_C(c) c##U + +#if UINTPTR_MAX == UINT64_MAX +#define INT64_C(c) c##L +#define UINT64_C(c) c##UL +#define INTMAX_C(c) c##L +#define UINTMAX_C(c) c##UL +#else +#define INT64_C(c) c##LL +#define UINT64_C(c) c##ULL +#define INTMAX_C(c) c##LL +#define UINTMAX_C(c) c##ULL +#endif + +#endif /* CKB_C_STDLIB_STDINT_H_ */ diff --git a/libc/stdio.h b/libc/stdio.h new file mode 100644 index 0000000..37afe61 --- /dev/null +++ b/libc/stdio.h @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for +// speed on +// embedded systems with a very limited resources. These routines are +// thread safe and reentrant! Use this instead of the bloated +// standard/newlib printf cause these use malloc for printf (and may not +// be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef CKB_C_STDLIB_STDIO_H_ +#define CKB_C_STDLIB_STDIO_H_ +#include + +/* + * This function uses `ckb_debug` syscall to output formatted messages. + * + * Pass `-D CKB_C_STDLIB_PRINTF` flag to GCC to enable printf; + * If the flag is undefined the printf will be compiled as an empty function. + * + * Some versions of GCC raise errors on compiling since those versions have a + * built-in printf function; pass `-fno-builtin-printf` flag to GCC to fix the + * compiling. + */ +int printf(const char *format, ...); +/* + * This function uses `ckb_debug` syscall to output formatted messages. + * + * Pass `-D CKB_C_STDLIB_PRINTF` flag to GCC to enable ckb_printf; + * If the flag is undefined the ckb_printf will be compiled as an empty + * function. + */ +int ckb_printf(const char *format, ...); +int ckb_debug(const char *s); + +#include +#include +#include "ckb_cell_fs.h" + +#define BUFSIZ 512 +#define EOF (-1) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 + +typedef struct FILE { + FSFile *file; + uint32_t offset; +} FILE; + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +int remove(const char *__filename); + +int rename(const char *__old, const char *__new); + +FILE *tmpfile(void); + +char *tmpnam(char *__s); + +char *tempnam(const char *__dir, const char *__pfx); + +int fclose(FILE *__stream); +int fflush(FILE *__stream); + +FILE *fopen(const char *__filename, const char *__modes); +FILE *freopen(const char *__filename, const char *__modes, FILE *__stream); + +void setbuf(FILE *__stream, char *__buf); +int setvbuf(FILE *__stream, char *__buf, int __modes, size_t __n); + +int fprintf(FILE *__stream, const char *__format, ...); + +int sprintf(char *__s, const char *__format, ...); + +int vfprintf(FILE *__s, const char *__format, ...); + +int vsprintf(char *__s, const char *__format, ...); +int vsnprintf(char *__s, size_t __maxlen, const char *__format, ...); +int snprintf(char *__s, size_t __maxlen, const char *__format, ...); +int snprintf_(char *__s, size_t __maxlen, const char *__format, ...); + +int fscanf(FILE *__stream, const char *__format, ...); + +int scanf(const char *__format, ...); + +int sscanf(const char *__s, const char *__format, ...); + +int fgetc(FILE *__stream); + +int getc(FILE *__stream); + +int getchar(void); + +int fputc(int __c, FILE *__stream); + +int putc(int __c, FILE *__stream); + +int putchar(int __c); + +char *fgets(char *__s, int __n, FILE *__stream); +char *gets(char *__s); + +int getline(char **__lineptr, size_t *__n, FILE *__stream); + +int fputs(const char *__s, FILE *__stream); + +int puts(const char *__s); + +int ungetc(int __c, FILE *__stream); + +size_t fread(void *__ptr, size_t __size, size_t __n, FILE *__stream); + +size_t fwrite(const void *__ptr, size_t __size, size_t __n, FILE *__s); + +int fseek(FILE *__stream, long int __off, int __whence); + +long int ftell(FILE *__stream); + +void rewind(FILE *__stream); + +void clearerr(FILE *__stream); + +int feof(FILE *__stream); + +int ferror(FILE *__stream); + +void perror(const char *__s); + +int fileno(FILE *__stream); + +FILE *popen(const char *__command, const char *__modes); + +int pclose(FILE *__stream); + +void enable_local_access(int); + +#endif /* CKB_C_STDLIB_STDIO_H_ */ diff --git a/libc/stdlib.h b/libc/stdlib.h new file mode 100644 index 0000000..5eab4c5 --- /dev/null +++ b/libc/stdlib.h @@ -0,0 +1,26 @@ +#ifndef CKB_C_STDLIB_STDLIB_H_ +#define CKB_C_STDLIB_STDLIB_H_ +#include +#include + +void *malloc(size_t size); +void free(void *ptr); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); +typedef int (*cmpfun)(const void *, const void *); +void qsort(void *base, size_t nel, size_t width, cmpfun cmp); +int rand(void); +void *bsearch(const void *key, const void *base, size_t nel, size_t width, + int (*cmp)(const void *, const void *)); + +float strtof(const char *__restrict, char **__restrict); +double strtod(const char *__restrict, char **__restrict); +long double strtold(const char *__restrict, char **__restrict); +int atoi(const char *); + +int abs(int); +void exit(int); +void abort(void); +#define alloca __builtin_alloca + +#endif /* CKB_C_STDLIB_STDLIB_H_ */ diff --git a/libc/string.h b/libc/string.h new file mode 100644 index 0000000..9ca7eba --- /dev/null +++ b/libc/string.h @@ -0,0 +1,27 @@ +#ifndef CKB_C_STDLIB_STRING_H_ +#define CKB_C_STDLIB_STRING_H_ + +#include +#include + +void *memset(void *dest, int c, size_t n); +void *memcpy(void *restrict dest, const void *restrict src, size_t n); +void *memmove(void *dest, const void *src, size_t n); +int memcmp(const void *vl, const void *vr, size_t n); +char *strcpy(char *restrict d, const char *restrict s); +size_t strlen(const char *s); +int strcmp(const char *l, const char *r); +char *strstr(const char *, const char *); + +char *strchr(const char *, int); +int strncmp(const char *_l, const char *_r, size_t n); +char *strpbrk(const char *, const char *); +size_t strcspn(const char *, const char *); +size_t strspn(const char *, const char *); +void *memchr(const void *, int, size_t); +char *strrchr(const char *str, int character); +char *strcat(char *destination, const char *source); +int strcoll(const char *, const char *); +char *strerror(int); + +#endif /* CKB_C_STDLIB_STRING_H_ */ diff --git a/quickjs/mocked.h b/libc/sys/time.h similarity index 69% rename from quickjs/mocked.h rename to libc/sys/time.h index 478536d..cbf6e8f 100644 --- a/quickjs/mocked.h +++ b/libc/sys/time.h @@ -1,9 +1,5 @@ - - -#ifndef __MOCKED_H__ -#define __MOCKED_H__ -#define FE_TONEAREST 0 -#define assert(f) (void)(f) +#ifndef CKB_C_STDLIB_SYS_TIME_H_ +#define CKB_C_STDLIB_SYS_TIME_H_ typedef unsigned long long suseconds_t; typedef unsigned int time_t; @@ -24,9 +20,6 @@ struct timezone { int tz_dsttime; /* type of DST correction */ }; -int fesetround(int round); -int fegetround(); -struct tm *localtime_r(const time_t *timer, struct tm *buf); int gettimeofday(struct timeval *restrict tv, struct timezone *restrict tz); #endif diff --git a/libc/time.h b/libc/time.h new file mode 100644 index 0000000..bdd6b97 --- /dev/null +++ b/libc/time.h @@ -0,0 +1,18 @@ +#ifndef CKB_C_STDLIB_TIME_H_ +#define CKB_C_STDLIB_TIME_H_ + +#include + +#define time_t long +#define CLOCK_MONOTONIC 0 + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +int clock_gettime(int c, struct timespec *ts); + +struct tm *localtime_r(const time_t *timer, struct tm *buf); + +#endif diff --git a/quickjs/mocked.c b/quickjs/mocked.c deleted file mode 100644 index 7299ac4..0000000 --- a/quickjs/mocked.c +++ /dev/null @@ -1,11 +0,0 @@ - - -#include "mocked.h" -#include "ckb_syscall_apis.h" - -int fesetround(int _round) { return 0; } - -int fegetround() { return 0; } - -struct tm *localtime_r(const time_t *a, struct tm *b) { return 0; } -int gettimeofday(struct timeval *restrict tv, struct timezone *restrict tz) { return 0; } \ No newline at end of file diff --git a/quickjs/ckb_module.c b/src/ckb_module.c similarity index 95% rename from quickjs/ckb_module.c rename to src/ckb_module.c index 16ad5c1..48f2373 100644 --- a/quickjs/ckb_module.c +++ b/src/ckb_module.c @@ -6,6 +6,26 @@ #include "molecule/blockchain.h" #include "molecule/molecule_reader.h" #include "ckb_cell_fs.h" +#include "qjs.h" + +#define CHECK2(cond, code) \ + do { \ + if (!(cond)) { \ + err = code; \ + printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ + goto exit; \ + } \ + } while (0) + +#define CHECK(_code) \ + do { \ + int code = (_code); \ + if (code != 0) { \ + err = code; \ + printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ + goto exit; \ + } \ + } while (0) // For syscalls supporting partial loading, the arguments are described as: // argument 1: index diff --git a/quickjs/ckb_module.h b/src/ckb_module.h similarity index 100% rename from quickjs/ckb_module.h rename to src/ckb_module.h diff --git a/quickjs/qjs.c b/src/qjs.c similarity index 97% rename from quickjs/qjs.c rename to src/qjs.c index 6dc3a85..65b0e88 100644 --- a/quickjs/qjs.c +++ b/src/qjs.c @@ -23,19 +23,18 @@ * THE SOFTWARE. */ #include -#include "my_stdlib.h" #include -#include "my_stdio.h" #include #include #include #include -#include "my_malloc.h" +#include #include "cutils.h" #include "std_module.h" #include "ckb_module.h" #include "ckb_exec.h" #include "cmdopt.h" +#include "qjs.h" #define MAIN_FILE_NAME "main.js" #define MAIN_FILE_NAME_BC "main.bc" @@ -290,12 +289,17 @@ static const CMDOptDesc js_vm_options[] = { }; int main(int argc, const char **argv) { + const char *new_argv[8] = {0}; + new_argv[0] = "qjs"; + for (int i = 0; i < argc; i++) { + new_argv[1 + i] = argv[i]; + } int optind; CMDOption *co; co = cmdopt_init("ckb-js-vm"); cmdopt_add_desc(co, js_vm_options); - optind = cmdopt_parse(co, argc, argv); - if (optind > argc) { + optind = cmdopt_parse(co, argc + 1, new_argv); + if (optind > argc + 1) { cmdopt_show_desc(js_vm_options); exit(1); } diff --git a/src/qjs.h b/src/qjs.h new file mode 100644 index 0000000..3fae451 --- /dev/null +++ b/src/qjs.h @@ -0,0 +1,30 @@ +#define CHECK2(cond, code) \ + do { \ + if (!(cond)) { \ + err = code; \ + printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ + goto exit; \ + } \ + } while (0) + +#define CHECK(_code) \ + do { \ + int code = (_code); \ + if (code != 0) { \ + err = code; \ + printf("checking failed on %s:%d, code = %d", __FILE__, __LINE__, code); \ + goto exit; \ + } \ + } while (0) + +#ifdef CONFIG_BIGNUM +#define BC_BASE_VERSION 2 +#else +#define BC_BASE_VERSION 1 +#endif +#define BC_BE_VERSION 0x40 +#ifdef WORDS_BIGENDIAN +#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION) +#else +#define BC_VERSION BC_BASE_VERSION +#endif diff --git a/quickjs/std_module.c b/src/std_module.c similarity index 99% rename from quickjs/std_module.c rename to src/std_module.c index 6f85455..3bcae2c 100644 --- a/quickjs/std_module.c +++ b/src/std_module.c @@ -1,5 +1,4 @@ #include -#include "my_stdlib.h" #include #include #include @@ -9,8 +8,8 @@ #include "cutils.h" #include "std_module.h" #include "ckb_syscall_apis.h" -#include "my_string.h" #include "ckb_cell_fs.h" +#include "qjs.h" /* console.log */ static JSValue js_print(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { diff --git a/quickjs/std_module.h b/src/std_module.h similarity index 100% rename from quickjs/std_module.h rename to src/std_module.h diff --git a/tests/basic/Makefile b/tests/basic/Makefile index 9492710..28e3890 100644 --- a/tests/basic/Makefile +++ b/tests/basic/Makefile @@ -1,4 +1,3 @@ - CKB-DEBUGGER := ckb-debugger ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) BIN_PATH = $(ROOT_DIR)/../../build/ckb-js-vm diff --git a/tests/benchmark/Makefile b/tests/benchmark/Makefile index dfcaf80..e6d0518 100644 --- a/tests/benchmark/Makefile +++ b/tests/benchmark/Makefile @@ -14,8 +14,8 @@ define debug endef define compile-run - $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/$(1) --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > $(ROOT_DIR)/../../build/$(1).bc - $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/../../build/$(1).bc --bin $(BIN_PATH) -- -r | tee $(ROOT_DIR)/benchmark.txt + $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/$(1) --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > $(ROOT_DIR)/../../build/bytecode/$(1).bc + $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/../../build/bytecode/$(1).bc --bin $(BIN_PATH) -- -r | tee $(ROOT_DIR)/benchmark.txt endef all: diff --git a/tests/benchmark/benchmark.txt b/tests/benchmark/benchmark.txt index 3db971a..b595967 100644 --- a/tests/benchmark/benchmark.txt +++ b/tests/benchmark/benchmark.txt @@ -1,42 +1,42 @@ Script log: Run from file, local access enabled. For Testing only. Script log: Benchmark started. Every test may iterate 1 internally ... -Script log: empty_loop: 3 K cycles -Script log: prop_read: 11 K cycles -Script log: prop_write: 10 K cycles -Script log: prop_create: 10 K cycles -Script log: prop_delete: 7 K cycles -Script log: array_read: 17 K cycles -Script log: array_write: 17 K cycles -Script log: array_prop_create: 685 K cycles -Script log: array_length_decr: 1275 K cycles -Script log: array_hole_length_decr: 2689 K cycles -Script log: array_push: 1182 K cycles -Script log: array_pop: 1231 K cycles -Script log: typed_array_read: 19 K cycles -Script log: typed_array_write: 20 K cycles -Script log: global_read: 3 K cycles -Script log: global_write: 4 K cycles -Script log: global_write_strict: 3 K cycles -Script log: local_destruct: 80 K cycles -Script log: global_destruct: 37 K cycles -Script log: global_destruct_strict: 56 K cycles -Script log: func_call: 11 K cycles -Script log: int_arith: 1018 K cycles -Script log: set_collection_add: 876 K cycles -Script log: array_for: 126 K cycles -Script log: array_for_in: 344 K cycles -Script log: array_for_of: 168 K cycles -Script log: math_min: 1213 K cycles -Script log: string_build1: 139 K cycles -Script log: string_build2: 141 K cycles -Script log: string_build3: 147 K cycles -Script log: string_build4: 145 K cycles -Script log: int_to_string: 9 K cycles -Script log: float_to_string: 21 K cycles -Script log: string_to_int: 5 K cycles -Script log: string_to_float: 8 K cycles -Script log: sort_bench(5000 numbers): 22550 K cycles -Script log: json_parse_bench: 112 K cycles -Script log: json_stringify_bench: 187 K cycles +Script log: empty_loop: 4 K cycles +Script log: prop_read: 16 K cycles +Script log: prop_write: 15 K cycles +Script log: prop_create: 14 K cycles +Script log: prop_delete: 10 K cycles +Script log: array_read: 25 K cycles +Script log: array_write: 24 K cycles +Script log: array_prop_create: 1101 K cycles +Script log: array_length_decr: 2076 K cycles +Script log: array_hole_length_decr: 3912 K cycles +Script log: array_push: 1516 K cycles +Script log: array_pop: 1752 K cycles +Script log: typed_array_read: 28 K cycles +Script log: typed_array_write: 27 K cycles +Script log: global_read: 5 K cycles +Script log: global_write: 6 K cycles +Script log: global_write_strict: 5 K cycles +Script log: local_destruct: 100 K cycles +Script log: global_destruct: 49 K cycles +Script log: global_destruct_strict: 71 K cycles +Script log: func_call: 15 K cycles +Script log: int_arith: 1560 K cycles +Script log: set_collection_add: 1047 K cycles +Script log: array_for: 216 K cycles +Script log: array_for_in: 440 K cycles +Script log: array_for_of: 242 K cycles +Script log: math_min: 1740 K cycles +Script log: string_build1: 181 K cycles +Script log: string_build2: 194 K cycles +Script log: string_build3: 202 K cycles +Script log: string_build4: 198 K cycles +Script log: int_to_string: 12 K cycles +Script log: float_to_string: 22 K cycles +Script log: string_to_int: 7 K cycles +Script log: string_to_float: 10 K cycles +Script log: sort_bench(5000 numbers): 24639 K cycles +Script log: json_parse_bench: 129 K cycles +Script log: json_stringify_bench: 222 K cycles Run result: 0 -All cycles: 49160561(46.9M) +All cycles: 59439077(56.7M) diff --git a/tests/ckb_js_tests/Makefile b/tests/ckb_js_tests/Makefile index 4a467dc..03b2360 100644 --- a/tests/ckb_js_tests/Makefile +++ b/tests/ckb_js_tests/Makefile @@ -18,29 +18,28 @@ cargo_test: spawn_caller: clang-18 --target=riscv64 -march=rv64imc_zba_zbb_zbc_zbs \ -I ../../deps/ckb-c-stdlib/libc -I ../../deps/ckb-c-stdlib \ - -nostdinc -nostdlib -o ../../build/spawn_caller test_data/spawn_caller.c + -nostdinc -nostdlib -o ../../build/bytecode/spawn_caller test_data/spawn_caller.c module: spawn_caller cargo run --bin module | ${CKB_DEBUGGER} --tx-file=- -s lock -build/testdata_fs_modules.bin: test_data/fs_module/main.js test_data/fs_module/fib_module.js +build/bytecode/fs_modules.fs: test_data/fs_module/main.js test_data/fs_module/fib_module.js cd test_data/fs_module && lua ../../../../tools/fs.lua pack ../../../../$@ main.js fib_module.js fs_bytecode: - mkdir -p ../../build/bytecode $(CKB_DEBUGGER) --read-file test_data/fs_module/main.js --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > ../../build/bytecode/main.bc $(CKB_DEBUGGER) --read-file test_data/fs_module/fib_module.js --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > ../../build/bytecode/fib_module.bc - cd ../../build/bytecode && lua ../../tools/fs.lua pack ../../build/testdata_fs_modules_bc.bin main.bc fib_module.bc - $(CKB_DEBUGGER) --max-cycles $(MAX_CYCLES) --read-file ../../build/testdata_fs_modules_bc.bin --bin $(BIN_PATH) -- -f -r 2>&1 | fgrep 'Run result: 0' + cd ../../build/bytecode && lua ../../tools/fs.lua pack ../../build/bytecode/fs_modules_bc.fs main.bc fib_module.bc + $(CKB_DEBUGGER) --max-cycles $(MAX_CYCLES) --read-file ../../build/bytecode/fs_modules_bc.fs --bin $(BIN_PATH) -- -f -r 2>&1 | fgrep 'Run result: 0' -file_system: build/testdata_fs_modules.bin +file_system: build/bytecode/fs_modules.fs cargo run --bin default_by_cell | $(CKB_DEBUGGER) -s lock --tx-file=- --read-file ../../$^ -- -f -r 2>&1 | fgrep 'Run result: 0' syscall: cargo run --bin syscall | $(CKB_DEBUGGER) --tx-file=- -s lock fs_mount: - cd test_data/fs_module_mount && lua ../../../../tools/fs.lua pack ../../../../build/fib_module.bin fib_module.js + cd test_data/fs_module_mount && lua ../../../../tools/fs.lua pack ../../../../build/bytecode/fib_module.fs fib_module.js cargo run --bin module_mount | ${CKB_DEBUGGER} --tx-file=- -s lock simple_udt: diff --git a/tests/ckb_js_tests/templates/fs_module_mount.json b/tests/ckb_js_tests/templates/fs_module_mount.json index 28d015e..e38d459 100644 --- a/tests/ckb_js_tests/templates/fs_module_mount.json +++ b/tests/ckb_js_tests/templates/fs_module_mount.json @@ -49,7 +49,7 @@ }, "type": "{{ def_type fib_module }}" }, - "data": "0x{{ data ../../../build/fib_module.bin }}" + "data": "0x{{ data ../../../build/bytecode/fib_module.fs }}" } ], "header_deps": [] diff --git a/tests/ckb_js_tests/templates/module.json b/tests/ckb_js_tests/templates/module.json index 4bdf240..8fe1100 100644 --- a/tests/ckb_js_tests/templates/module.json +++ b/tests/ckb_js_tests/templates/module.json @@ -25,7 +25,7 @@ }, "type": "{{ def_type spawn_caller }}" }, - "data": "0x{{ data ../../../build/spawn_caller }}" + "data": "0x{{ data ../../../build/bytecode/spawn_caller }}" }, { "output": { @@ -49,7 +49,7 @@ }, "type": "{{ def_type js-code-file }}" }, - "data": "0x{{ data ../../../build/testdata_fs_modules_bc.bin }}" + "data": "0x{{ data ../../../build/bytecode/fs_modules_bc.fs }}" } ], "header_deps": [] diff --git a/tests/examples/Makefile b/tests/examples/Makefile index 49c1a1b..fadde7b 100644 --- a/tests/examples/Makefile +++ b/tests/examples/Makefile @@ -1,4 +1,3 @@ - CKB-DEBUGGER := ckb-debugger ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) BIN_PATH := $(ROOT_DIR)/../../build/ckb-js-vm @@ -15,8 +14,8 @@ define debug endef define compile-run - $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/$(1) --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > $(ROOT_DIR)/../../build/$(1).bc - $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/../../build/$(1).bc --bin $(BIN_PATH) -- -r | fgrep 'Run result: 0' + $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/$(1) --bin $(BIN_PATH) -- -c | awk -f $(ROOT_DIR)/../../tools/compile.awk | xxd -r -p > $(ROOT_DIR)/../../build/bytecode/$(1).bc + $(CKB-DEBUGGER) --read-file $(ROOT_DIR)/../../build/bytecode/$(1).bc --bin $(BIN_PATH) -- -r | fgrep 'Run result: 0' endef all: